package Perl6::Signature::Val; use Moose 0.33; # Signature AST base. Add debug methods here? package Perl6::Signature::Val::Sig; =begin Pugscode |-- AST for function signature. data Sig = MkSig { s_invocant :: Maybe Param , s_requiredPositionalCount :: Int , s_requiredNames :: Set ID , s_positionalList :: [Param] , s_namedSet :: Map.Map ID Param , s_slurpyScalarList :: [Param] , s_slurpyArray :: Maybe Param , s_slurpyHash :: Maybe Param , s_slurpyCode :: Maybe Param , s_slurpyCapture :: Maybe Param } =cut # XXX: L # suggests that requiredNames should be modeled with a list, not a set, # and that the compiler convert mandatory named args to positionals. # Fix this sometime. use Moose; extends 'Perl6::Signature::Val'; # Sorry, Haskell style is the only sane way I know to format these. # :,/^$/s/^ *(/ (/ # :,/^$/s/^ *,/ ,/ # :,/^$/s/^ *)/ )/ has 's_invocant' => ( isa => 'Perl6::Signature::Val::SigParam' , is => 'rw' , required => 0 ); has 's_requiredPositionalCount' => ( isa => 'Int' , is => 'rw' ); has 's_requiredNames' => ( isa => 'HashRef' # Set of names , is => 'rw' ); has 's_positionalList' => ( isa => 'ArrayRef[Perl6::Signature::Val::SigParam]' , is => 'rw' ); has 's_namedList' => ( isa => 'ArrayRef[Perl6::Signature::Val::SigParam]' , is => 'rw' ); has 's_slurpyScalarList' => ( isa => 'ArrayRef[Perl6::Signature::Val::SigParam]' , is => 'rw' , required => 0 , predicate => "has_s_slurpyScalarList" ); has 's_slurpyArray' => ( isa => 'Perl6::Signature::Val::SigParam' , is => 'rw' , required => 0 , predicate => "has_s_slurpyArray" ); has 's_slurpyHash' => ( isa => 'Perl6::Signature::Val::SigParam' , is => 'rw' , required => 0 , predicate => "has_s_slurpyHash" ); has 's_slurpyCode' => ( isa => 'Perl6::Signature::Val::SigParam' , is => 'rw' , required => 0 , predicate => "has_s_slurpyCode" ); has 's_slurpyCapture' => ( isa => 'Perl6::Signature::Val::SigParam' , is => 'rw' , required => 0 , predicate => "has_s_slurpyCapture" ); sub find_named_param { my($self, $label) = @_; for my $param (@{ $self->s_namedList }) { return $param if $param->p_label eq $label; } return; # Or should this die? } sub to_string { my($self) = @_; my $inv_str; if (my $inv = $self->s_invocant) { $inv_str = $inv->to_string . ":"; } my @params; my $positionals = $self->s_positionalList; for my $i (0 .. $#$positionals) { push @params, $positionals->[$i]->to_string( required => $i < $self->s_requiredPositionalCount); } push @params, map { $_->to_string( style => 'named' , required => exists $self->s_requiredNames->{$_->p_label} ) } @{ $self->s_namedList }; push @params, '*' . $self->s_slurpyArray->to_string if $self->has_s_slurpyArray; push @params, '*' . $self->s_slurpyHash->to_string if $self->has_s_slurpyHash; return ":(" . join(" ", ($inv_str ? $inv_str : ()), (@params ? join(", ", @params) : ())) . ")"; } package Perl6::Signature::Val::SigParam; use Moose; extends 'Perl6::Signature::Val'; =begin Pugscode -- | Single parameter for a function or method, e.g.: -- Elk $m where { $m.antlers ~~ Velvet } {-| A formal parameter of a sub (or other callable). These represent declared parameters; don't confuse them with actual argument values. -} data SigParam = MkParam { p_variable :: Var -- ^ E.g. $m above , p_types :: [Types.Type] -- ^ Static pieces of inferencer-food -- E.g. Elk above , p_constraints :: [Code] -- ^ Dynamic pieces of runtime-mood -- E.g. where {...} above , p_unpacking :: Maybe PureSig -- ^ E.g. BinTree $t (Left $l, Right $r) , p_default :: ParamDefault -- ^ E.g. $answer? = 42 , p_label :: ID -- ^ The external name for the param ('m' above) , p_slots :: Table -- ^ Any additional attrib not -- explicitly mentioned below , p_hasAccess :: ParamAccess -- ^ is ro, is rw, is copy , p_isRef :: Bool -- ^ must be true if hasAccess = AccessRW , p_isContext :: Bool -- ^ "is context" , p_isLazy :: Bool } =cut use Moose::Util::TypeConstraints; enum __PACKAGE__ . "::Access" => qw(rw ro copy); enum __PACKAGE__ . "::Sigil" => qw($ % @ &); has 'p_variable' => ( is => 'rw', isa => 'Str' ); has 'p_types' => ( is => 'rw', isa => 'ArrayRef' ); # of types # I don't actually remember why this isn't a scalar :( has 'p_constraints' => ( is => 'rw', isa => 'ArrayRef' ); # of code has 'p_unpacking' => ( isa => 'Perl6::Signature::Val::Sig|Undef' , is => 'rw' , required => 0 ); has 'p_default' => ( is => 'rw', required => 0 ); has 'p_label' => ( is => 'rw', isa => 'Str' ); has 'p_slots' => ( is => 'rw', isa => 'HashRef' ); has 'p_hasAccess' => ( isa => __PACKAGE__ . "::Access" , is => 'rw' , default => "ro" ); has 'p_isRef' => ( is => 'rw', isa => 'Bool' ); has 'p_isContext' => ( is => 'rw', isa => 'Bool' ); has 'p_isLazy' => ( is => 'rw', isa => 'Bool' ); has 'p_sigil' => ( isa => __PACKAGE__ . "::Sigil" , is => "ro" , lazy => 1 , default => sub { substr( shift->p_variable, 0, 1 ) } ); my %quoted_slots = map { $_ => 1 } qw(ro rw copy ref context lazy); sub to_string { my($self, %args) = @_; $args{required} = 1 if not exists $args{required}; $args{style} = 'positional' if not exists $args{style}; die "required param can't have a default value" if $args{required} && $self->p_default; my $ident; if ($args{style} eq 'positional') { $ident = $self->p_variable; $ident .= "?" if !$args{required} && not defined $self->p_default; } else { # TODO: implement a Perl6::...::Variable::basename my($label, $variable) = ($self->p_label, $self->p_variable); $ident = ":" . (($variable =~ /^.\Q$label\E$/) ? $variable : "$label($variable)"); $ident .= "!" if $args{required}; } my $default = "= " . $self->p_default if $self->p_default; my $p_slots = $self->p_slots || {}; my @slots; push @slots, "is " . $self->p_hasAccess if $self->p_hasAccess ne 'ro'; push @slots, "is ref" if $self->p_isRef; push @slots, "is context" if $self->p_isContext; push @slots, "is lazy" if $self->p_isLazy; push @slots, map { my $qkey = $quoted_slots{$_} ? "'$_'" : $_; my $val = defined $p_slots->{$_} && $p_slots->{$_} == 1 ? "" : "<$p_slots->{$_}>"; "is $qkey$val" } keys %$p_slots; my @constraints = map { "where $_" } @{ $self->p_constraints || [] }; return join(" ", (@{ $self->p_types } ? join("|", @{ $self->p_types }) : ()), $ident, ($self->p_unpacking ? $self->p_unpacking->to_string : ()), ($default ? $default : ()), @slots, @constraints); } 6;