2 # Copyright (C) 2007, The Perl Foundation.
4 class Pynie
::Grammar
::Actions
;
7 make
$( $<file_input
> );
10 method file_input
($/) {
11 my $past := PAST
::Stmts
.new
( :node
($/) );
18 method suite
($/, $key) {
23 make
$( $<stmt_list
> );
27 my $past := PAST
::Stmts
.new
( :node
($/) );
34 method statement
($/, $key) {
38 method stmt_list
($/) {
39 my $past := PAST
::Stmts
.new
( :node
($/) );
46 method compound_stmt
($/, $key) {
50 method assert_stmt
($/) {
61 my $exp1 := $( $<exp1
> );
63 ## XXX change into "AssertionError"
64 my $exception := PAST
::Op
.new
( :inline
(' %r = new "Exception"') );
66 my $throwcode := PAST
::Op
.new
( $exception, :pirop
('throw'), :node
($/) );
68 my $debugcode := PAST
::Op
.new
( $exp1, $throwcode,
72 my $debugflag := PAST
::Var
.new
( :name
('__debug__'),
77 my $past := PAST
::Op
.new
( $debugflag,
86 my $cond := +$<expression
> - 1;
87 my $past := PAST
::Op
.new
( $( $<expression
>[$cond] ),
93 $past.push( $( $<else>[0] ) );
97 $past := PAST
::Op
.new
( $( $<expression
>[$cond] ),
107 method while_stmt
($/) {
108 my $past := PAST
::Op
.new
( $( $<expression
> ),
114 ## handle 'else' clause
115 $past := PAST
::Stmts
.new
( $past,
123 method parameter_list
($/) {
124 ## the only place for parameters to live is in a function block;
125 ## create that here already.
126 my $past := PAST
::Block
.new
( :blocktype
('declaration'), :node
($/) );
128 ## handle normal parameters
129 for $<defparameter
> {
133 ## handle '*' <identifier>
134 if $<excess_positional_parameter
> {
135 my $slurpparam := $( $<excess_positional_parameter
> );
136 $past.push( $slurpparam );
138 ## handle '**' <identifier>
139 if $<excess_keyword_parameter
> {
140 my $dictparam := $( $<excess_keyword_parameter
> );
141 $past.push( $dictparam );
146 method defparameter
($/) {
147 my $past := $( $<parameter
> );
148 $past.scope
('parameter');
150 ## add the default value for this parameter, if any
152 my $defaultvalue := $( $<expression
>[0] );
153 $past.viviself
( $defaultvalue );
158 method parameter
($/, $key) {
166 method excess_positional_parameter
($/) {
167 ## a :slurpy argument
168 my $past := $( $<identifier
> );
169 $past.scope
('parameter');
174 method excess_keyword_parameter
($/) {
175 ## a :named, :slurpy argument
176 my $past := $( $<identifier
> );
177 $past.scope
('parameter');
183 method lambda_form
($/) {
185 if $<parameter_list
> {
186 $past := $( $<parameter_list
>[0] );
188 else { # if no parameters, create a block here:
189 $past := PAST
::Block
.new
( :blocktype
('declaration'), :node
($/) );
192 my $expr := $( $<expression
> );
194 ## add a return statement to this block
195 $past.push( PAST
::Op
.new
( $expr, :pasttype
('return'), :node
($/) ) );
196 $past.control
('return_pir');
203 if $<parameter_list
> {
204 $past := $( $<parameter_list
>[0] );
207 $past := PAST
::Block
.new
( :blocktype
('declaration'), :node
($/) );
209 my $name := $( $<funcname
> );
210 $past.name
( $name.name
() );
211 $past.push( $($<suite
>) );
213 $past.control
('return_pir');
217 method funcname
($/) {
218 make
$( $<identifier
> );
221 method argument_list
($/) {
224 if $<positional_arguments
> {
225 $past := $( $<positional_arguments
> );
228 $past := PAST
::Op
.new
( :pasttype
('call'), :node
($/) );
231 if $<keyword_arguments
> {
232 for $( $<keyword_arguments
> ) {
233 ## XXX should this be: for @( $<keyword_arguments> )??
241 method positional_arguments
($/) {
242 my $past := PAST
::Op
.new
( :pasttype
('call'), :node
($/) );
249 method keyword_arguments
($/) {
250 my $past := PAST
::Op
.new
( :pasttype
('call'), :node
($/) );
251 for $<keyword_item
> {
257 method keyword_item
($/) {
258 my $past := $( $<expression
> );
259 my $name := $( $<identifier
> );
261 ## XXX why doesn't this work??
262 #$past.named( $name.name() );
263 #make PAST::Val.new( :value('100'), :named('x'), :node($/) );
267 method classname
($/) {
268 make
$( $<identifier
> );
271 method classdef
($/) {
272 ## a class definition is a set of statements
273 my $past := PAST
::Stmts
.new
( :node
($/) );
275 ## create an anonymous sub that generates the class
276 my $cdef := PAST
::Block
.new
( :blocktype
('declaration'), :node
($/) );
277 my $cname := $( $<classname
> );
278 my $pir := ' $P0 = newclass "' ~ $cname.name
() ~ '"';
279 $cdef.push( PAST
::Op
.new
( :inline
($pir) ) );
280 $cdef.pirflags
(':init :anon');
282 ## handle parents, if available
284 my $parent := $( $<inheritance
>[0] );
285 my $pir := ' addparent $P0, %0';
286 my $addparent := PAST
::Op
.new
( $parent, :inline
($pir), :node
($/) );
287 $cdef.push($addparent);
291 ## handle class contents
292 my $suite := $( $<suite
> );
297 method del_stmt
($/) {
300 my $targets := $( $<target_list
> );
302 my $past := PAST
::Stmts
.new
( :node
($/) );
304 my $pir := " .local pmc ns\n"
305 ~ ' ns = get_hll_namespace';
307 $past.push( PAST
::Op
.new
( :inline
($pir), :node
($/) ) );
309 $pir := ' delete ns["' ~ $_.name
() ~ '"]';
310 $past.push( PAST
::Op
.new
( :inline
($pir), :node
($/) ) );
316 method pass_stmt
($/) {
317 ## pass statement doesn't do anything, but do create a PAST
318 ## node to prevent special case code.
319 make PAST
::Op
.new
( :inline
(' # pass'), :node
($/) );
322 method raise_stmt
($/) {
324 my $numexpr := +$<expression
>;
326 ## think of better structure to handle this:
330 elsif $numexpr == 1 {
333 elsif $numexpr == 2 {
334 #my $exctype := $( $<expression> );
335 #my $excvalue := $( $<expression> );
337 elsif $numexpr == 3 {
339 } # else will never happen.
341 ## XXX for now this'll do:
342 my $exc := PAST
::Op
.new
( :inline
(' %r = new "Exception"'), :node
($/) );
343 my $pir := ' throw %0';
344 my $past := PAST
::Op
.new
( $exc, :inline
($pir), :node
($/) );
349 method simple_stmt
($/, $key) {
353 method expression_stmt
($/) {
354 make
$( $<expression_list
> );
357 method return_stmt
($/) {
358 my $past := PAST
::Op
.new
( :pasttype
('return'), :node
($/) );
359 if $<expression_list
> {
360 my $retvals := $( $<expression_list
>[0] );
361 $past.push($retvals);
366 method global_stmt
($/) {
369 $?BLOCK
.symbol
( $( $_ ).name
(), :scope
('package') );
372 make PAST
::Op
.new
( :inline
(' # global declaration'), :node
($/) );
375 method expression_list
($/) {
377 if (+$<expression
> == 1) {
378 $past := $( $<expression
>[0] );
381 $past := PAST
::Op
.new
( :name
('listmaker'), :node
($/) );
390 method identifier
($/) {
391 make PAST
::Var
.new
( :name
( ~$/ ),
397 method print_stmt
($/) {
398 my $past := PAST
::Op
.new
( :name
('printnl'), :node
($/) );
409 method expression
($/, $key) {
411 if $key eq 'lambda_form' {
412 make
$( $<lambda_form
> );
415 make
$( $<or_test
>[0] );
419 method test
($/, $key) {
424 my $count := +$<and_test
> - 1;
425 my $past := $( $<and_test
>[$count] );
427 $count := $count - 1;
428 my $past := PAST
::Op
.new
( $($<and_test
>[$count]),
435 method and_test
($/) {
436 my $count := +$<not_test
> - 1;
437 my $past := $( $<not_test
>[$count] );
439 $count := $count - 1;
440 my $past := PAST
::Op
.new
( $($<not_test
>[$count]),
442 :pasttype
('unless') );
448 method not_test
($/) {
449 my $past := $( $<in_test
> );
451 $past := PAST
::Op
.new
( $past, :pirop
('not'), :node
($/) );
458 make
$($<is_test
>[0]);
463 make
$($<comparison
>[0]);
466 method comparison
($/, $key) {
471 my $past := PAST
::Op
.new
( :name
($<type
>),
472 :pasttype
($<top
><pasttype
>),
473 :pirop
($<top
><pirop
>),
474 :lvalue
($<top
><lvalue
>),
484 method list_iter
($/, $key) {
488 method list_for
($/) {
497 my $past := $( $<atom
> );
498 ## $past is the first child of each <postop>, so unshift it
499 ## so it ends up at the front of the list.
502 $postop.unshift($past);
508 method postop
($/, $key) {
512 method call
($/, $key) {
515 if $<argument_list
> {
516 make
$( $<argument_list
>[0] );
519 make PAST
::Op
.new
( :pasttype
('call'), :node
($/) );
523 method subscription
($/) {
524 make PAST
::Var
.new
( $( $<tuple_or_scalar
> ), :scope
('keyed'));
527 method atom
($/, $key) {
531 method literal
($/, $key) {
536 make PAST
::Val
.new
( :value
( ~$/ ), :returns('Integer'), :node($/) );
539 method floatnumber
($/) {
540 make PAST
::Val
.new
( :value
( ~$/ ), :returns('Float'), :node($/) );
543 method stringliteral
($/, $key) {
547 method shortstring
($/) {
548 make PAST
::Val
.new
( :value
( ~$/[0] ), :node($/) );
551 method parenth_form
($/) {
552 if +$<tuple_or_scalar
> {
553 make
$( $<tuple_or_scalar
>[0] );
556 make PAST
::Op
.new
( :name
('tuplemaker'),
561 method assignment_stmt
($/) {
562 my $lhs := $( $<target_list
> );
563 my $explist := $( $<expression_list
> );
564 my $past := PAST
::Stmts
.new
( :node
($/) );
567 my $rhs := $explist.shift();
568 $past.push( PAST
::Op
.new
( $_, $rhs, :pasttype
('bind'), :node
($/) ) );
574 method target_list
($/) {
575 my $past := PAST
::VarList
.new
( :node
($/) );
582 method target
($/, $key) {
583 my $past := $( $/{$key} );
588 method list_literal
($/) {
589 my $past := PAST
::Op
.new
( :name
('listmaker'), :pasttype
('call'), :node
($/) );
596 method list_display
($/, $key) {
600 method dict_display
($/) {
601 if $<key_datum_list
> {
602 make
$( $<key_datum_list
>[0] );
605 ## if there's no list of key_datum items, have 'dictmaker' return an empty
607 make PAST
::Op
.new
( :name
('dictmaker'), :pasttype
('call'), :node
($/) );
611 method key_datum_list
($/) {
612 my $past := PAST
::Op
.new
( :name
('dictmaker'), :pasttype
('call'), :node
($/) );
614 $past.push( $( $_ ) );
619 method key_datum
($/) {
620 my $key := $( $<key
> );
621 my $value := $( $<value
> );
622 ## this only works if $key /has/ a name() method
623 ## XXX need for some generic solution for all PAST node types.
624 my $hashedkey := PAST
::Val
.new
( :value
($key.name
()) );
625 $value.named
($hashedkey);
629 method tuple_or_scalar
($/, $key) {
633 method tuple_constructor
($/) {
634 my $past := PAST
::Op
.new
( :name
('tuplemaker'), :pasttype
('call'), :node
($/) );