tagged release 0.7.1
[parrot.git] / languages / perl6 / src / parser / actions.pm
blobba18974baad3369aafe1b62bc19fdfc3381cad00
1 # Copyright (C) 2007-2008, The Perl Foundation.
2 # $Id$
4 class Perl6::Grammar::Actions ;
6 method TOP($/) {
7 my $past := $( $<statement_block> );
8 $past.blocktype('declaration');
9 declare_implicit_var($past, '$_', 'new');
10 declare_implicit_var($past, '$!', 'new');
11 declare_implicit_var($past, '$/', 'new');
13 # Attach any initialization code.
14 our $?INIT;
15 if defined( $?INIT ) {
16 $?INIT.unshift(
17 PAST::Var.new(
18 :name('$def'),
19 :scope('lexical'),
20 :isdecl(1)
23 $?INIT.blocktype('declaration');
24 $?INIT.pirflags(':init :load');
25 $past.unshift( $?INIT );
26 $?INIT := PAST::Block.new(); # For the next eval.
29 # Make sure we have the interpinfo constants.
30 $past.unshift( PAST::Op.new( :inline('.include "interpinfo.pasm"') ) );
32 # Add code to load perl6.pbc if it's not already present
33 my $loadinit := $past.loadinit();
34 $loadinit.unshift(
35 PAST::Op.new( :inline('$P0 = compreg "Perl6"',
36 'unless null $P0 goto have_perl6',
37 'load_bytecode "perl6.pbc"',
38 'have_perl6:')
42 # convert the last operation of the block into a .return op
43 # so that :load block below isn't used as return value
44 $past.push( PAST::Op.new( $past.pop(), :pirop('return') ) );
45 # automatically invoke mainline on :load (but not :init)
46 $past.push(
47 PAST::Block.new(
48 PAST::Op.new(
49 :inline(
50 '$P0 = interpinfo .INTERPINFO_CURRENT_SUB',
51 '$P0 = $P0."get_outer"()',
52 '$P0()'
55 :pirflags(':load')
59 make $past;
63 method statement_block($/, $key) {
64 our $?BLOCK;
65 our @?BLOCK;
66 our $?BLOCK_SIGNATURED;
67 ## when entering a block, use any $?BLOCK_SIGNATURED if it exists,
68 ## otherwise create an empty block with an empty first child to
69 ## hold any parameters we might encounter inside the block.
70 if $key eq 'open' {
71 if $?BLOCK_SIGNATURED {
72 $?BLOCK := $?BLOCK_SIGNATURED;
73 $?BLOCK_SIGNATURED := 0;
74 $?BLOCK.symbol('___HAVE_A_SIGNATURE', :scope('lexical'));
76 else {
77 $?BLOCK := PAST::Block.new( PAST::Stmts.new(), :node($/));
79 @?BLOCK.unshift($?BLOCK);
81 if $key eq 'close' {
82 my $past := @?BLOCK.shift();
83 $?BLOCK := @?BLOCK[0];
84 $past.push($($<statementlist>));
85 make $past;
90 method block($/) {
91 make $( $<statement_block> );
95 method statementlist($/) {
96 my $past := PAST::Stmts.new( :node($/) );
97 for $<statement> {
98 $past.push( $($_) );
100 make $past;
104 method statement($/, $key) {
105 my $past;
106 if $key eq 'statement_control' {
107 $past := $( $<statement_control> );
109 elsif $key eq 'null' {
110 $past := PAST::Stmts.new(); # empty stmts seem eliminated by TGE
112 else {
113 my $expr := $( $<expr> );
114 if $expr.WHAT() eq 'Block' && !$expr.blocktype() {
115 $expr.blocktype('immediate');
118 if $key eq 'statement_mod_cond' {
119 $past := $( $<statement_mod_cond> );
120 $past.push( $expr );
121 if $<sml> {
122 $expr := $past;
123 $key := 'statement_mod_loop';
124 $<statement_mod_loop> := $<sml>[0];
127 elsif $key eq 'statement_mod_loop' {
128 my $mod := $( $<statement_mod_loop> );
129 if $<statement_mod_loop><sym> eq 'for' {
130 my $loop := PAST::Block.new(
131 PAST::Stmts.new(
132 PAST::Var.new(
133 :name('$_'),
134 :scope('parameter'),
135 :viviself('Failure')
137 $expr
139 :node( $/ )
141 $loop.symbol( '$_', :scope('lexical') );
142 $mod.push($loop);
143 $past := PAST::Stmts.new( $mod, :node($/) );
145 else {
146 $mod.push( $expr );
147 $past := PAST::Block.new( $mod, :blocktype('immediate'), :node($/) );
150 else {
151 $past := $expr;
154 make $past;
158 method statement_control($/, $key) {
159 make $( $/{$key} );
163 method if_statement($/) {
164 my $count := +$<EXPR> - 1;
165 my $expr := $( $<EXPR>[$count] );
166 my $then := $( $<block>[$count] );
167 $then.blocktype('immediate');
168 declare_implicit_immediate_vars($then);
169 my $past := PAST::Op.new(
170 $expr, $then,
171 :pasttype('if'),
172 :node( $/ )
174 if $<else> {
175 my $else := $( $<else>[0] );
176 $else.blocktype('immediate');
177 declare_implicit_immediate_vars($else);
178 $past.push( $else );
180 while $count != 0 {
181 $count := $count - 1;
182 $expr := $( $<EXPR>[$count] );
183 $then := $( $<block>[$count] );
184 $then.blocktype('immediate');
185 declare_implicit_immediate_vars($then);
186 $past := PAST::Op.new(
187 $expr, $then, $past,
188 :pasttype('if'),
189 :node( $/ )
192 make $past;
196 method unless_statement($/) {
197 my $then := $( $<block> );
198 $then.blocktype('immediate');
199 declare_implicit_immediate_vars($then);
200 my $past := PAST::Op.new(
201 $( $<EXPR> ), $then,
202 :pasttype('unless'),
203 :node( $/ )
205 make $past;
209 method while_statement($/) {
210 my $cond := $( $<EXPR> );
211 my $block := $( $<block> );
212 declare_implicit_immediate_vars($block);
213 $block.blocktype('immediate');
214 make PAST::Op.new( $cond, $block, :pasttype(~$<sym>), :node($/) );
217 method repeat_statement($/) {
218 my $cond := $( $<EXPR> );
219 my $block := $( $<block> );
220 $block.blocktype('immediate');
221 # pasttype is 'repeat_while' or 'repeat_until'
222 my $pasttype := 'repeat_' ~ ~$<loop>;
223 make PAST::Op.new( $cond, $block, :pasttype($pasttype), :node($/) );
226 method given_statement($/) {
227 my $block := $( $<pblock> );
228 $block.blocktype('declaration');
229 declare_implicit_function_vars($block);
230 ## call the block using the expression as an argument
231 my $past := PAST::Op.new(
232 :pasttype('call'),
233 $block,
234 $( $<EXPR> )
236 make $past;
239 method when_statement($/) {
240 my $block := $( $<block> );
241 $block.blocktype('immediate');
243 # XXX TODO: push a control exception throw onto the end of the block so we
244 # exit the innermost block in which $_ was set.
246 # Invoke smartmatch of the expression.
247 my $match_past := PAST::Op.new(
248 PAST::Var.new( :name('$_') ),
249 $( $<EXPR> ),
250 :name('infix:~~'),
251 :pasttype('call'),
252 :node($/)
255 # Use the smartmatch result as the condition.
256 my $past := PAST::Op.new(
257 $match_past, $block,
258 :pasttype('if'),
259 :node( $/ )
261 make $past;
264 method default_statement($/) {
265 # Always executed if reached, so just produce the block.
266 my $past := $( $<block> );
267 $past.blocktype('immediate');
268 make $past;
271 method loop_statement($/) {
272 my $block := $( $<block> );
273 $block.blocktype('immediate');
274 my $cond := $<e2> ?? $( $<e2>[0] ) !! PAST::Val.new( :value( 1 ) );
275 if $<e3> {
276 $block := PAST::Stmts.new( $block, $( $<e3>[0] ) );
278 my $loop := PAST::Op.new( $cond, $block, :pasttype('while'), :node($/) );
279 if $<e1> {
280 $loop := PAST::Stmts.new( $( $<e1>[0] ), $loop, :node($/) );
282 make $loop;
285 method for_statement($/) {
286 my $block := $( $<pblock> );
287 $block.blocktype('declaration');
288 declare_implicit_function_vars($block);
289 my $past := PAST::Op.new(
290 PAST::Op.new(:name('list'), $($<EXPR>)),
291 $block,
292 :pasttype($<sym>),
293 :node( $/ )
295 make $past;
298 method pblock($/) {
299 my $block := $( $<block> );
300 make $block;
303 method use_statement($/) {
304 my $name := ~$<name>;
305 my $past;
306 if $name eq 'v6' || $name eq 'lib' {
307 $past := PAST::Stmts.new( :node($/) );
309 else {
310 $past := PAST::Op.new(
311 PAST::Val.new( :value($name) ),
312 :name('use'),
313 :pasttype('call'),
314 :node( $/ )
317 make $past;
320 method begin_statement($/) {
321 my $past := $( $<block> );
322 $past.blocktype('declaration');
323 my $sub := PAST::Compiler.compile( $past );
324 $sub();
325 # XXX - should emit BEGIN side-effects, and do a proper return()
326 make PAST::Block.new();
329 method end_statement($/) {
330 my $past := $( $<block> );
331 $past.blocktype('declaration');
332 my $sub := PAST::Compiler.compile( $past );
333 PIR q< $P0 = get_hll_global ['Perl6'], '@?END_BLOCKS' >;
334 PIR q< $P1 = find_lex '$sub' >;
335 PIR q< push $P0, $P1 >;
336 make $past;
339 method statement_mod_loop($/) {
340 my $expr := $( $<EXPR> );
341 if ~$<sym> eq 'given' {
342 my $assign := PAST::Op.new(
343 :name('infix::='),
344 :pasttype('bind'),
345 :node($/)
347 $assign.push(
348 PAST::Var.new( :node($/), :name('$_'), :scope('lexical') )
350 $assign.push( $expr );
352 my $past := PAST::Stmts.new( $assign, :node($/) );
353 make $past;
355 elsif ~$<sym> eq 'for' {
356 my $past := PAST::Op.new(
357 PAST::Op.new($expr, :name('list')),
358 :pasttype($<sym>),
359 :node( $/ )
361 make $past;
363 else {
364 make PAST::Op.new(
365 $expr,
366 :pasttype( ~$<sym> ),
367 :node( $/ )
372 method statement_mod_cond($/) {
373 if ~$<sym> eq 'when' {
374 my $expr := $( $<EXPR> );
375 my $match_past := PAST::Op.new(
376 :name('infix:~~'),
377 :pasttype('call'),
378 :node($/)
380 $match_past.push(
381 PAST::Var.new( :node($/), :name('$_'), :scope('lexical') )
383 $match_past.push( $expr );
385 my $past := PAST::Op.new(
386 $match_past,
387 :pasttype('if'),
388 :node( $/ )
390 make $past;
392 else {
393 make PAST::Op.new(
394 $( $<EXPR> ),
395 :pasttype( ~$<sym> ),
396 :node( $/ )
402 method statement_prefix($/) {
403 my $past := $($<statement>);
404 my $sym := ~$<sym>;
406 if $sym eq 'do' {
407 # fall through, just use the statement itself
409 ## after the code in the try block is executed, bind $! to Failure,
410 ## and set up the code to catch an exception, in case one is thrown
411 elsif $sym eq 'try' {
412 $past := PAST::Op.new( $past, :pasttype('try') );
414 ## Add a catch node to the try op that captures the
415 ## exception object into $!.
416 my $catchpir := " .get_results (%r, $S0)\n store_lex '$!', %r";
417 $past.push( PAST::Op.new( :inline( $catchpir ) ) );
419 ## Add an 'else' node to the try op that clears $! if
420 ## no exception occurred.
421 my $elsepir := " new %r, 'Failure'\n store_lex '$!', %r";
422 $past.push( PAST::Op.new( :inline( $elsepir ) ) );
424 elsif $sym eq 'gather' {
425 if $past.isa(PAST::Block) {
426 $past.blocktype('declaration');
428 else {
429 $past := PAST::Block.new(:blocktype('declaration'), $past)
431 # XXX Workaround for lexicals issue. rt #58854
432 $past := PAST::Op.new(:pirop('newclosure'), $past);
433 $past := PAST::Op.new( $past, :pasttype('call'), :name('gather'), :node($/) );
435 else {
436 $/.panic( $sym ~ ' not implemented');
438 make $past;
442 method multi_declarator($/, $key) {
443 my $past := $( $/{$key} );
445 # If we just got a routine_def, make it a sub.
446 if $key eq 'routine_def' {
447 create_sub($/, $past);
450 # If it was multi, then emit a :multi and a type list.
451 if $<sym> eq 'multi' {
452 # For now, if this is a multi we need to add code to transform the sub's
453 # multi container to a Perl6MultiSub.
454 $past.loadinit().push(
455 PAST::Op.new(
456 :pasttype('call'),
457 :name('!TOPERL6MULTISUB'),
458 PAST::Var.new(
459 :name('block'),
460 :scope('register')
465 # Flag the sub as multi, but it will get the signature from the
466 # signature object, so don't worry about that here.
467 my $pirflags := $past.pirflags();
468 unless $pirflags { $pirflags := '' }
469 $past.pirflags($pirflags ~ ' :multi()');
471 make $past;
475 method routine_declarator($/, $key) {
476 my $past;
477 if $key eq 'sub' {
478 $past := $($<routine_def>);
479 create_sub($/, $past);
481 elsif $key eq 'method' {
482 $past := $($<method_def>);
484 # If it's got a name, only valid inside a class, role or grammar.
485 if $past.name() {
486 our @?CLASS;
487 our @?GRAMMAR;
488 our @?ROLE;
489 unless +@?CLASS || +@?GRAMMAR || +@?ROLE {
490 $/.panic("Named methods cannot appear outside of a class, grammar or role.");
494 # Add declaration of leixcal self.
495 $past[0].unshift(PAST::Op.new(
496 :pasttype('bind'),
497 PAST::Var.new(
498 :name('self'),
499 :scope('lexical'),
500 :isdecl(1)
502 PAST::Var.new( :name('self'), :scope('register') )
505 # Set up the block details.
506 $past.blocktype('method');
507 set_block_proto($past, 'Method');
508 if $<method_def><multisig> {
509 set_block_sig($past, $( $<method_def><multisig>[0]<signature> ));
511 else {
512 set_block_sig($past, empty_signature());
514 $past := add_method_to_class($past);
516 $past.node($/);
517 if (+@($past[1])) {
518 declare_implicit_var($past, '$_', 'new');
519 declare_implicit_var($past, '$!', 'new');
520 declare_implicit_var($past, '$/', 'new');
522 else {
523 $past[1].push( PAST::Op.new( :name('list') ) );
525 make $past;
529 method enum_declarator($/, $key) {
530 my $values := $( $/{$key} );
532 if $<name> {
533 # It's a named enumeration. First, we will get a mapping of all the names
534 # we will introduce with this enumeration to their values. We'll compute
535 # these at compile time, so then we can build as much of the enum as possible
536 # as PAST at compile time too. Note that means that, like a BEGIN block, we
537 # will compile, run and get the return value now.
538 my $block := PAST::Block.new(
539 :blocktype('declaration'),
540 PAST::Stmts.new(
541 PAST::Op.new(
542 :pasttype('call'),
543 :name('!anon_enum'),
544 $values
548 my $getvals_sub := PAST::Compiler.compile( $block );
549 my %values := $getvals_sub();
551 # Now we need to emit an role of the name of the enum containing:
552 # * One attribute with the same name as the enum
553 # * A method of the same name as the enum
554 # * Methods for each name introduced by the enum that compare the
555 # attribute with the value of that name.
556 my $role_past := PAST::Stmts.new(
557 PAST::Op.new(
558 :pasttype('bind'),
559 PAST::Var.new(
560 :name('$def'),
561 :scope('lexical')
563 PAST::Op.new(
564 :pasttype('call'),
565 :name('!keyword_role'),
566 PAST::Val.new( :value(~$<name>[0]) )
569 PAST::Op.new(
570 :pasttype('call'),
571 :name('!keyword_has'),
572 PAST::Var.new(
573 :name('$def'),
574 :scope('lexical')
576 PAST::Val.new( :value("$!" ~ ~$<name>[0]) ),
577 # XXX Set declared type here, when we parse that.
578 PAST::Var.new(
579 :name('Object'),
580 :scope('package')
583 PAST::Op.new(
584 :pasttype('callmethod'),
585 :name('add_method'),
586 PAST::Var.new(
587 :name('$def'),
588 :scope('lexical')
590 PAST::Val.new( :value(~$<name>[0]) ),
591 make_accessor($/, undef, "$!" ~ ~$<name>[0], 1, 'attribute')
594 for %values.keys() {
595 # Method for this value.
596 $role_past.push(PAST::Op.new(
597 :pasttype('callmethod'),
598 :name('add_method'),
599 PAST::Var.new(
600 :name('$def'),
601 :scope('lexical')
603 PAST::Val.new( :value($_) ),
604 PAST::Block.new(
605 :blocktype('declaration'),
606 :pirflags(':method'),
607 PAST::Stmts.new(
608 PAST::Op.new(
609 :pasttype('call'),
610 :name('infix:eq'), # XXX not generic enough
611 PAST::Var.new(
612 :name("$!" ~ ~$<name>[0]),
613 :scope('attribute')
615 PAST::Val.new( :value(%values{$_}) )
622 # Now we emit code to create a class for the enum that does the role
623 # that we just defined. Note $def in the init code refers to this
624 # class from now on. Mark the class as an enum.
625 my $class_past := PAST::Stmts.new(
626 PAST::Op.new(
627 :pasttype('bind'),
628 PAST::Var.new(
629 :name('$def'),
630 :scope('lexical')
632 PAST::Op.new(
633 :pasttype('call'),
634 :name('!keyword_enum'),
635 PAST::Var.new(
636 :name('$def'),
637 :scope('lexical')
641 PAST::Op.new(
642 :inline(' setprop %0, "enum", %1'),
643 PAST::Var.new(
644 :name('$def'),
645 :scope('lexical')
647 PAST::Val.new(
648 :value(1),
649 :returns('Int')
654 # Want to give the class an invoke method that returns the enum value,
655 # and get_string, get_number and get_integer v-table overrides to we
656 # can get data from it..
657 $class_past.push(PAST::Op.new(
658 :pasttype('callmethod'),
659 :name('add_method'),
660 PAST::Var.new(
661 :scope('lexical'),
662 :name('$def')
664 PAST::Val.new( :value('invoke') ),
665 PAST::Block.new(
666 :blocktype('declaration'),
667 :pirflags(":method"),
668 PAST::Var.new(
669 :name("$!" ~ ~$<name>[0]),
670 :scope('attribute')
673 PAST::Val.new(
674 :value(1),
675 :named( PAST::Val.new( :value('vtable') ) )
678 $class_past.push(PAST::Op.new(
679 :pasttype('callmethod'),
680 :name('add_method'),
681 PAST::Var.new(
682 :scope('lexical'),
683 :name('$def')
685 PAST::Val.new( :value('get_string') ),
686 PAST::Block.new(
687 :blocktype('declaration'),
688 :pirflags(":method"),
689 PAST::Op.new(
690 :pasttype('call'),
691 :name('prefix:~'),
692 PAST::Var.new(
693 :name("$!" ~ ~$<name>[0]),
694 :scope('attribute')
698 PAST::Val.new(
699 :value(1),
700 :named( PAST::Val.new( :value('vtable') ) )
703 $class_past.push(PAST::Op.new(
704 :pasttype('callmethod'),
705 :name('add_method'),
706 PAST::Var.new(
707 :scope('lexical'),
708 :name('$def')
710 PAST::Val.new( :value('get_integer') ),
711 PAST::Block.new(
712 :blocktype('declaration'),
713 :pirflags(":method"),
714 PAST::Op.new(
715 :pasttype('call'),
716 :name('prefix:+'),
717 PAST::Var.new(
718 :name("$!" ~ ~$<name>[0]),
719 :scope('attribute')
723 PAST::Val.new(
724 :value(1),
725 :named( PAST::Val.new( :value('vtable') ) )
728 $class_past.push(PAST::Op.new(
729 :pasttype('callmethod'),
730 :name('add_method'),
731 PAST::Var.new(
732 :scope('lexical'),
733 :name('$def')
735 PAST::Val.new( :value('get_number') ),
736 PAST::Block.new(
737 :blocktype('declaration'),
738 :pirflags(":method"),
739 PAST::Op.new(
740 :pasttype('call'),
741 :name('prefix:+'),
742 PAST::Var.new(
743 :name("$!" ~ ~$<name>[0]),
744 :scope('attribute')
748 PAST::Val.new(
749 :value(1),
750 :named( PAST::Val.new( :value('vtable') ) )
754 # Now we need to create instances of each of these and install them
755 # in a package starting with the enum's name, plus an alias to them
756 # in the current package.
757 for %values.keys() {
758 # Instantiate with value.
759 $class_past.push(PAST::Op.new(
760 :pasttype('bind'),
761 PAST::Var.new(
762 :name($_),
763 :namespace(~$<name>[0]),
764 :scope('package')
766 PAST::Op.new(
767 :pasttype('callmethod'),
768 :name('new'),
769 PAST::Var.new(
770 :name('$def'),
771 :scope('lexical')
773 PAST::Val.new(
774 :value(%values{$_}),
775 :named( PAST::Val.new( :value("$!" ~ ~$<name>[0]) ) )
780 # Add alias in current package.
781 # XXX Need to do collision detection, once we've a registry.
782 $class_past.push(PAST::Op.new(
783 :pasttype('bind'),
784 PAST::Var.new(
785 :name($_),
786 :scope('package')
788 PAST::Var.new(
789 :name($_),
790 :namespace(~$<name>[0]),
791 :scope('package')
796 # Assemble all that we build into a statement list and then place it
797 # into the init code.
798 our $?INIT;
799 unless defined( $?INIT ) {
800 $?INIT := PAST::Block.new();
802 $?INIT.push(PAST::Stmts.new(
803 $role_past,
804 $class_past
807 # Finally, since it's a decl, we don't have anything to emit at this
808 # point; just hand back empty statements block.
809 make PAST::Stmts.new();
811 else {
812 # Emit runtime call anonymous enum constructor.
813 make PAST::Op.new(
814 :pasttype('call'),
815 :name('!anon_enum'),
816 $values
822 method routine_def($/) {
823 my $past := $( $<block> );
824 if $<ident> {
825 $past.name( ~$<ident>[0] );
826 our $?BLOCK;
827 $?BLOCK.symbol(~$<ident>[0], :scope('package'));
829 $past.control('return_pir');
830 make $past;
833 method method_def($/) {
834 my $past := $( $<block> );
835 if $<ident> {
836 $past.name( ~$<ident>[0] );
838 $past.control('return_pir');
839 make $past;
843 method signature($/) {
844 # In here, we build a signature object and optionally some other things
845 # if $?SIG_BLOCK_NOT_NEEDED is not set to a true value.
846 # * $?BLOCK_SIGNATURED ends up containing the PAST tree for a block that
847 # takes and binds the parameters. This is used for generating subs,
848 # methods and so forth.
849 # * $?PARAM_TYPE_CHECK is used to export details of the types from here
850 # so that the multi plurality declarator can make use of them.
852 # Initialize PAST for the signatured block, if we're going to have it.
853 our $?SIG_BLOCK_NOT_NEEDED;
854 my $params;
855 my $type_check;
856 my $block_past;
857 unless $?SIG_BLOCK_NOT_NEEDED {
858 $params := PAST::Stmts.new( :node($/) );
859 $block_past := PAST::Block.new( $params, :blocktype('declaration') );
860 $type_check := PAST::Stmts.new( :node($/) );
863 # Initialize PAST for constructing the signature object.
864 my $sig_past := PAST::Op.new(
865 :pasttype('callmethod'),
866 :name('!create'),
867 PAST::Var.new(
868 :name('Signature'),
869 :scope('package'),
870 :namespace(list())
874 # Go through the parameters.
875 for $/[0] {
876 my $parameter := $($_<parameter>);
877 my $separator := $_[0];
879 # Add parameter declaration to the block, if we're producing one.
880 unless $?SIG_BLOCK_NOT_NEEDED {
881 # Register symbol and put parameter PAST into the node.
882 $block_past.symbol($parameter.name(), :scope('lexical'));
883 $params.push($parameter);
885 # If it is invocant, modify it to be just a lexical and bind self to it.
886 if substr($separator, 0, 1) eq ':' {
887 # Make sure it's first parameter.
888 if +@($params) != 1 {
889 $/.panic("There can only be one invocant and it must be the first parameter");
892 # Modify.
893 $parameter.scope('lexical');
894 $parameter.isdecl(1);
896 # Bind self to it.
897 $params.push(PAST::Op.new(
898 :pasttype('bind'),
899 PAST::Var.new(
900 :name($parameter.name()),
901 :scope('lexical')
903 PAST::Var.new( :name('self'), :scope('register') )
907 # Are we going to take the type of the thing we were passed and bind
908 # it to an abstraction parameter?
909 if $_<parameter><generic_binder> {
910 my $tv_var := $( $_<parameter><generic_binder>[0]<variable> );
911 $params.push(PAST::Op.new(
912 :pasttype('bind'),
913 PAST::Var.new(
914 :name($tv_var.name()),
915 :scope('lexical'),
916 :isdecl(1)
918 PAST::Op.new(
919 :pasttype('callmethod'),
920 :name('WHAT'),
921 PAST::Var.new(
922 :name($parameter.name()),
923 :scope('lexical')
927 $block_past.symbol($tv_var.name(), :scope('lexical'));
931 # Now start making a descriptor for the signature.
932 my $descriptor := sig_descriptor_create();
933 $sig_past.push($descriptor);
934 sig_descriptor_set($descriptor, 'name',
935 PAST::Val.new( :value(~$parameter.name()) ));
936 if $parameter.named() {
937 sig_descriptor_set($descriptor, 'named',
938 PAST::Val.new( :value(~$parameter.named()) ));
940 if $parameter.viviself() {
941 sig_descriptor_set($descriptor, 'optional', PAST::Val.new( :value(1) ));
943 if $parameter.slurpy() {
944 sig_descriptor_set($descriptor, 'slurpy', PAST::Val.new( :value(1) ));
947 # See if we have any traits. For now, we just handle ro, rw and copy.
948 my $cont_trait := 'readonly';
949 my $cont_traits := 0;
950 for $_<parameter><trait> {
951 if $_<trait_auxiliary> {
952 # Get name of the trait and see if it's one of the special
953 # traits we handle in the compiler.
954 my $name := ~$_<trait_auxiliary><name>;
955 if $name eq 'readonly' {
956 $cont_traits := $cont_traits + 1;
958 elsif $name eq 'rw' {
959 $cont_trait := 'rw';
960 $cont_traits := $cont_traits + 1;
962 elsif $name eq 'copy' {
963 $cont_trait := 'copy';
964 $cont_traits := $cont_traits + 1;
966 else {
967 $/.panic("Cannot apply trait " ~ $name ~ " to parameters yet.");
970 else {
971 $/.panic("Cannot apply traits to parameters yet.");
975 # If we had is copy is rw or some other impossible combination, die.
976 if $cont_traits > 1 {
977 $/.panic("Can only use one of readonly, rw and copy on a parameter.");
980 # Add any type check that is needed. The scheme for this: $type_check
981 # is a statement block. We create a block for each parameter, which
982 # will be empty if there are no constraints for that parameter. This
983 # is so we can later generate a multi-sig from it.
984 my $cur_param_types := PAST::Stmts.new();
985 if $_<parameter><type_constraint> {
986 for $_<parameter><type_constraint> {
987 my $type_obj;
989 # Just a type name?
990 if $_<typename> {
991 $type_obj := PAST::Op.new(
992 :pasttype('call'),
993 :name('!TYPECHECKPARAM'),
994 $( $_<typename> ),
995 PAST::Var.new(
996 :name($parameter.name()),
997 :scope('lexical')
1001 else {
1002 $type_obj := make_anon_subset($( $_<EXPR> ), $parameter);
1005 # Add it to the types list.
1006 $cur_param_types.push($type_obj);
1010 # Add any post-constraints too.
1011 for $_<parameter><post_constraint> {
1012 my $type_obj := make_anon_subset($( $_<EXPR> ), $parameter);
1013 $cur_param_types.push($type_obj);
1016 # For blocks, we just collect the check into the list of all checks.
1017 unless $?SIG_BLOCK_NOT_NEEDED {
1018 $type_check.push($cur_param_types);
1021 # For signatures, we build a list from the constraints and store it.
1022 my $sig_type_cons := PAST::Stmts.new(
1023 PAST::Op.new(
1024 :inline(' $P2 = new "List"')
1026 PAST::Stmts.new(),
1027 PAST::Op.new(
1028 :inline(' %r = $P2')
1031 for @($cur_param_types) {
1032 # Just want the type, not the call to the checker.
1033 $sig_type_cons[1].push(PAST::Op.new(
1034 :inline(' push $P2, %0'),
1035 $_[0]
1038 sig_descriptor_set($descriptor, 'constraints', $sig_type_cons);
1040 # If we're making a block, emit code for trait types.
1041 unless $?SIG_BLOCK_NOT_NEEDED {
1042 if $cont_trait eq 'rw' {
1043 # We just leave it as it is.
1045 elsif $cont_trait eq 'readonly' {
1046 # Create a new container with ro set and bind the parameter to it.
1047 $params.push(PAST::Op.new(
1048 :pasttype('bind'),
1049 PAST::Var.new(
1050 :name($parameter.name()),
1051 :scope('lexical')
1053 PAST::Op.new(
1054 :inline(
1055 ' %r = new "Perl6Scalar", %0',
1056 ' $P0 = get_hll_global ["Bool"], "True"',
1057 ' setprop %r, "readonly", $P0'
1059 PAST::Var.new(
1060 :name($parameter.name()),
1061 :scope('lexical')
1066 elsif $cont_trait eq 'copy' {
1067 # Create a new container and copy the value into it..
1068 $params.push(PAST::Op.new(
1069 :pasttype('bind'),
1070 PAST::Var.new(
1071 :name($parameter.name()),
1072 :scope('lexical')
1074 PAST::Op.new(
1075 :inline(
1076 ' %r = new "Perl6Scalar"',
1077 ' %r."infix:="(%0)'
1079 PAST::Var.new(
1080 :name($parameter.name()),
1081 :scope('lexical')
1089 # Finish setting up the signatured block, if we're making one.
1090 unless $?SIG_BLOCK_NOT_NEEDED {
1091 $block_past.arity( +$/[0] );
1092 our $?BLOCK_SIGNATURED := $block_past;
1093 our $?PARAM_TYPE_CHECK := $type_check;
1094 $params.push($type_check);
1097 # Hand back the PAST to construct a signature object.
1098 make $sig_past;
1102 method parameter($/) {
1103 my $past := $( $<param_var> );
1104 my $sigil := $<param_var><sigil>;
1105 if $<quant> eq '*' {
1106 $past.slurpy( $sigil eq '@' || $sigil eq '%' );
1107 $past.named( $sigil eq '%' );
1109 else {
1110 if $<named> eq ':' { # named
1111 $past.named(~$<param_var><ident>);
1112 if $<quant> ne '!' { # required (optional is default)
1113 $past.viviself('Failure');
1116 else { # positional
1117 if $<quant> eq '?' { # optional (required is default)
1118 $past.viviself('Failure');
1122 if $<default_value> {
1123 if $<quant> eq '!' {
1124 $/.panic("Can't put a default on a required parameter");
1126 if $<quant> eq '*' {
1127 $/.panic("Can't put a default on a slurpy parameter");
1129 $past.viviself( $( $<default_value>[0]<EXPR> ) );
1131 make $past;
1135 method param_var($/) {
1136 if $<twigil> && $<twigil>[0] ne '.' && $<twigil>[0] ne '!' {
1137 $/.panic('Invalid twigil used in signature parameter.');
1139 make PAST::Var.new(
1140 :name(~$/),
1141 :scope('parameter'),
1142 :node($/)
1147 method special_variable($/) {
1148 make PAST::Var.new( :node($/), :name(~$/), :scope('lexical') );
1152 method expect_term($/, $key) {
1153 my $past;
1154 if $key eq '*' {
1155 # Whatever.
1156 $past := PAST::Op.new(
1157 :pasttype('callmethod'),
1158 :name('new'),
1159 :node($/),
1160 :lvalue(1),
1161 PAST::Var.new(
1162 :name('Whatever'),
1163 :scope('package'),
1164 :node($/)
1168 else {
1169 $past := $( $/{$key} );
1172 if $<postfix> {
1173 for $<postfix> {
1174 my $term := $past;
1175 $past := $($_);
1176 if $past.name() eq 'infix:,' { $past.name(''); }
1178 if $past.isa(PAST::Op)
1179 && $past.pasttype() eq 'callmethod'
1180 && !$past.name() {
1181 # indirect call, invocant needs to be second arg
1182 my $meth := $past[0];
1183 $past[0] := $term;
1184 $past.unshift($meth);
1186 else {
1187 $past.unshift($term);
1191 make $past;
1195 method postfix($/, $key) {
1196 make $( $/{$key} );
1200 method dotty($/, $key) {
1201 my $past;
1203 if $key eq '.' {
1204 # Just a normal method call.
1205 $past := $( $<methodop> );
1207 elsif $key eq '!' {
1208 # Private method call. Need to put ! on the start of the name
1209 # (unless it was call to a code object, in which case we don't do
1210 # anything more).
1211 $past := $( $<methodop> );
1212 if $<methodop><name> {
1213 $past.name('!' ~ $past.name());
1215 elsif $<methodop><quote> {
1216 $past[0] := PAST::Op.new(
1217 :pasttype('call'),
1218 :name('infix:~'),
1219 PAST::Val.new( :value('!') ),
1220 $past[0]
1224 elsif $key eq '.*' {
1225 $past := $( $<methodop> );
1226 if $/[0] eq '.?' || $/[0] eq '.+' || $/[0] eq '.*' || $/[0] eq '.^' {
1227 my $name := $past.name();
1228 unless $name {
1229 $/.panic("Cannot use " ~ $/[0] ~ " when method is a code ref");
1231 unless $name.isa(PAST::Node) {
1232 $name := PAST::Val.new( :value($name) );
1234 $past.unshift($name);
1235 $past.name('!' ~ $/[0]);
1237 else {
1238 $/.panic($/[0] ~ ' method calls not yet implemented');
1241 elsif $key eq 'VAR' {
1242 $past := PAST::Op.new(
1243 :pasttype('call'),
1244 :name('!VAR'),
1245 :node($/)
1249 make $past;
1253 method methodop($/, $key) {
1254 my $past;
1256 if $key eq 'null' {
1257 $past := PAST::Op.new();
1259 else {
1260 $past := build_call( $( $/{$key} ) );
1262 $past.pasttype('callmethod');
1263 $past.node($/);
1265 if $<name> {
1266 $past.name(~$<name><ident>[0]);
1268 elsif $<variable> {
1269 $past.unshift( $( $<variable> ) );
1271 else {
1272 $past.name( $( $<quote> ) );
1275 make $past;
1278 method postcircumfix($/, $key) {
1279 my $past;
1280 if $key eq '[ ]' {
1281 $past := PAST::Var.new(
1282 $( $<semilist> ),
1283 :scope('keyed_int'),
1284 :vivibase('Perl6Array'),
1285 :viviself('Failure'),
1286 :node( $/ )
1289 elsif $key eq '( )' {
1290 $past := build_call( $( $<semilist> ) );
1291 $past.node($/);
1293 elsif $key eq '{ }' {
1294 $past := PAST::Var.new(
1295 $( $<semilist> ),
1296 :scope('keyed'),
1297 :vivibase('Perl6Hash'),
1298 :viviself('Failure'),
1299 :node( $/ )
1302 elsif $key eq '< >' {
1303 $past := PAST::Var.new(
1304 $( $<quote_expression> ),
1305 :scope('keyed'),
1306 :vivibase('Perl6Hash'),
1307 :viviself('Failure'),
1308 :node( $/ )
1311 else {
1312 $/.panic("postcircumfix " ~ $key ~ " not yet implemented");
1314 make $past;
1318 method noun($/, $key) {
1319 my $past;
1320 if $key eq 'self' {
1321 $past := PAST::Var.new(
1322 :name('self'),
1323 :scope('lexical'),
1324 :node($/)
1327 elsif $key eq 'dotty' {
1328 # Call on $_.
1329 $past := $( $/{$key} );
1330 $past.unshift(PAST::Var.new(
1331 :name('$_'),
1332 :scope('lexical'),
1333 :viviself('Failure'),
1334 :node($/)
1337 else {
1338 $past := $( $/{$key} );
1340 make $past;
1344 sub apply_package_traits($package, $traits) {
1345 for $traits {
1346 # Apply any "is" traits through MMD.
1347 if $_<trait_auxiliary><sym> eq 'is' {
1348 $package.push(
1349 PAST::Op.new(
1350 :pasttype('call'),
1351 :name('trait_auxiliary:is'),
1352 PAST::Var.new(
1353 :name(~$_<trait_auxiliary><name>),
1354 :scope('package'),
1355 :viviself('Undef')
1357 PAST::Var.new(
1358 :name('$def'),
1359 :scope('lexical')
1364 elsif $_<trait_auxiliary><sym> eq 'does' {
1365 # Role.
1366 $package.push(
1367 PAST::Op.new(
1368 :pasttype('call'),
1369 :name('!keyword_does'),
1370 PAST::Var.new(
1371 :name('$def'),
1372 :scope('lexical')
1374 PAST::Var.new(
1375 :name(~$_<trait_auxiliary><name>),
1376 :scope('package')
1381 else {
1382 $traits.panic("Currently only is and does traits are supported on packages.");
1388 method package_declarator($/, $key) {
1389 our $?CLASS;
1390 our @?CLASS;
1391 our $?ROLE;
1392 our @?ROLE;
1393 our $?PACKAGE;
1394 our @?PACKAGE;
1395 our $?GRAMMAR;
1396 our @?GRAMMAR;
1398 if $key eq 'open' {
1399 # Start of a new package. We create an empty PAST::Stmts node for the
1400 # package definition to be stored in and put it onto the current stack
1401 # of packages and the stack of its package type.
1402 my $decl_past := PAST::Stmts.new();
1403 @?PACKAGE.unshift($?PACKAGE);
1404 $?PACKAGE := $decl_past;
1405 if $<sym> eq 'class' {
1406 @?CLASS.unshift($?CLASS);
1407 $?CLASS := $decl_past;
1409 elsif $<sym> eq 'role' {
1410 @?ROLE.unshift( $?ROLE );
1411 $?ROLE := $decl_past;
1413 elsif $<sym> eq 'grammar' {
1414 @?GRAMMAR.unshift( $?GRAMMAR );
1415 $?GRAMMAR := $decl_past;
1418 else {
1419 # End of declaration. Our PAST will be that made by the package_def or
1420 # role_def.
1421 my $past := $( $/{$key} );
1423 # Restore outer package.
1424 $?PACKAGE := @?PACKAGE.shift();
1425 if $<sym> eq 'class' {
1426 $?CLASS := @?CLASS.shift();
1428 elsif $<sym> eq 'role' {
1429 $?ROLE := @?ROLE.shift();
1431 elsif $<sym> eq 'grammar' {
1432 $?GRAMMAR := @?GRAMMAR.shift();
1435 make $past;
1440 method package_def($/, $key) {
1441 our $?PACKAGE;
1442 our $?CLASS;
1443 our $?GRAMMAR;
1444 our $?NS;
1445 our $?INIT;
1447 if $key eq 'open' {
1448 # Start of package definition. Handle class and grammar specially.
1449 if $?PACKAGE =:= $?CLASS {
1450 # Start of class definition; make PAST to create class object.
1451 my $class_def := PAST::Op.new(
1452 :pasttype('bind'),
1453 PAST::Var.new(
1454 :name('$def'),
1455 :scope('lexical')
1457 PAST::Op.new(
1458 :pasttype('call'),
1459 :name('!keyword_class')
1463 # Add a name, if we have one.
1464 if $<name> {
1465 $class_def[1].push( PAST::Val.new( :value(~$<name>[0]) ) );
1468 $?CLASS.push($class_def);
1470 elsif $?PACKAGE =:= $?GRAMMAR {
1471 # Anonymous grammars not supported.
1472 unless $<name> {
1473 $/.panic('Anonymous grammars not supported');
1476 # Start of grammar definition. Create grammar class object.
1477 $?GRAMMAR.push(
1478 PAST::Op.new(
1479 :pasttype('bind'),
1480 PAST::Var.new(
1481 :name('$def'),
1482 :scope('lexical')
1484 PAST::Op.new(
1485 :pasttype('call'),
1486 :name('!keyword_grammar'),
1487 PAST::Val.new( :value(~$<name>[0]) )
1492 else {
1493 # Anonymous modules not supported.
1494 unless $<name> {
1495 $/.panic('Anonymous modules not supported');
1499 # Also store the current namespace, if we're not anonymous.
1500 if $<name> {
1501 $?NS := $<name>[0]<ident>;
1504 else {
1505 # XXX For now, to work around the :load :init not being allowed to be
1506 # an outer bug, we will enclose the actual package block inside an
1507 # immediate block of its own.
1508 my $inner_block := $( $<package_block> );
1509 $inner_block.blocktype('immediate');
1510 my $past := PAST::Block.new(
1511 $inner_block
1514 # Declare the namespace and that the result block holds things that we
1515 # do "on load".
1516 if $<name> {
1517 $past.namespace($<name>[0]<ident>);
1519 $past.blocktype('declaration');
1520 $past.pirflags(':init :load');
1522 if $?PACKAGE =:= $?CLASS {
1523 # Apply traits.
1524 apply_package_traits($?CLASS, $<trait>);
1526 # It's a class. Make proto-object.
1527 $?CLASS.push(
1528 PAST::Op.new(
1529 :pasttype('callmethod'),
1530 :name('register'),
1531 PAST::Var.new(
1532 :scope('package'),
1533 :name('$!P6META'),
1534 :namespace('Perl6Object')
1536 PAST::Var.new(
1537 :scope('lexical'),
1538 :name('$def')
1540 PAST::Val.new(
1541 :value('Any'),
1542 :named( PAST::Val.new( :value('parent') ) )
1547 # If this is an anonymous class, the block doesn't want to be a
1548 # :init :load, and it's going to contain the class definition, so
1549 # we need to declare the lexical $def.
1550 unless $<name> {
1551 $past.pirflags('');
1552 $past.blocktype('immediate');
1553 $past[0].push(PAST::Var.new(
1554 :name('$def'),
1555 :scope('lexical'),
1556 :isdecl(1)
1560 # Attatch any class initialization code to the init code;
1561 # note that we skip blocks, which are method accessors that
1562 # we want to put under this block so they get the correct
1563 # namespace. If it's an anonymous class, everything goes into
1564 # this block.
1565 unless defined( $?INIT ) {
1566 $?INIT := PAST::Block.new();
1568 for @( $?CLASS ) {
1569 if $_.WHAT() eq 'Block' || !$<name> {
1570 $past[0].push( $_ );
1572 else {
1573 $?INIT.push( $_ );
1577 elsif $?PACKAGE =:= $?GRAMMAR {
1578 # Apply traits.
1579 apply_package_traits($?GRAMMAR, $<trait>);
1581 # Make proto-object for grammar.
1582 $?GRAMMAR.push(
1583 PAST::Op.new(
1584 :pasttype('callmethod'),
1585 :name('register'),
1586 PAST::Var.new(
1587 :scope('package'),
1588 :name('$!P6META'),
1589 :namespace('Perl6Object')
1591 PAST::Var.new(
1592 :scope('lexical'),
1593 :name('$def')
1595 PAST::Val.new(
1596 :value('Grammar'),
1597 :named( PAST::Val.new( :value('parent') ) )
1602 # Attatch grammar declaration to the init code.
1603 unless defined( $?INIT ) {
1604 $?INIT := PAST::Block.new();
1606 $?INIT.push( $?GRAMMAR );
1608 # Clear namespace.
1609 $?NS := '';
1612 make $past;
1617 method role_def($/, $key) {
1618 our $?ROLE;
1619 our $?NS;
1620 our $?INIT;
1622 if $key eq 'open' {
1623 # Start of role definition. Push on code to create a role object.
1624 $?ROLE.push(
1625 PAST::Op.new(
1626 :pasttype('bind'),
1627 PAST::Var.new(
1628 :name('$def'),
1629 :scope('lexical')
1631 PAST::Op.new(
1632 :pasttype('call'),
1633 :name('!keyword_role'),
1634 PAST::Val.new( :value(~$<name>) )
1639 # Also store the current namespace.
1640 $?NS := $<name><ident>;
1642 else {
1643 # Declare the namespace and that the result block holds things that we
1644 # do "on load".
1645 my $past := $( $<package_block> );
1646 $past.namespace($<name><ident>);
1647 $past.blocktype('declaration');
1648 $past.pirflags(':init :load');
1650 # Apply traits.
1651 apply_package_traits($?ROLE, $<trait>);
1653 # Attatch role declaration to the init code, skipping blocks since
1654 # those are accessors.
1655 unless defined( $?INIT ) {
1656 $?INIT := PAST::Block.new();
1658 for @( $?ROLE ) {
1659 if $_.WHAT() eq 'Block' {
1660 $past.push( $_ );
1662 else {
1663 $?INIT.push( $_ );
1667 # Clear namespace.
1668 $?NS := '';
1670 make $past;
1675 method package_block($/, $key) {
1676 my $past := $( $/{$key} );
1677 make $past;
1681 method variable_declarator($/) {
1682 my $past := $( $<variable> );
1684 # If it's an attribute declaration, we handle traits elsewhere.
1685 my $twigil := $<variable><twigil>[0];
1686 if $<trait> && $twigil ne '.' && $twigil ne '!' {
1687 for $<trait> {
1688 my $trait := $_;
1689 if $trait<trait_auxiliary> {
1690 my $aux := $trait<trait_auxiliary>;
1691 my $sym := $aux<sym>;
1692 if $sym eq 'is' {
1693 if $aux<postcircumfix> {
1694 $/.panic("'" ~ ~$trait ~ "' not implemented");
1696 else {
1697 $past.viviself(~$aux<name>);
1700 else {
1701 $/.panic("'" ~ $sym ~ "' not implemented");
1704 elsif $trait<trait_verb> {
1705 my $verb := $trait<trait_verb>;
1706 my $sym := $verb<sym>;
1707 if $sym ne 'handles' {
1708 $/.panic("'" ~ $sym ~ "' not implemented");
1714 make $past;
1718 method scoped($/) {
1719 my $past;
1721 # Variable declaration?
1722 if $<declarator><variable_declarator> {
1723 $past := $( $<declarator><variable_declarator> );
1725 # Unless it's an attribute, emit code to set type and initialize it to
1726 # the correct proto.
1727 if $<fulltypename> && $past.WHAT() eq 'Var' {
1728 my $type_pir := " %r = new %0, %1\n setprop %r, 'type', %2\n";
1729 my $type := build_type($<fulltypename>);
1730 $past.viviself(
1731 PAST::Op.new(
1732 :inline($type_pir),
1733 PAST::Val.new( :value(~$past.viviself()) ),
1734 PAST::Op.new(
1735 :pasttype('if'),
1736 PAST::Op.new(
1737 :pirop('isa'),
1738 $type,
1739 PAST::Val.new( :value("P6protoobject") )
1741 $type,
1742 PAST::Var.new(
1743 :name('Failure'),
1744 :scope('package')
1747 $type
1753 # Variable declaration, but with a signature?
1754 elsif $<declarator><signature> {
1755 if $<fulltypename> {
1756 $/.panic("Distributing a type across a signature at declaration unimplemented.");
1758 $past := $( $<declarator><signature> );
1761 # Routine declaration?
1762 else {
1763 $past := $( $<routine_declarator> );
1765 # Don't support setting return type yet.
1766 if $<fulltypename> {
1767 $/.panic("Setting return type of a routine not yet implemented.");
1770 make $past;
1774 sub declare_attribute($/, $sym, $variable_sigil, $variable_twigil, $variable_name) {
1775 # Get the class or role we're in.
1776 our $?CLASS;
1777 our $?ROLE;
1778 our $?PACKAGE;
1779 our $?BLOCK;
1780 my $class_def;
1781 if $?ROLE =:= $?PACKAGE {
1782 $class_def := $?ROLE;
1784 else {
1785 $class_def := $?CLASS;
1787 unless defined( $class_def ) {
1788 $/.panic(
1789 "attempt to define attribute '" ~ $name ~ "' outside of class"
1793 # Is this a role-private or just a normal attribute?
1794 my $name;
1795 if $sym eq 'my' {
1796 # These are only allowed inside a role.
1797 unless $class_def =:= $?ROLE {
1798 $/.panic('Role private attributes can only be declared in a role');
1801 # We need to name-manage this somehow. We'll do $!rolename!attrname
1802 # for now; long term, want some UUID. For the block entry, we enter it
1803 # as $!attrname, add the real name and set the scope as rpattribute,
1804 # then translate it to the right thing when we see it.
1805 our $?NS;
1806 $name := ~$variable_sigil ~ '!' ~ $?NS[0] ~ '!' ~ ~$variable_name;
1807 my $visible_name := ~$variable_sigil ~ '!' ~ ~$variable_name;
1808 my $real_name := '!' ~ $?NS[0] ~ '!' ~ ~$variable_name;
1809 $?BLOCK.symbol($visible_name, :scope('rpattribute'), :real_name($real_name));
1811 else {
1812 # Register name as attribute scope.
1813 $name := ~$variable_sigil ~ '!' ~ ~$variable_name;
1814 $?BLOCK.symbol($name, :scope('attribute'));
1817 # Add attribute to class (always name it with ! twigil).
1818 if $/<scoped><fulltypename> {
1819 $class_def.push(
1820 PAST::Op.new(
1821 :pasttype('call'),
1822 :name('!keyword_has'),
1823 PAST::Var.new(
1824 :name('$def'),
1825 :scope('lexical')
1827 PAST::Val.new( :value($name) ),
1828 build_type($/<scoped><fulltypename>)
1832 else {
1833 $class_def.push(
1834 PAST::Op.new(
1835 :pasttype('call'),
1836 :name('!keyword_has'),
1837 PAST::Var.new(
1838 :name('$def'),
1839 :scope('lexical')
1841 PAST::Val.new( :value($name) )
1846 # Is there any "handles" trait verb or an "is rw" or "is ro"?
1847 my $rw := 0;
1848 if $<scoped><declarator><variable_declarator><trait> {
1849 for $<scoped><declarator><variable_declarator><trait> {
1850 if $_<trait_verb><sym> eq 'handles' {
1851 # Get the methods for the handles and add them to
1852 # the class
1853 my $meths := process_handles(
1855 $( $_<trait_verb><EXPR> ),
1856 $name
1858 for @($meths) {
1859 $class_def.push($_);
1862 elsif $_<trait_auxiliary><sym> eq 'is' {
1863 # Just handle rw for now.
1864 if ~$_<trait_auxiliary><name> eq 'rw' {
1865 $rw := 1;
1867 else {
1868 $/.panic("Only 'is rw' trait is implemented for attributes");
1871 else {
1872 $/.panic("Only is and handles trait verbs are implemented for attributes");
1877 # Twigil handling.
1878 if $variable_twigil eq '.' {
1879 # We have a . twigil, so we need to generate an accessor.
1880 my $accessor := make_accessor($/, ~$variable_name, $name, $rw, 'attribute');
1881 $class_def.push(add_method_to_class($accessor));
1883 elsif $variable_twigil eq '!' {
1884 # Don't need to do anything.
1886 elsif $variable_twigil eq '' {
1887 # We have no twigil, make $name as an alias to $!name.
1888 $?BLOCK.symbol(
1889 ~$variable_sigil ~ ~$variable_name, :scope('attribute')
1892 else {
1893 # It's a twigil that you canny use in an attribute declaration.
1894 $/.panic(
1895 "invalid twigil "
1896 ~ $variable_twigil ~ " in attribute declaration"
1901 method scope_declarator($/) {
1902 our $?BLOCK;
1903 my $declarator := $<sym>;
1904 my $past := $( $<scoped> );
1906 # What sort of thing are we scoping?
1907 if $<scoped><declarator><variable_declarator> {
1908 our $?PACKAGE;
1909 our $?ROLE;
1910 our $?CLASS;
1912 # Variable. If it's declared with "has" it is always an attribute. If
1913 # it is declared with "my" inside a role and has the ! twigil, it is
1914 # a role private attribute.
1915 my $variable := $<scoped><declarator><variable_declarator><variable>;
1916 my $twigil := $variable<twigil>[0];
1917 my $role_priv := $?ROLE =:= $?PACKAGE && $declarator eq 'my' && $twigil eq '!';
1918 if $declarator eq 'has' || $role_priv {
1919 # Attribute declarations need special handling.
1920 my $sigil := ~$<scoped><declarator><variable_declarator><variable><sigil>;
1921 my $twigil := ~$<scoped><declarator><variable_declarator><variable><twigil>[0];
1922 my $name := ~$<scoped><declarator><variable_declarator><variable><name>;
1923 declare_attribute($/, $declarator, $sigil, $twigil, $name);
1925 # We don't have any PAST at the point of the declaration.
1926 $past := PAST::Stmts.new();
1929 # If we're in a class and have something declared with a sigil, then
1930 # we need to generate an accessor method and emit that along with the
1931 # lexical declaration itself.
1932 elsif ($twigil eq '.' || $twigil eq '!') && $?CLASS =:= $?PACKAGE {
1933 # This node is just the variable declaration; also register it in
1934 # the symbol table.
1935 my $orig_past := $past;
1936 $past := PAST::Var.new(
1937 :name(~$variable<sigil> ~ '!' ~ ~$variable<name>),
1938 :scope('lexical'),
1939 :isdecl(1),
1940 :viviself(container_type(~$variable<sigil>))
1942 $?BLOCK.symbol($past.name(), :scope('lexical'));
1944 # Now generate accessor, if it's public.
1945 if $twigil eq '.' {
1946 $?CLASS.push(make_accessor($/, $orig_past.name(), $past.name(), 1, 'lexical'));
1950 # Otherwise, just a normal variable declaration.
1951 else {
1952 # Has this already been declared?
1953 my $name := $past.name();
1954 unless $?BLOCK.symbol($name) {
1955 # First declaration
1956 my $scope := 'lexical';
1957 $past.isdecl(1);
1958 if $declarator eq 'our' {
1959 $scope := 'package';
1961 elsif $declarator ne 'my' {
1962 $/.panic(
1963 "scope declarator '"
1964 ~ $declarator ~ "' not implemented"
1968 # Add block entry.
1969 $?BLOCK.symbol($name, :scope($scope));
1974 # Signature.
1975 elsif $<scoped><declarator><signature> {
1976 # We'll emit code to declare each of the parameters, then we'll have
1977 # the declaration evaluate to the signature object, thus allowing an
1978 # assignment to it.
1979 my @declare := sig_extract_declarables($/, $past);
1980 $past := PAST::Stmts.new($past);
1981 for @declare {
1982 # Work out sigil and twigil.
1983 my $sigil := substr($_, 0, 1);
1984 my $twigil := substr($_, 1, 1);
1985 my $desigilname;
1986 if $twigil eq '.' || $twigil eq '!' {
1987 $desigilname := substr($_, 2);
1989 else {
1990 $twigil := '';
1991 $desigilname := substr($_, 1);
1994 # Decide by declarator.
1995 if $declarator eq 'my' || $declarator eq 'our' {
1996 # Add declaration code.
1997 my $scope;
1998 if $declarator eq 'my' {
1999 $scope := 'lexical'
2001 else {
2002 $scope := 'package';
2004 $past.unshift(PAST::Var.new(
2005 :name($_),
2006 :isdecl(1),
2007 :scope($scope),
2008 :viviself('Perl6Scalar')
2011 # Add block entry.
2012 $?BLOCK.symbol($_, :scope($scope));
2013 } elsif $declarator eq 'has' {
2014 declare_attribute($/, $declarator, $sigil, $twigil, $desigilname);
2016 else {
2017 $/.panic("Scope declarator " ~ $declarator ~ " unimplemented with signatures.");
2022 # Routine?
2023 elsif $<scoped><routine_declarator> {
2024 # What declarator?
2025 if $declarator eq 'our' {
2026 # Default, nothing to do.
2028 elsif $declarator eq 'my' {
2029 if $<scoped><routine_declarator><sym> eq 'method' {
2030 # Add ! to start of name.
2031 $past.name('!' ~ $past.name());
2033 else {
2034 $/.panic("Lexically scoped subs not yet implemented.");
2037 else {
2038 $/.panic("Cannot apply declarator '" ~ $declarator ~ "' to a routine.");
2042 # Something else we've not implemetned yet?
2043 else {
2044 $/.panic("Don't know how to apply a scope declarator here.");
2047 make $past;
2051 method variable($/, $key) {
2052 my $past;
2053 if $key eq 'special_variable' {
2054 $past := $( $<special_variable> );
2056 elsif $key eq '$0' {
2057 $past := PAST::Var.new(
2058 :scope('keyed_int'),
2059 :node($/),
2060 :viviself('Failure'),
2061 PAST::Var.new(
2062 :scope('lexical'),
2063 :name('$/')
2065 PAST::Val.new(
2066 :value(~$<matchidx>),
2067 :returns('Int')
2071 elsif $key eq '$<>' {
2072 $past := $( $<postcircumfix> );
2073 $past.unshift(PAST::Var.new(
2074 :scope('lexical'),
2075 :name('$/'),
2076 :viviself('Failure')
2079 else {
2080 our $?BLOCK;
2081 # Handle naming.
2082 my @ident := $<name><ident>;
2083 my $name;
2084 PIR q< $P0 = find_lex '@ident' >;
2085 PIR q< $P0 = clone $P0 >;
2086 PIR q< store_lex '@ident', $P0 >;
2087 PIR q< $P1 = pop $P0 >;
2088 PIR q< store_lex '$name', $P1 >;
2090 my $twigil := ~$<twigil>[0];
2091 my $sigil := ~$<sigil>;
2092 my $fullname := $sigil ~ $twigil ~ ~$name;
2094 if $fullname eq '@_' || $fullname eq '%_' {
2095 unless $?BLOCK.symbol($fullname) {
2096 $?BLOCK.symbol( $fullname, :scope('lexical') );
2097 my $var;
2098 if $sigil eq '@' {
2099 $var := PAST::Var.new( :name($fullname), :scope('parameter'), :slurpy(1) );
2101 else {
2102 $var := PAST::Var.new( :name($fullname), :scope('parameter'), :slurpy(1), :named(1) );
2104 $?BLOCK[0].unshift($var);
2108 if $twigil eq '^' || $twigil eq ':' {
2109 if $?BLOCK.symbol('___HAVE_A_SIGNATURE') {
2110 $/.panic('A signature must not be defined on a sub that uses placeholder vars.');
2112 unless $?BLOCK.symbol($fullname) {
2113 $?BLOCK.symbol( $fullname, :scope('lexical') );
2114 $?BLOCK.arity( +$?BLOCK.arity() + 1 );
2115 my $var := PAST::Var.new(:name($fullname), :scope('parameter'));
2116 if $twigil eq ':' { $var.named( ~$name ); }
2117 my $block := $?BLOCK[0];
2118 my $i := +@($block);
2119 while $i > 0 && $block[$i-1]<name> gt $fullname {
2120 $block[$i] := $block[$i-1];
2121 $i--;
2123 $block[$i] := $var;
2127 # If it's $.x, it's a method call, not a variable.
2128 if $twigil eq '.' {
2129 $past := PAST::Op.new(
2130 :node($/),
2131 :pasttype('callmethod'),
2132 :name($name),
2133 PAST::Var.new(
2134 :name('self'),
2135 :scope('lexical'),
2136 :node($/)
2140 else {
2141 # Variable. [!:^] twigil should be kept in the name.
2142 if $twigil eq '!' || $twigil eq ':' || $twigil eq '^' { $name := $twigil ~ ~$name; }
2144 # All but subs should keep their sigils.
2145 my $sigil := '';
2146 if $<sigil> ne '&' {
2147 $sigil := ~$<sigil>;
2150 # If we have no twigil, but we see the name noted as an attribute in
2151 # an enclosing scope, add the ! twigil anyway; it's an alias.
2152 if $twigil eq '' {
2153 our @?BLOCK;
2154 for @?BLOCK {
2155 if defined( $_ ) {
2156 my $sym_table := $_.symbol($sigil ~ $name);
2157 if defined( $sym_table )
2158 && $sym_table<scope> eq 'attribute' {
2159 $name := '!' ~ $name;
2165 # If it's a role-private attribute, fix up the name.
2166 if $twigil eq '!' {
2167 our @?BLOCK;
2168 for @?BLOCK {
2169 if defined( $_ ) {
2170 my $sym_table := $_.symbol($sigil ~ $name);
2171 if defined( $sym_table )
2172 && $sym_table<scope> eq 'rpattribute' {
2173 $name := $sym_table<real_name>;
2179 $past := PAST::Var.new(
2180 :name( $sigil ~ $name ),
2181 :node($/)
2183 if @ident || $twigil eq '*' {
2184 $past.namespace(@ident);
2185 $past.scope('package');
2188 # If it has a ! twigil, give it attribute scope and add self.
2189 if $twigil eq '!' {
2190 $past.scope('attribute');
2191 $past.unshift(PAST::Var.new(
2192 :name('self'),
2193 :scope('lexical')
2197 # If we have something with an & sigil see if it has any entries
2198 # in the enclosing blocks; otherwise, default to package.
2199 if $<sigil> eq '&' {
2200 $past.scope('package');
2201 our @?BLOCK;
2202 for @?BLOCK {
2203 if defined($_) {
2204 my $sym_table := $_.symbol($name);
2205 if defined($sym_table) && defined($sym_table<scope>) {
2206 $past.scope( $sym_table<scope> );
2212 $past.viviself(container_type($sigil));
2215 make $past;
2219 method circumfix($/, $key) {
2220 my $past;
2221 if $key eq '( )' {
2222 $past := $<statementlist><statement>
2223 ?? $( $<statementlist> )
2224 !! PAST::Op.new(:name('list'));
2226 if $key eq '[ ]' {
2227 $past := PAST::Op.new(:name('circumfix:[ ]'), :node($/) );
2228 if $<statementlist><statement> { $past.push( $( $<statementlist> ) ); }
2230 elsif $key eq '{ }' {
2231 # If it is completely empty or consists of a single list, the first
2232 # element of which is either a hash or a pair, it's a hash constructor.
2233 $past := $( $<pblock> );
2234 my $is_hash := 0;
2235 if +@($past) == 2 && +@($past[0]) == 0 {
2236 if +@($past[1]) == 0 {
2237 # Empty block, so a hash.
2238 $is_hash := 1;
2240 elsif +@($past[1]) == 1 && $past[1][0].WHAT() eq 'Op' {
2241 if $past[1][0].name() eq 'infix:=>' {
2242 # Block with just one pair in it, so a hash.
2243 $is_hash := 1;
2245 elsif $past[1][0].name() eq 'infix:,' {
2246 # List, but first elements must be...
2247 if $past[1][0][0].WHAT() eq 'Op' &&
2248 $past[1][0][0].name() eq 'infix:=>' {
2249 # ...a Pair
2250 $is_hash := 1;
2252 elsif $past[1][0][0].WHAT() eq 'Var' &&
2253 substr($past[1][0][0].name(), 0, 1) eq '%' {
2254 # ...or a hash.
2255 $is_hash := 1
2260 if $is_hash {
2261 my @children := @($past[1]);
2262 $past := PAST::Op.new(
2263 :pasttype('call'),
2264 :name('hash'),
2265 :node($/)
2267 for @children {
2268 $past.push($_);
2271 else {
2272 declare_implicit_function_vars($past);
2275 elsif $key eq '$( )' {
2276 my $method := contextualizer_name($/, $<sigil>);
2277 my $call_on := $( $<semilist> );
2278 if $call_on.name() eq 'infix:,' && +@($call_on) == 0 {
2279 $call_on := PAST::Var.new(
2280 :name('$/'),
2281 :scope('lexical')
2284 $past := PAST::Op.new(
2285 :pasttype('callmethod'),
2286 :name($method),
2287 :node($/),
2288 $call_on
2291 make $past;
2295 method value($/, $key) {
2296 make $( $/{$key} );
2300 method number($/, $key) {
2301 make $( $/{$key} );
2305 ## for a variety of reasons, this is easier in PIR than NQP for now.
2306 ## NQP doesn't have assign yet, and Perl6Str is lighter-weight than Str.
2307 method integer($/) {
2308 my $str;
2309 PIR q< $P0 = find_lex '$/' >;
2310 PIR q< $S0 = $P0 >;
2311 PIR q< $P1 = new 'Perl6Str' >;
2312 PIR q< assign $P1, $S0 >;
2313 PIR q< store_lex '$str', $P1 >;
2314 make PAST::Val.new(
2315 :value( +$str ),
2316 :returns('Int'),
2317 :node( $/ )
2322 method dec_number($/) {
2323 make PAST::Val.new( :value( ~$/ ), :returns('Num'), :node( $/ ) );
2326 method radint($/, $key) {
2327 make $( $/{$key} );
2330 method rad_number($/) {
2331 my $radix := ~$<radix>;
2332 my $intpart := ~$<intpart>;
2333 my $fracpart := ~$<fracpart>;
2334 my $base;
2335 my $exp;
2336 if defined( $<base>[0] ) { $base := $<base>[0].text(); }
2337 if defined( $<exp>[0] ) { $exp := $<exp>[0].text(); }
2338 if ~$<postcircumfix> {
2339 my $radcalc := $( $<postcircumfix> );
2340 $radcalc.name('radcalc');
2341 $radcalc.pasttype('call');
2342 $radcalc.unshift( PAST::Val.new( :value( $radix ), :node( $/ ) ) );
2343 make $radcalc;
2345 else{
2346 my $return_type := 'Int';
2347 if $fracpart { $return_type := 'Num'; }
2348 make PAST::Val.new(
2349 :value( radcalc( $radix, $intpart, $fracpart, ~$base, ~$exp ) ),
2350 :returns($return_type),
2351 :node( $/ )
2357 method quote($/) {
2358 make $( $<quote_expression> );
2361 method quote_expression($/, $key) {
2362 my $past;
2363 if $key eq 'quote_regex' {
2364 our $?NS;
2365 $past := PAST::Block.new(
2366 $<quote_regex>,
2367 :compiler('PGE::Perl6Regex'),
2368 :namespace($?NS),
2369 :blocktype('declaration'),
2370 :node( $/ )
2373 elsif $key eq 'quote_concat' {
2374 if +$<quote_concat> == 1 {
2375 $past := $( $<quote_concat>[0] );
2377 else {
2378 $past := PAST::Op.new(
2379 :name('list'),
2380 :pasttype('call'),
2381 :node( $/ )
2383 for $<quote_concat> {
2384 $past.push( $($_) );
2388 make $past;
2392 method quote_concat($/) {
2393 my $terms := +$<quote_term>;
2394 my $count := 1;
2395 my $past := $( $<quote_term>[0] );
2396 while ($count != $terms) {
2397 $past := PAST::Op.new(
2398 $past,
2399 $( $<quote_term>[$count] ),
2400 :pirop('n_concat'),
2401 :pasttype('pirop')
2403 $count := $count + 1;
2405 make $past;
2409 method quote_term($/, $key) {
2410 my $past;
2411 if ($key eq 'literal') {
2412 $past := PAST::Val.new(
2413 :value( ~$<quote_literal> ),
2414 :returns('Perl6Str'), :node($/)
2417 elsif ($key eq 'variable') {
2418 $past := $( $<variable> );
2420 elsif ($key eq 'circumfix') {
2421 $past := $( $<circumfix> );
2422 if $past.WHAT() eq 'Block' {
2423 $past.blocktype('immediate');
2426 make $past;
2430 method typename($/) {
2431 # Extract shortname part of identifier, if there is one.
2432 my $ns := $<name><ident>.clone();
2433 my $shortname := $ns.pop();
2435 # Create default PAST node for package lookup of type.
2436 my $past := PAST::Var.new(
2437 :name($shortname),
2438 :namespace($ns),
2439 :scope('package'),
2440 :node($/),
2441 :viviself('Failure')
2444 # If there's no namespace, could be lexical abstraction type.
2445 if +@($ns) == 0 {
2446 # See if we got lexical with the right name.
2447 our @?BLOCK;
2448 my $name := '::' ~ $shortname;
2449 for @?BLOCK {
2450 if defined($_) {
2451 my $sym_table := $_.symbol($name);
2452 if defined($sym_table) && defined($sym_table<scope>) {
2453 $past.name( $name );
2454 $past.scope( $sym_table<scope> );
2460 make $past;
2464 method term($/, $key) {
2465 my $past;
2466 if $key eq 'func args' {
2467 $past := build_call( $( $<semilist> ) );
2468 $past.name( ~$<ident> );
2470 elsif $key eq 'listop args' {
2471 $past := build_call( $( $<arglist> ) );
2472 $past.name( ~$<ident> );
2474 elsif $key eq 'listop noarg' {
2475 $past := PAST::Op.new( :name( ~$<ident> ), :pasttype('call') );
2477 elsif $key eq 'VAR' {
2478 $past := PAST::Op.new(
2479 :name('!VAR'),
2480 :pasttype('call'),
2481 $( $<variable> )
2484 elsif $key eq 'sigil' {
2485 my $method := contextualizer_name($/, $<sigil>);
2487 $past := PAST::Op.new(
2488 :pasttype('callmethod'),
2489 :name($method),
2490 :node($/),
2491 $( $<arglist> )
2494 else { $past := $( $/{$key} ); }
2495 $past.node($/);
2496 make $past;
2500 method semilist($/) {
2501 my $past := $<EXPR>
2502 ?? $( $<EXPR>[0] )
2503 !! PAST::Op.new( :node($/), :name('infix:,') );
2504 make $past;
2508 method arglist($/) {
2509 my $past := $<EXPR>
2510 ?? $( $<EXPR> )
2511 !! PAST::Op.new( :node($/), :name('infix:,') );
2512 make $past;
2516 method EXPR($/, $key) {
2517 if $key eq 'end' {
2518 make $($<expr>);
2520 elsif ~$<type> eq 'infix:.=' {
2521 my $invocant := $( $/[0] );
2522 my $call := $( $/[1] );
2524 # Check that we have a sub call.
2525 if $call.WHAT() ne 'Op' || $call.pasttype() ne 'call' {
2526 $/.panic('.= must have a call on the right hand side');
2529 # Make a duplicate of the target node to receive result
2530 my $target := PAST::Var.new(
2531 :name($invocant.name()),
2532 :scope($invocant.scope()),
2533 :lvalue(1)
2536 # Change call node to a callmethod and add the invocant
2537 $call.pasttype('callmethod');
2538 $call.unshift($invocant);
2540 # and assign result to target
2541 my $past := PAST::Op.new(
2542 :inline(" %r = %1.'infix:='(%0)"),
2543 :node($/),
2544 $call,
2545 $target
2548 make $past;
2550 elsif ~$<type> eq 'infix:does' || ~$<type> eq 'infix:but' {
2551 my $past := PAST::Op.new(
2552 $( $/[0] ),
2553 :pasttype('call'),
2554 :name(~$<type>),
2555 :node($/)
2557 my $rhs := $( $/[1] );
2558 if $rhs.HOW().isa($rhs, PAST::Op) && $rhs.pasttype() eq 'call' {
2559 # Make sure we only have one initialization value.
2560 if +@($rhs) > 2 {
2561 $/.panic("Role initialization can only supply a value for one attribute");
2563 # Push role name and argument onto infix:does or infix:but.
2564 $past.push($rhs[0]);
2565 $past.push($rhs[1]);
2567 else {
2568 $past.push($rhs);
2570 make $past;
2572 else {
2573 my $past := PAST::Op.new(
2574 :node($/),
2575 :name($<type>),
2576 :opattr($<top>)
2578 if $<top><subname> { $past.name(~$<top><subname>); }
2579 for @($/) {
2580 unless +$_.from() == +$_.to() { $past.push( $($_) ) };
2583 make $past;
2588 method regex_declarator($/, $key) {
2589 make $( $/{$key} );
2593 method regex_declarator_regex($/) {
2594 my $past := $( $<quote_expression> );
2595 $past.name( ~$<ident>[0] );
2596 make $past;
2600 method regex_declarator_token($/) {
2601 my $past := $( $<quote_expression> );
2602 $past.compiler_args( :ratchet(1) );
2603 $past.name( ~$<ident>[0] );
2604 make $past;
2608 method regex_declarator_rule($/) {
2609 my $past := $( $<quote_expression> );
2610 $past.compiler_args( :s(1), :ratchet(1) );
2611 $past.name( ~$<ident>[0] );
2612 make $past;
2616 method type_declarator($/) {
2617 # We need a block containing the constraint condition.
2618 my $past := $( $<EXPR> );
2619 if $past.WHAT() ne 'Block' {
2620 # Make block with a smart match of the the expression as its contents.
2621 $past := PAST::Block.new(
2622 PAST::Stmts.new(
2623 PAST::Var.new(
2624 :scope('parameter'),
2625 :name('$_')
2628 PAST::Stmts.new(
2629 PAST::Op.new(
2630 :pasttype('callmethod'),
2631 :name('ACCEPTS'),
2632 $past,
2633 PAST::Var.new(
2634 :scope('lexical'),
2635 :name('$_')
2642 # Make sure it has a parameter and keep hold of it if found.
2643 my $param;
2644 my $dollar_underscore;
2645 for @($past[0]) {
2646 if $_.WHAT() eq 'Var' {
2647 if $_.scope() eq 'parameter' {
2648 $param := $_;
2650 elsif $_.name() eq '$_' {
2651 $dollar_underscore := $_;
2655 unless $param {
2656 if $dollar_underscore {
2657 $dollar_underscore.scope('parameter');
2658 $param := $dollar_underscore;
2660 else {
2661 $param := PAST::Var.new(
2662 :name('$_'),
2663 :scope('parameter')
2665 $past[0].push($param);
2669 # Do we have an existing constraint to check?
2670 if $<typename> {
2671 my $new_cond := $past[1];
2672 my $prev_cond := $( $<typename>[0] );
2673 $past[1] := PAST::Op.new(
2674 :pasttype('if'),
2675 PAST::Op.new(
2676 :pasttype('callmethod'),
2677 :name('ACCEPTS'),
2678 $prev_cond,
2679 PAST::Var.new(
2680 :name($param.name())
2683 $new_cond
2687 # Set block details.
2688 $past.node($/);
2690 # Now we need to create the block wrapper class.
2691 $past := PAST::Op.new(
2692 :pasttype('callmethod'),
2693 :name('!create'),
2694 PAST::Var.new(
2695 :name('Subset'),
2696 :scope('package')
2698 PAST::Val.new( :value(~$<name>) ),
2699 $past
2702 make $past;
2706 method fatarrow($/) {
2707 my $past := PAST::Op.new(
2708 :node($/),
2709 :pasttype('call'),
2710 :name('infix:=>'),
2711 :returns('Pair'),
2712 PAST::Val.new( :value(~$<key>) ),
2713 $( $<val> )
2715 make $past;
2719 method colonpair($/, $key) {
2720 my $pair_key;
2721 my $pair_val;
2723 if $key eq 'false' {
2724 $pair_key := PAST::Val.new( :value(~$<ident>) );
2725 $pair_val := PAST::Val.new( :value(0), :returns('Int') );
2727 elsif $key eq 'value' {
2728 $pair_key := PAST::Val.new( :value(~$<ident>) );
2729 if $<postcircumfix> {
2730 $pair_val := $( $<postcircumfix>[0] );
2731 if $pair_val.name() ne 'infix:,' || +@($pair_val) == 1 {
2732 $pair_val := $pair_val[0];
2735 else {
2736 $pair_val := PAST::Val.new( :value(1), :returns('Int') );
2739 elsif $key eq 'varname' {
2740 if $<desigilname><name> {
2741 $pair_key := PAST::Val.new( :value( ~$<desigilname> ) );
2742 $pair_val := PAST::Var.new(
2743 :name( ~$<sigil> ~ ~$<twigil> ~ ~$<desigilname> )
2746 else {
2747 $/.panic('complex varname colonpair case not yet implemented');
2750 else {
2751 $/.panic($key ~ " pairs not yet implemented.");
2754 my $past := PAST::Op.new(
2755 :node($/),
2756 :pasttype('call'),
2757 :name('infix:=>'),
2758 :returns('Pair'),
2759 $pair_key,
2760 $pair_val
2762 make $past;
2766 method capterm($/) {
2767 # We will create the capture object, passing the things supplied.
2768 my $past := build_call( $( $<capture> ) );
2769 $past.name('prefix:\\');
2770 make $past;
2774 method capture($/) {
2775 make $( $<EXPR> );
2779 method sigterm($/) {
2780 my $past := $( $/<signature> );
2781 make $past;
2785 # Used by all calling code to process arguments into the correct form.
2786 sub build_call($args) {
2787 if $args.WHAT() ne 'Op' || $args.name() ne 'infix:,' {
2788 $args := PAST::Op.new( :node($args), :name('infix:,'), $args);
2790 my $i := 0;
2791 my $elems := +@($args);
2792 while $i < $elems {
2793 my $x := $args[$i];
2794 if $x.returns() eq 'Pair' {
2795 $x[1].named($x[0]);
2796 $args[$i] := $x[1];
2798 $i++;
2800 $args.pasttype('call');
2801 $args;
2805 sub declare_implicit_var($block, $name, $type) {
2806 unless $block.symbol($name) {
2807 my $var := PAST::Var.new( :name($name), :isdecl(1) );
2808 $var.scope($type eq 'parameter' ?? 'parameter' !! 'lexical');
2809 if $type eq 'new' {
2810 $var.viviself( 'Perl6Scalar' );
2812 else {
2813 my $opast := PAST::Op.new(
2814 :name('!OUTER'),
2815 PAST::Val.new( :value($name) )
2817 $var.viviself($opast);
2819 $block[0].push($var);
2820 $block.symbol($name, :scope('lexical') );
2825 sub declare_implicit_function_vars($block) {
2826 declare_implicit_var($block, '$_',
2827 defined($block.arity()) ?? 'outer' !! 'parameter');
2828 declare_implicit_var($block, '$!', 'outer');
2829 declare_implicit_var($block, '$/', 'outer');
2833 sub declare_implicit_immediate_vars($block) {
2834 declare_implicit_var($block, '$_', 'outer');
2835 declare_implicit_var($block, '$!', 'outer');
2836 declare_implicit_var($block, '$/', 'outer');
2840 sub contextualizer_name($/, $sigil) {
2841 ## Contextualizing is calling .item, .list, .hash, etc.
2842 ## on the expression in the brackets
2843 my $method;
2844 if $sigil eq '$' { $method := 'item'; }
2845 elsif $sigil eq '@' { $method := 'list'; }
2846 elsif $sigil eq '%' { $method := 'hash'; }
2847 else {
2848 $/.panic("Use of contextualizer " ~ $sigil ~ " not implemented.");
2850 $method
2854 sub container_type($sigil) {
2855 if $sigil eq '@' { return 'Perl6Array' }
2856 elsif $sigil eq '%' { return 'Perl6Hash' }
2857 else { return 'Perl6Scalar' }
2861 # Processes a handles expression to produce the appropriate method(s).
2862 sub process_handles($/, $expr, $attr_name) {
2863 my $past := PAST::Stmts.new();
2865 # What type of expression do we have?
2866 if $expr.WHAT() eq 'Val' && $expr.returns() eq 'Perl6Str' {
2867 # Just a single string mapping.
2868 my $name := ~$expr.value();
2869 my $method := make_handles_method($/, $name, $name, $attr_name);
2870 $past.push(add_method_to_class($method));
2872 elsif $expr.WHAT() eq 'Op' && $expr.returns() eq 'Pair' {
2873 # Single pair.
2874 my $method := make_handles_method_from_pair($/, $expr, $attr_name);
2875 $past.push(add_method_to_class($method));
2877 elsif $expr.WHAT() eq 'Op' && $expr.pasttype() eq 'call' &&
2878 $expr.name() eq 'list' {
2879 # List of something, but what is it?
2880 for @($expr) {
2881 if $_.WHAT() eq 'Val' && $_.returns() eq 'Perl6Str' {
2882 # String value.
2883 my $name := ~$_.value();
2884 my $method := make_handles_method($/, $name, $name, $attr_name);
2885 $past.push(add_method_to_class($method));
2887 elsif $_.WHAT() eq 'Op' && $_.returns() eq 'Pair' {
2888 # Pair.
2889 my $method := make_handles_method_from_pair($/, $_, $attr_name);
2890 $past.push(add_method_to_class($method));
2892 else {
2893 $/.panic(
2894 'Only a list of constants or pairs can be used in handles'
2899 elsif $expr.WHAT() eq 'Stmts' && $expr[0].name() eq 'infix:,' {
2900 # Also a list, but constructed differently.
2901 for @($expr[0]) {
2902 if $_.WHAT() eq 'Val' && $_.returns() eq 'Perl6Str' {
2903 # String value.
2904 my $name := ~$_.value();
2905 my $method := make_handles_method($/, $name, $name, $attr_name);
2906 $past.push(add_method_to_class($method));
2908 elsif $_.WHAT() eq 'Op' && $_.returns() eq 'Pair' {
2909 # Pair.
2910 my $method := make_handles_method_from_pair($/, $_, $attr_name);
2911 $past.push(add_method_to_class($method));
2913 else {
2914 $/.panic(
2915 'Only a list of constants or pairs can be used in handles'
2920 else {
2921 $/.panic('Illegal or unimplemented use of handles');
2924 $past
2928 # Produces a handles method.
2929 sub make_handles_method($/, $from_name, $to_name, $attr_name) {
2930 PAST::Block.new(
2931 :name($from_name),
2932 :pirflags(':method'),
2933 :blocktype('declaration'),
2934 :node($/),
2935 PAST::Var.new(
2936 :name('@a'),
2937 :scope('parameter'),
2938 :slurpy(1)
2940 PAST::Var.new(
2941 :name('%h'),
2942 :scope('parameter'),
2943 :named(1),
2944 :slurpy(1)
2946 PAST::Op.new(
2947 :name($to_name),
2948 :pasttype('callmethod'),
2949 PAST::Var.new(
2950 :name($attr_name),
2951 :scope('attribute')
2953 PAST::Var.new(
2954 :name('@a'),
2955 :scope('lexical'),
2956 :flat(1)
2958 PAST::Var.new(
2959 :name('%h'),
2960 :scope('lexical'),
2961 :flat(1),
2962 :named(PAST::Val.new( :value(1) ))
2969 # Makes a handles method from a pair.
2970 sub make_handles_method_from_pair($/, $pair, $attr_name) {
2971 my $meth;
2973 # Single pair mapping. Check we have string name and value.
2974 my $key := $pair[0];
2975 my $value := $pair[1];
2976 if $key.WHAT() eq 'Val' && $value.WHAT() eq 'Val' {
2977 my $from_name := ~$key.value();
2978 my $to_name := ~$value.value();
2979 $meth := make_handles_method($/, $from_name, $to_name, $attr_name);
2981 else {
2982 $/.panic('Only constants may be used in a handles pair argument.');
2985 $meth
2989 # This takes an array of match objects of type constraints and builds a type
2990 # representation out of them.
2991 sub build_type($cons_pt) {
2992 # Build the type constraints list for the variable.
2993 my $num_types := 0;
2994 my $type_cons := PAST::Op.new();
2995 for $cons_pt {
2996 $type_cons.push( $( $_<typename> ) );
2997 $num_types := $num_types + 1;
3000 # If there were none, it's Object.
3001 if $num_types == 0 {
3002 $type_cons.push(PAST::Var.new(
3003 :name('Object'),
3004 :scope('package')
3006 $num_types := 1;
3009 # Now need to apply the type constraints. How many are there?
3010 if $num_types == 1 {
3011 # Just the first one.
3012 $type_cons := $type_cons[0];
3014 else {
3015 # Many; make an and junction of types.
3016 $type_cons.pasttype('call');
3017 $type_cons.name('all');
3020 $type_cons
3024 # Takes a block and turns it into a sub.
3025 sub create_sub($/, $past) {
3026 $past.blocktype('declaration');
3027 set_block_proto($past, 'Sub');
3028 if $<routine_def><multisig> {
3029 set_block_sig($past, $( $<routine_def><multisig>[0]<signature> ));
3031 else {
3032 set_block_sig($past, empty_signature());
3037 # Set the proto object type of a block.
3038 sub set_block_proto($block, $type) {
3039 my $loadinit := $block.loadinit();
3040 $loadinit.push(
3041 PAST::Op.new(
3042 :inline('setprop %0, "$!proto", %1'),
3043 PAST::Var.new( :name('block'), :scope('register') ),
3044 PAST::Var.new( :name($type), :scope('package') )
3050 # Associate a signature object with a block.
3051 sub set_block_sig($block, $sig_obj) {
3052 my $loadinit := $block.loadinit();
3053 $loadinit.push(
3054 PAST::Op.new(
3055 :inline('setprop %0, "$!signature", %1'),
3056 PAST::Var.new( :name('block'), :scope('register') ),
3057 $sig_obj
3063 # Create an empty signautre object for subs with no signatures.
3064 sub empty_signature() {
3065 PAST::Op.new(
3066 :pasttype('callmethod'),
3067 :name('!create'),
3068 PAST::Var.new(
3069 :name('Signature'),
3070 :scope('package'),
3071 :namespace(list())
3077 # Creates a signature descriptor (for now, just a hash).
3078 sub sig_descriptor_create() {
3079 PAST::Stmts.new(
3080 PAST::Op.new( :inline(' $P1 = new "Hash"') ),
3081 PAST::Stmts.new(),
3082 PAST::Op.new( :inline(' %r = $P1') )
3086 # Sets a given value in the signature descriptor.
3087 sub sig_descriptor_set($descriptor, $name, $value) {
3088 $descriptor[1].push(PAST::Op.new(
3089 :inline(' $P1[%0] = %1'),
3090 PAST::Val.new( :value(~$name) ),
3091 $value
3095 # Returns a list of variables from a signature that we are to declare. Panics
3096 # if the signature is too complex to unpack.
3097 sub sig_extract_declarables($/, $sig_setup) {
3098 # Just make sure it's what we expect.
3099 if $sig_setup.WHAT() ne 'Op' || $sig_setup.pasttype() ne 'callmethod' ||
3100 $sig_setup[0].name() ne 'Signature' {
3101 $/.panic("sig_extract_declarables was not passed signature declaration PAST!");
3104 # Now go through what signature and extract what to declare.
3105 my @result := list();
3106 my $first := 1;
3107 for @($sig_setup) {
3108 if $first {
3109 # Skip over invocant.
3110 $first := 0;
3112 else {
3113 # If it has a name, we're fine; if not, it's something odd - give
3114 # it a miss for now.
3115 my $found_name := undef;
3116 for @($_[1]) {
3117 if $_[0].value() eq 'name' {
3118 $found_name := ~$_[1].value();
3121 if defined($found_name) {
3122 @result.push($found_name);
3124 else {
3125 $/.panic("Signature too complex for LHS of assignment.");
3129 @result
3132 # Generates a setter/getter method for an attribute in a class or role.
3133 sub make_accessor($/, $method_name, $attr_name, $rw, $scope) {
3134 my $getset;
3135 if $rw {
3136 $getset := PAST::Var.new( :name($attr_name), :scope($scope) );
3138 else {
3139 $getset := PAST::Op.new(
3140 :inline(
3141 ' %r = new "Perl6Scalar", %0',
3142 ' $P0 = get_hll_global [ "Bool" ], "True"',
3143 ' setprop %r, "readonly", $P0'
3145 PAST::Var.new( :name($attr_name), :scope($scope) )
3148 my $accessor := PAST::Block.new(
3149 PAST::Stmts.new($getset),
3150 :blocktype('declaration'),
3151 :name($method_name),
3152 :pirflags(':method'),
3153 :node( $/ )
3155 $accessor
3159 # Adds the given method to the current class. This just returns the method that
3160 # is passed to it if the current class is named; in the case that it is anonymous
3161 # we need instead to emit an add_method call and remove the methods name so it
3162 # doesn't pollute the namespace.
3163 sub add_method_to_class($method) {
3164 our $?CLASS;
3165 our $?PACKAGE;
3166 if $?CLASS =:= $?PACKAGE && +@($?CLASS[0][1]) == 0 {
3167 # Create new PAST::Block - can't work out how to unset the name of an
3168 # existing one.
3169 my $new_method := PAST::Block.new(
3170 :blocktype($method.blocktype()),
3171 :pirflags($method.pirflags())
3173 for @($method) {
3174 $new_method.push($_);
3177 # Put call to add method into the class definition.
3178 $?CLASS.push(PAST::Op.new(
3179 :pasttype('callmethod'),
3180 :name('add_method'),
3181 PAST::Var.new(
3182 :name('$def'),
3183 :scope('lexical')
3185 PAST::Val.new( :value($method.name()) ),
3186 $new_method
3189 $new_method
3191 else {
3192 $method
3196 # Creates an anonymous subset type.
3197 sub make_anon_subset($past, $parameter) {
3198 # We need a block containing the constraint condition.
3199 if $past.WHAT() ne 'Block' {
3200 # Make block with the expression as its contents.
3201 $past := PAST::Block.new(
3202 PAST::Stmts.new(),
3203 PAST::Stmts.new( $past )
3207 # Make sure it has a parameter.
3208 my $param;
3209 my $dollar_underscore;
3210 for @($past[0]) {
3211 if $_.WHAT() eq 'Var' {
3212 if $_.scope() eq 'parameter' {
3213 $param := $_;
3215 elsif $_.name() eq '$_' {
3216 $dollar_underscore := $_;
3220 unless $param {
3221 if $dollar_underscore {
3222 $dollar_underscore.scope('parameter');
3223 $param := $dollar_underscore;
3225 else {
3226 $param := PAST::Var.new(
3227 :name('$_'),
3228 :scope('parameter')
3230 $past[0].push($param);
3234 # Now we'll just pass this block to the type checker,
3235 # since smart-matching a block invokes it.
3236 return PAST::Op.new(
3237 :pasttype('call'),
3238 :name('!TYPECHECKPARAM'),
3239 PAST::Op.new(
3240 :pirop('newclosure'),
3241 $past
3243 PAST::Var.new(
3244 :name($parameter.name()),
3245 :scope('lexical')
3250 # Local Variables:
3251 # mode: cperl
3252 # cperl-indent-level: 4
3253 # fill-column: 100
3254 # End:
3255 # vim: expandtab shiftwidth=4: