diff --git a/src/Raku/Actions.nqp b/src/Raku/Actions.nqp index e666054274c..17d7645508c 100644 --- a/src/Raku/Actions.nqp +++ b/src/Raku/Actions.nqp @@ -1257,8 +1257,9 @@ class Raku::Actions is HLL::Actions does Raku::CommonActions { my $decl; if $ { my str $name := $ ~ ($ || '') ~ $; + my $shape := $ ?? $[0].ast !! self.r('SemiList'); $decl := self.r('VarDeclaration', 'Simple').new: - :$scope, :$type, :$name, :$initializer; + :$scope, :$type, :$name, :$initializer, :$shape; if $scope eq 'my' || $scope eq 'state' || $scope eq 'our' { $*R.declare-lexical($decl); } diff --git a/src/Raku/Grammar.nqp b/src/Raku/Grammar.nqp index b316f0359c5..f106e7c2d10 100644 --- a/src/Raku/Grammar.nqp +++ b/src/Raku/Grammar.nqp @@ -1916,6 +1916,7 @@ grammar Raku::Grammar is HLL::Grammar does Raku::Common { token variable_declarator { :my $*IN_DECL := 'variable'; + :my $sigil; [ | ? ? | $=['$'] $=[<[/_!ยข]>] @@ -1924,7 +1925,41 @@ grammar Raku::Grammar is HLL::Grammar does Raku::Common { { $*IN_DECL := ''; $*LEFTSIGIL := nqp::substr(self.orig(), self.from, 1) unless $*LEFTSIGIL; + $sigil := $.Str; } + [ + <.unsp>? + $=[ + | '(' ~ ')' + { + if $sigil eq '&' { + self.typed_sorry('X::Syntax::Reserved', + reserved => '() shape syntax in routine declarations', + instead => ' (maybe use :() to declare a longname?)' + ); + } + elsif $sigil eq '@' { + self.typed_sorry('X::Syntax::Reserved', + reserved => '() shape syntax in array declarations'); + } + elsif $sigil eq '%' { + self.typed_sorry('X::Syntax::Reserved', + reserved => '() shape syntax in hash declarations'); + } + else { + self.typed_sorry('X::Syntax::Reserved', + reserved => '() shape syntax in variable declarations'); + } + } + | :dba('shape definition') '[' ~ ']' + { $sigil ne '@' && self.typed_sorry('X::Syntax::Reserved', + reserved => '[] shape syntax with the ' ~ $sigil ~ ' sigil') } + | :dba('shape definition') '{' ~ '}' + { $sigil ne '%' && self.typed_sorry('X::Syntax::Reserved', + reserved => '{} shape syntax with the ' ~ $sigil ~ ' sigil') } + | <.NYI: "Shaped variable declarations"> + ]+ + ]? [ <.ws> + ]? [<.ws> ]? } diff --git a/src/Raku/ast/variable-declaration.rakumod b/src/Raku/ast/variable-declaration.rakumod index f2fd54f34cb..2ef93fb03cb 100644 --- a/src/Raku/ast/variable-declaration.rakumod +++ b/src/Raku/ast/variable-declaration.rakumod @@ -164,11 +164,12 @@ class RakuAST::VarDeclaration::Simple is RakuAST::Declaration is RakuAST::Implic has str $.name; has str $!storage-name; has RakuAST::Initializer $.initializer; + has RakuAST::SemiList $.shape; has RakuAST::Package $!attribute-package; has Mu $!package; method new(str :$name!, RakuAST::Type :$type, RakuAST::Initializer :$initializer, - str :$scope) { + str :$scope, RakuAST::SemiList :$shape) { my $obj := nqp::create(self); if nqp::chars($name) < 2 { nqp::die('Cannot use RakuAST::VarDeclaration::Simple to declare an anonymous varialbe; use RakuAST::VarDeclaration::Anonymous'); @@ -176,6 +177,7 @@ class RakuAST::VarDeclaration::Simple is RakuAST::Declaration is RakuAST::Implic nqp::bindattr_s($obj, RakuAST::VarDeclaration::Simple, '$!name', $name); nqp::bindattr_s($obj, RakuAST::Declaration, '$!scope', $scope); nqp::bindattr($obj, RakuAST::VarDeclaration::Simple, '$!type', $type // RakuAST::Type); + nqp::bindattr($obj, RakuAST::VarDeclaration::Simple, '$!shape', $shape // RakuAST::SemiList); nqp::bindattr($obj, RakuAST::VarDeclaration::Simple, '$!initializer', $initializer // RakuAST::Initializer); $obj @@ -391,11 +393,16 @@ class RakuAST::VarDeclaration::Simple is RakuAST::Declaration is RakuAST::Implic :scope('lexical'), :decl('contvar'), :name($!name), :value($container) ); - if self.IMPL-HAS-CONTAINER-BASE-TYPE { + if $!shape || self.IMPL-HAS-CONTAINER-BASE-TYPE { $qast := QAST::Op.new( :op('bind'), $qast, QAST::Op.new( :op('callmethod'), :name('new'), QAST::WVal.new( :value(self.IMPL-CONTAINER-BASE-TYPE) ) ) ); + if $!shape { + my $shape_ast := $!shape.IMPL-TO-QAST($context); + $shape_ast.named('shape'); + $qast[1].push($shape_ast); + } } $qast }