File Coverage

blib/lib/Language/P/Parser.pm
Criterion Covered Total %
statement 541 725 74.6
branch 274 436 62.8
condition 158 286 55.2
subroutine 56 63 88.8
pod 1 5 20.0
total 1030 1515 67.9


line stmt bran cond sub pod time code
1             package Language::P::Parser;
2              
3 86     86   2210711 use strict;
  86         1134  
  86         3674  
4 86     86   481 use warnings;
  86         179  
  86         3100  
5 86     86   555 use base qw(Class::Accessor::Fast);
  86         159  
  86         91328  
6              
7 86     86   382840 use Language::P::Lexer qw(:all);
  86         334  
  86         57002  
8 86     86   1251 use Language::P::ParseTree qw(:all);
  86         364  
  86         102595  
9 86     86   78873 use Language::P::Parser::Regex;
  86         288  
  86         811  
10 86     86   57343 use Language::P::Parser::Lexicals;
  86         281  
  86         697  
11 86     86   3137 use Language::P::Keywords;
  86         180  
  86         35962  
12              
13             __PACKAGE__->mk_ro_accessors( qw(lexer generator runtime) );
14             __PACKAGE__->mk_accessors( qw(_package _lexicals _pending_lexicals
15             _in_declaration _lexical_state
16             _options) );
17              
18 7     7   64 sub _lexical_sub_state { $_[0]->{_lexical_state}->[-1]->{sub} }
19              
20             use constant
21 86         1378942 { PREC_HIGHEST => 0,
22             PREC_NAMED_UNOP => 10,
23             PREC_TERNARY => 18,
24             PREC_TERNARY_COLON => 40,
25             PREC_LISTEXPR => 19,
26             PREC_COMMA => 20,
27             PREC_LISTOP => 21,
28             PREC_LOWEST => 50,
29              
30             BLOCK_OPEN_SCOPE => 1,
31             BLOCK_IMPLICIT_RETURN => 2,
32             BLOCK_BARE => 4,
33              
34             ASSOC_LEFT => 1,
35             ASSOC_RIGHT => 2,
36             ASSOC_NON => 3,
37 86     86   575 };
  86         188  
38              
39             my %token_to_sigil =
40             ( T_DOLLAR() => VALUE_SCALAR,
41             T_AT() => VALUE_ARRAY,
42             T_PERCENT() => VALUE_HASH,
43             T_STAR() => VALUE_GLOB,
44             T_AMPERSAND() => VALUE_SUB,
45             T_ARYLEN() => VALUE_ARRAY_LENGTH,
46             );
47              
48             my %declaration_to_flags =
49             ( OP_MY() => DECLARATION_MY,
50             OP_OUR() => DECLARATION_OUR,
51             OP_STATE() => DECLARATION_STATE,
52             );
53              
54             my %prec_assoc_bin =
55             ( # T_ARROW() => [ 2, ASSOC_LEFT ],
56             T_POWER() => [ 4, ASSOC_RIGHT, OP_POWER ],
57             T_MATCH() => [ 6, ASSOC_LEFT, OP_MATCH ],
58             T_NOTMATCH() => [ 6, ASSOC_LEFT, OP_NOT_MATCH ],
59             T_STAR() => [ 7, ASSOC_LEFT, OP_MULTIPLY ],
60             T_SLASH() => [ 7, ASSOC_LEFT, OP_DIVIDE ],
61             T_PERCENT() => [ 7, ASSOC_LEFT, OP_MODULUS ],
62             T_SSTAR() => [ 7, ASSOC_LEFT, OP_REPEAT ],
63             T_PLUS() => [ 8, ASSOC_LEFT, OP_ADD ],
64             T_MINUS() => [ 8, ASSOC_LEFT, OP_SUBTRACT ],
65             T_DOT() => [ 8, ASSOC_LEFT, OP_CONCATENATE ],
66             T_OPAN() => [ 11, ASSOC_NON, OP_NUM_LT ],
67             T_CLAN() => [ 11, ASSOC_NON, OP_NUM_GT ],
68             T_LESSEQUAL() => [ 11, ASSOC_NON, OP_NUM_LE ],
69             T_GREATEQUAL() => [ 11, ASSOC_NON, OP_NUM_GE ],
70             T_SLESS() => [ 11, ASSOC_NON, OP_STR_LT ],
71             T_SGREAT() => [ 11, ASSOC_NON, OP_STR_GT ],
72             T_SLESSEQUAL() => [ 11, ASSOC_NON, OP_STR_LE ],
73             T_SGREATEQUAL() => [ 11, ASSOC_NON, OP_STR_GE ],
74             T_EQUALEQUAL() => [ 12, ASSOC_NON, OP_NUM_EQ ],
75             T_NOTEQUAL() => [ 12, ASSOC_NON, OP_NUM_NE ],
76             T_CMP() => [ 12, ASSOC_NON, OP_NUM_CMP ],
77             T_SEQUALEQUAL() => [ 12, ASSOC_NON, OP_STR_EQ ],
78             T_SNOTEQUAL() => [ 12, ASSOC_NON, OP_STR_NE ],
79             T_SCMP() => [ 12, ASSOC_NON, OP_STR_CMP ],
80             T_AMPERSAND() => [ 13, ASSOC_LEFT, OP_BIT_AND ],
81             T_OR() => [ 14, ASSOC_LEFT, OP_BIT_OR ],
82             T_XOR() => [ 14, ASSOC_LEFT, OP_BIT_XOR ],
83             T_ANDAND() => [ 15, ASSOC_LEFT, OP_LOG_AND ],
84             T_OROR() => [ 16, ASSOC_LEFT, OP_LOG_OR ],
85             T_DOTDOT() => [ 17, ASSOC_NON, OP_DOT_DOT ],
86             T_DOTDOTDOT() => [ 17, ASSOC_NON, OP_DOT_DOT_DOT ],
87             T_INTERR() => [ 18, ASSOC_RIGHT ], # ternary
88             T_EQUAL() => [ 19, ASSOC_RIGHT, OP_ASSIGN ],
89             T_PLUSEQUAL() => [ 19, ASSOC_RIGHT, OP_ADD_ASSIGN ],
90             T_MINUSEQUAL() => [ 19, ASSOC_RIGHT, OP_SUBTRACT_ASSIGN ],
91             T_STAREQUAL() => [ 19, ASSOC_RIGHT, OP_MULTIPLY_ASSIGN ],
92             T_SLASHEQUAL() => [ 19, ASSOC_RIGHT, OP_DIVIDE_ASSIGN ],
93             T_COMMA() => [ 20, ASSOC_LEFT ],
94             # 21, list ops
95             T_ANDANDLOW() => [ 23, ASSOC_LEFT, OP_LOG_AND ],
96             T_ORORLOW() => [ 24, ASSOC_LEFT, OP_LOG_OR ],
97             T_XORLOW() => [ 24, ASSOC_LEFT, OP_LOG_XOR ],
98             T_COLON() => [ 40, ASSOC_RIGHT ], # ternary, must be lowest,
99             );
100              
101             my %prec_assoc_un =
102             ( T_PLUSPLUS() => [ 3, ASSOC_NON, OP_PREINC ],
103             T_MINUSMINUS() => [ 3, ASSOC_NON, OP_PREDEC ],
104             T_PLUS() => [ 5, ASSOC_RIGHT, OP_PLUS ],
105             T_MINUS() => [ 5, ASSOC_RIGHT, OP_MINUS ],
106             T_NOT() => [ 5, ASSOC_RIGHT, OP_LOG_NOT ],
107             T_TILDE() => [ 5, ASSOC_RIGHT, OP_BIT_NOT ],
108             T_BACKSLASH() => [ 5, ASSOC_RIGHT, OP_REFERENCE ],
109             T_NOTLOW() => [ 22, ASSOC_RIGHT, OP_LOG_NOT ],
110             );
111              
112             my %dereference_type =
113             ( VALUE_SCALAR() => OP_DEREFERENCE_SCALAR,
114             VALUE_ARRAY() => OP_DEREFERENCE_ARRAY,
115             VALUE_HASH() => OP_DEREFERENCE_HASH,
116             VALUE_SUB() => OP_DEREFERENCE_SUB,
117             VALUE_GLOB() => OP_DEREFERENCE_GLOB,
118             VALUE_ARRAY_LENGTH() => OP_ARRAY_LENGTH,
119             );
120              
121             sub new {
122 61     61 1 634 my( $class, $args ) = @_;
123 61         477 my $self = $class->SUPER::new( $args );
124              
125 61 50       826 $self->_options( {} ) unless $self->_options;
126              
127 61         1115 return $self;
128             }
129              
130             sub set_option {
131 0     0 0 0 my( $self, $option, $value ) = @_;
132              
133 0 0       0 if( $option eq 'dump-parse-tree' ) {
134 0         0 $self->_options->{$option} = 1;
135             }
136              
137 0         0 return 0;
138             }
139              
140             sub parse_string {
141 46     46 0 443 my( $self, $string, $package ) = @_;
142              
143 46     20   1734 open my $fh, '<', \$string;
  20         243  
  20         46  
  20         184  
144              
145 46         31021 $self->_package( $package );
146 46         613 $self->parse_stream( $fh, '' );
147             }
148              
149             sub parse_file {
150 15     15 0 210 my( $self, $file ) = @_;
151              
152 15 50       1188 open my $fh, '<', $file or die "open '$file': $!";
153              
154 15         107 $self->_package( 'main' );
155 15         156 $self->parse_stream( $fh, $file );
156             }
157              
158             sub parse_stream {
159 61     61 0 166 my( $self, $stream, $filename ) = @_;
160              
161 61         436 $self->{lexer} = Language::P::Lexer->new
162             ( { stream => $stream,
163             file => $filename,
164             symbol_table => $self->runtime->symbol_table,
165             } );
166 61         274 $self->{_lexical_state} = [];
167 61         545 $self->_parse;
168             }
169              
170             sub _qualify {
171 387     387   639 my( $self, $name, $type ) = @_;
172 387 50       1096 if( $type == T_FQ_ID ) {
173 0         0 ( my $normalized = $name ) =~ s/^(?:::)?(?:main::)?//;
174 0         0 return $normalized;
175             }
176 387 50       1095 my $prefix = $self->_package eq 'main' ? '' : $self->_package . '::';
177 387         5137 return $prefix . $name;
178             }
179              
180             sub _parse {
181 61     61   147 my( $self ) = @_;
182              
183 61         124 my $dumper;
184 61 50 33     251 if( $self->_options->{'dump-parse-tree'}
185             && -f $self->lexer->file ) {
186 0         0 require Language::P::ParseTree::DumpYAML;
187 0         0 ( my $outfile = $self->lexer->file ) =~ s/(\.\w+)?$/.pt/;
188 0   0     0 open my $out, '>', $outfile || die "Can't open '$outfile': $!";
189 0         0 my $dumpyml = Language::P::ParseTree::DumpYAML->new;
190             $dumper = sub {
191 0     0   0 print $out $dumpyml->dump( $_[0] );
192 0         0 };
193             }
194              
195 61         774 $self->_pending_lexicals( [] );
196 61         554 $self->_lexicals( undef );
197 61         582 $self->_enter_scope( 0, 1 ); # FIXME eval
198              
199 61         647 $self->generator->start_code_generation( { file_name => $self->lexer->file,
200             } );
201 61         1119 while( my $line = _parse_line( $self ) ) {
202 202 50       1218 $dumper->( $line ) if $dumper;
203 202         671 $self->generator->process( $line );
204             }
205 61         276 $self->_leave_scope;
206 61         1196 my $code = $self->generator->end_code_generation;
207              
208 61         610 return $code;
209             }
210              
211             sub _enter_scope {
212 172     172   319 my( $self, $is_sub, $top_level ) = @_;
213              
214 172         254 push @{$self->{_lexical_state}}, { package => $self->_package,
  172         822  
215             lexicals => $self->_lexicals,
216             is_sub => $is_sub,
217             top_level=> $top_level,
218             };
219 172 100 100     2850 if( $is_sub || $top_level ) {
  90 50       313  
220 82         528 $self->{_lexical_state}[-1]{sub} = { labels => {},
221             jumps => [],
222             };
223             } elsif( @{$self->{_lexical_state}} > 1 ) {
224 90         328 $self->{_lexical_state}[-1]{sub} = $self->{_lexical_state}[-2]{sub};
225             }
226 172   100     654 $self->_lexicals( Language::P::Parser::Lexicals->new
227             ( { outer => $self->_lexicals,
228             is_subroutine => $is_sub || 0,
229             top_level => $top_level,
230             } ) );
231             }
232              
233             sub _leave_scope {
234 172     172   306 my( $self ) = @_;
235              
236 172         247 my $state = pop @{$self->{_lexical_state}};
  172         441  
237 172         777 $self->_package( $state->{package} );
238 172         1235 $self->_lexicals( $state->{lexicals} );
239 172 100 100     2566 _patch_gotos( $self, $state ) if $state->{is_sub} || $state->{top_level};
240             }
241              
242             sub _patch_gotos {
243 82     82   1228 my( $self, $state ) = @_;
244 82         281 my $labels = $state->{sub}{labels};
245              
246 82         139 foreach my $goto ( @{$state->{sub}{jumps}} ) {
  82         437  
247 3 50       13 if( $labels->{$goto->left} ) {
248 3         28 $goto->set_attribute( 'target', $labels->{$goto->left}, 1 );
249             }
250             }
251             }
252              
253             sub _syntax_error {
254 0     0   0 my( $self, $token ) = @_;
255              
256 0         0 Carp::confess( sprintf "Unexpected token '%s' (%s) at %s:%d\n ",
257             $token->[O_VALUE], $token->[O_TYPE],
258             $token->[O_POS][0], $token->[O_POS][1] );
259             }
260              
261             sub _lex_token {
262 443     443   797 my( $self, $type, $value, $expect ) = @_;
263 443   100     1252 my $token = $self->lexer->lex( $expect || X_NOTHING );
264              
265 443 100 33     2789 return if !$value && !$type;
266              
267 433 50 33     2716 if( ( $type && $type != $token->[O_TYPE] )
      33        
      33        
268             || ( $value && $value eq $token->[O_VALUE] ) ) {
269 0         0 _syntax_error( $self, $token );
270             }
271              
272 433         954 return $token;
273             }
274              
275             sub _lex_semicolon {
276 339     339   484 my( $self ) = @_;
277 339         985 my $token = $self->lexer->lex;
278              
279 339 100 100     2920 if( $token->[O_TYPE] == T_EOF || $token->[O_TYPE] == T_SEMICOLON ) {
    50          
280 328         565 return;
281             } elsif( $token->[O_TYPE] == T_CLBRK ) {
282 11         40 $self->lexer->unlex( $token );
283 11         72 return;
284             }
285              
286 0         0 _syntax_error( $self, $token );
287             }
288              
289             my %special_sub = map { $_ => 1 }
290             ( qw(AUTOLOAD DESTROY BEGIN UNITCHECK CHECK INIT END) );
291              
292             sub _parse_line {
293 396     396   1105 my( $self ) = @_;
294 396         1159 my $label = $self->lexer->peek( X_STATE );
295              
296 396 100       1062 if( $label->[O_TYPE] != T_LABEL ) {
297 389         1088 return _parse_line_rest( $self, 1 );
298             } else {
299 7         46 _lex_token( $self, T_LABEL );
300 7   33     22 my $statement = _parse_line_rest( $self, 0 )
301             || Language::P::ParseTree::Empty->new;
302              
303 7         87 $statement->set_attribute( 'label', $label->[O_VALUE] );
304 7   66     31 $self->_lexical_sub_state->{labels}{$label->[O_VALUE]} ||= $statement;
305              
306 7         26 return $statement;
307             }
308             }
309              
310             sub _parse_line_rest {
311 396     396   611 my( $self, $no_empty ) = @_;
312 396         1262 my $token = $self->lexer->peek( X_STATE );
313 396         880 my $tokidt = $token->[O_ID_TYPE];
314              
315 396 50 100     3210 if( $token->[O_TYPE] == T_SEMICOLON ) {
    100          
    100          
    50          
316 0         0 _lex_semicolon( $self );
317              
318 0 0       0 return $no_empty ? _parse_line_rest( $self, 1 ) : undef;
319             } elsif( $token->[O_TYPE] == T_OPBRK ) {
320 7         31 _lex_token( $self, T_OPBRK );
321              
322 7         42 return _parse_block_rest( $self, BLOCK_OPEN_SCOPE|BLOCK_BARE );
323             } elsif( $token->[O_TYPE] == T_ID && is_keyword( $tokidt ) ) {
324 87 100 100     2021 if( $tokidt == KEY_SUB ) {
    100 100        
    100 100        
    100 66        
    50 66        
    50 66        
      100        
      100        
      100        
      66        
325 17         61 return _parse_sub( $self, 1 | 2 );
326             } elsif( $tokidt == KEY_IF || $tokidt == KEY_UNLESS ) {
327 10         40 return _parse_cond( $self );
328             } elsif( $tokidt == KEY_WHILE || $tokidt == KEY_UNTIL ) {
329 12         55 return _parse_while( $self );
330             } elsif( $tokidt == KEY_FOR || $tokidt == KEY_FOREACH ) {
331 11         43 return _parse_for( $self );
332             } elsif( $tokidt == KEY_PACKAGE ) {
333 0         0 _lex_token( $self, T_ID );
334 0         0 my $id = $self->lexer->lex_identifier( 0 );
335 0         0 _lex_semicolon( $self );
336              
337 0         0 $self->_package( $id->[O_VALUE] );
338              
339 0         0 return Language::P::ParseTree::Package->new
340             ( { name => $id->[O_VALUE],
341             } );
342             } elsif( $tokidt == OP_MY
343             || $tokidt == OP_OUR
344             || $tokidt == OP_STATE
345             || $tokidt == OP_GOTO
346             || $tokidt == OP_LAST
347             || $tokidt == OP_NEXT
348             || $tokidt == OP_REDO
349             || $tokidt == KEY_LOCAL ) {
350 37         127 return _parse_sideff( $self );
351             }
352             } elsif( $special_sub{$token->[O_VALUE]} ) {
353 0         0 return _parse_sub( $self, 1, 1 );
354             } else {
355 302         873 return _parse_sideff( $self );
356             }
357              
358 0         0 _syntax_error( $self, $token );
359             }
360              
361             sub _add_pending_lexicals {
362 380     380   575 my( $self ) = @_;
363              
364             # FIXME our() is different
365 380         492 foreach my $lexical ( @{$self->_pending_lexicals} ) {
  380         1293  
366 11         82 $self->_lexicals->add_lexical( $lexical );
367             }
368              
369 380         2895 $self->_pending_lexicals( [] );
370             }
371              
372             sub _parse_sub {
373 21     21   45 my( $self, $flags, $no_sub_token ) = @_;
374 21 100       93 _lex_token( $self, T_ID ) unless $no_sub_token;
375 21         76 my $name = $self->lexer->lex_alphabetic_identifier( 0 );
376 21 100       99 my $fqname = $name ? _qualify( $self, $name->[O_VALUE], $name->[O_ID_TYPE] ) : undef;
377              
378             # TODO prototypes
379 21 100       52 if( $fqname ) {
380 17 50       63 die "Syntax error: named sub '$fqname'" unless $flags & 1;
381              
382 17         56 my $next = $self->lexer->lex( X_OPERATOR );
383              
384 17 50       114 if( $next->[O_TYPE] == T_SEMICOLON ) {
    50          
385 0         0 $self->generator->add_declaration( $fqname );
386              
387 0         0 return Language::P::ParseTree::SubroutineDeclaration->new
388             ( { name => $fqname,
389             } );
390             } elsif( $next->[O_TYPE] != T_OPBRK ) {
391 0         0 _syntax_error( $self, $next );
392             }
393             } else {
394 4         12 _lex_token( $self, T_OPBRK );
395 4 50       15 die 'Syntax error: anonymous sub' unless $flags & 2;
396             }
397              
398 21         71 $self->_enter_scope( 1 );
399 21 100       366 my $sub = $fqname ? Language::P::ParseTree::NamedSubroutine->new
400             ( { name => $fqname,
401             } ) :
402             Language::P::ParseTree::AnonymousSubroutine->new;
403             # add @_ to lexical scope
404 21         89 $self->_lexicals->add_name( VALUE_ARRAY, '_' );
405              
406 21         320 my $block = _parse_block_rest( $self, BLOCK_IMPLICIT_RETURN );
407 21         86 $sub->{lines} = $block->{lines}; # FIXME encapsulation
408 21         80 $sub->set_parent_for_all_childs;
409 21         90 $self->_leave_scope;
410              
411             # add a subroutine declaration, the generator might
412             # not create it until later
413 21 100       90 if( $fqname ) {
414 17         65 $self->generator->add_declaration( $fqname );
415             }
416              
417 21         300 return $sub;
418             }
419              
420             sub _parse_cond {
421 10     10   17 my( $self ) = @_;
422 10         49 my $cond = _lex_token( $self, T_ID );
423              
424 10         22 _lex_token( $self, T_OPPAR );
425              
426 10         29 $self->_enter_scope;
427 10         78 my $expr = _parse_expr( $self );
428 10         46 $self->_add_pending_lexicals;
429              
430 10         69 _lex_token( $self, T_CLPAR );
431 10         28 _lex_token( $self, T_OPBRK, undef, X_BLOCK );
432              
433 10         50 my $block = _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
434              
435 10         124 my $if = Language::P::ParseTree::Conditional->new
436             ( { iftrues => [ Language::P::ParseTree::ConditionalBlock->new
437             ( { block_type => $cond->[O_VALUE],
438             condition => $expr,
439             block => $block,
440             } )
441             ],
442             } );
443              
444 10         35 for(;;) {
445 20         68 my $else = $self->lexer->peek( X_STATE );
446 20 100 100     128 last if $else->[O_TYPE] != T_ID
      66        
447             || ( $else->[O_ID_TYPE] != KEY_ELSE && $else->[O_ID_TYPE] != KEY_ELSIF );
448 10         37 _lex_token( $self );
449              
450 10         16 my $expr;
451 10 100       32 if( $else->[O_ID_TYPE] == KEY_ELSIF ) {
452 4         12 _lex_token( $self, T_OPPAR );
453 4         16 $expr = _parse_expr( $self );
454 4         11 _lex_token( $self, T_CLPAR );
455             }
456 10         23 _lex_token( $self, T_OPBRK, undef, X_BLOCK );
457 10         24 my $block = _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
458              
459 10 100       37 if( $expr ) {
460 4         8 push @{$if->iftrues}, Language::P::ParseTree::ConditionalBlock->new
  4         18  
461             ( { block_type => 'if',
462             condition => $expr,
463             block => $block,
464             } )
465             } else {
466             # FIXME encapsulation
467 6         44 $if->{iffalse} = Language::P::ParseTree::ConditionalBlock->new
468             ( { block_type => 'else',
469             condition => undef,
470             block => $block,
471             } );
472             }
473             }
474              
475 10         39 $if->set_parent_for_all_childs;
476 10         38 $self->_leave_scope;
477              
478 10         70 return $if;
479             }
480              
481             sub _parse_for {
482 11     11   24 my( $self ) = @_;
483 11         44 my $keyword = _lex_token( $self, T_ID );
484 11         44 my $token = $self->lexer->lex( X_OPERATOR );
485 11         44 my( $foreach_var, $foreach_expr );
486              
487 11         39 $self->_enter_scope;
488              
489 11 100 33     158 if( $token->[O_TYPE] == T_OPPAR ) {
    100 66        
    50          
490 4         27 my $expr = _parse_expr( $self );
491 4         36 my $sep = $self->lexer->lex( X_OPERATOR );
492              
493 4 50       150 if( $sep->[O_TYPE] == T_CLPAR ) {
    50          
494 0         0 $foreach_var = _find_symbol( $self, VALUE_SCALAR, '_', T_FQ_ID );
495 0         0 $foreach_expr = $expr;
496             } elsif( $sep->[O_TYPE] == T_SEMICOLON ) {
497             # C-style for
498 4         19 $self->_add_pending_lexicals;
499              
500 4         26 my $cond = _parse_expr( $self );
501 4         16 _lex_token( $self, T_SEMICOLON );
502 4         15 $self->_add_pending_lexicals;
503              
504 4         29 my $incr = _parse_expr( $self );
505 4         12 _lex_token( $self, T_CLPAR );
506 4         14 $self->_add_pending_lexicals;
507              
508 4         29 _lex_token( $self, T_OPBRK, undef, X_BLOCK );
509 4         17 my $block = _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
510              
511 4         95 my $for = Language::P::ParseTree::For->new
512             ( { block_type => 'for',
513             initializer => $expr,
514             condition => $cond,
515             step => $incr,
516             block => $block,
517             } );
518              
519 4         21 $self->_leave_scope;
520              
521 4         39 return $for;
522             } else {
523 0         0 _syntax_error( $self, $sep );
524             }
525             } elsif( $token->[O_TYPE] == T_ID && ( $token->[O_ID_TYPE] == OP_MY
526             || $token->[O_ID_TYPE] == OP_OUR
527             || $token->[O_ID_TYPE] == OP_STATE ) ) {
528 3         14 _lex_token( $self, T_DOLLAR );
529 3         30 my $name = $self->lexer->lex_identifier( 0 );
530 3 50       25 die "No name" unless $name;
531              
532             # FIXME our() variable refers to package it was declared in
533 3         31 $foreach_var = Language::P::ParseTree::Symbol->new
534             ( { name => $name->[O_VALUE],
535             sigil => VALUE_SCALAR,
536             } );
537 3         23 $foreach_var = _process_declaration( $self, $foreach_var,
538             $token->[O_ID_TYPE] );
539             } elsif( $token->[O_TYPE] == T_DOLLAR ) {
540 4         19 my $id = $self->lexer->lex_identifier( 0 );
541 4         25 $foreach_var = _find_symbol( $self, VALUE_SCALAR, $id->[O_VALUE], $id->[O_ID_TYPE] );
542             } else {
543 0         0 _syntax_error( $self, $token );
544             }
545              
546             # if we get there it is not C-style for
547 7 50       62 if( !$foreach_expr ) {
548 7         28 _lex_token( $self, T_OPPAR );
549 7         24 $foreach_expr = _parse_expr( $self );
550 7         20 _lex_token( $self, T_CLPAR );
551             }
552              
553 7         31 $self->_add_pending_lexicals;
554 7         52 _lex_token( $self, T_OPBRK, undef, X_BLOCK );
555              
556 7         34 my $block = _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
557 7         33 my $continue = _parse_continue( $self );
558 7         107 my $for = Language::P::ParseTree::Foreach->new
559             ( { expression => $foreach_expr,
560             block => $block,
561             variable => $foreach_var,
562             continue => $continue,
563             } );
564              
565 7         38 $self->_leave_scope;
566              
567 7         52 return $for;
568             }
569              
570             sub _parse_while {
571 12     12   23 my( $self ) = @_;
572 12         175 my $keyword = _lex_token( $self, T_ID );
573              
574 12         34 _lex_token( $self, T_OPPAR );
575              
576 12         43 $self->_enter_scope;
577 12         105 my $expr = _parse_expr( $self );
578 12         42 $self->_add_pending_lexicals;
579              
580 12         80 _lex_token( $self, T_CLPAR );
581 12         87 _lex_token( $self, T_OPBRK, undef, X_BLOCK );
582              
583 12         40 my $block = _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
584 12         53 my $continue = _parse_continue( $self );
585 12         163 my $while = Language::P::ParseTree::ConditionalLoop
586             ->new( { condition => $expr,
587             block => $block,
588             block_type => $keyword->[O_VALUE],
589             continue => $continue,
590             } );
591              
592 12         52 $self->_leave_scope;
593              
594 12         82 return $while;
595             }
596              
597             sub _parse_continue {
598 26     26   56 my( $self ) = @_;
599 26         134 my $token = $self->lexer->peek( X_STATE );
600 26 100 100     223 return unless $token->[O_TYPE] == T_ID && $token->[O_ID_TYPE] == KEY_CONTINUE;
601              
602 7         72 _lex_token( $self, T_ID );
603 7         34 _lex_token( $self, T_OPBRK, undef, X_BLOCK );
604              
605 7         23 return _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
606             }
607              
608             sub _parse_sideff {
609 339     339   542 my( $self ) = @_;
610 339         790 my $expr = _parse_expr( $self );
611 339         1124 my $keyword = $self->lexer->peek( X_TERM );
612              
613 339 100 66     1687 if( $keyword->[O_TYPE] == T_ID && is_keyword( $keyword->[O_ID_TYPE] ) ) {
614 10         20 my $keyidt = $keyword->[O_ID_TYPE];
615              
616 10 50 33     44 if( $keyidt == KEY_IF || $keyidt == KEY_UNLESS ) {
    0 0        
    0 0        
617 10         27 _lex_token( $self, T_ID );
618 10         21 my $cond = _parse_expr( $self );
619              
620 10         167 $expr = Language::P::ParseTree::Conditional->new
621             ( { iftrues => [ Language::P::ParseTree::ConditionalBlock->new
622             ( { block_type => $keyword->[O_VALUE],
623             condition => $cond,
624             block => $expr,
625             } )
626             ],
627             } );
628             } elsif( $keyidt == KEY_WHILE || $keyidt == KEY_UNTIL ) {
629 0         0 _lex_token( $self, T_ID );
630 0         0 my $cond = _parse_expr( $self );
631              
632 0         0 $expr = Language::P::ParseTree::ConditionalLoop->new
633             ( { condition => $cond,
634             block => $expr,
635             block_type => $keyword->[O_VALUE],
636             } );
637             } elsif( $keyidt == KEY_FOR || $keyidt == KEY_FOREACH ) {
638 0         0 _lex_token( $self, T_ID );
639 0         0 my $cond = _parse_expr( $self );
640              
641 0         0 $expr = Language::P::ParseTree::Foreach->new
642             ( { expression => $cond,
643             block => $expr,
644             variable => _find_symbol( $self, VALUE_SCALAR, '_', T_FQ_ID ),
645             } );
646             }
647             }
648              
649 339         998 _lex_semicolon( $self );
650 339         903 $self->_add_pending_lexicals;
651              
652 339         3494 return $expr;
653             }
654              
655             sub _parse_expr {
656 415     415   560 my( $self ) = @_;
657              
658 415         1108 return _parse_term( $self, PREC_LOWEST );
659             }
660              
661             sub _find_symbol {
662 321     321   1226 my( $self, $sigil, $name, $type ) = @_;
663              
664 321 100       1054 if( $self->_in_declaration ) {
    50          
665 8         115 return Language::P::ParseTree::Symbol->new
666             ( { name => $name,
667             sigil => $sigil,
668             } );
669             } elsif( $type == T_FQ_ID ) {
670 0         0 return Language::P::ParseTree::Symbol->new
671             ( { name => _qualify( $self, $name, $type ),
672             sigil => $sigil,
673             } );
674             }
675              
676 313         2776 my( $level, $lex ) = $self->_lexicals->find_name( $sigil . "\0" . $name );
677              
678 313 100       1120 if( $lex ) {
679 22 100       77 $lex->set_closed_over if $level > 0;
680              
681 22         246 return Language::P::ParseTree::LexicalSymbol->new
682             ( { declaration => $lex,
683             level => $level,
684             } );
685             }
686              
687 291         808 return Language::P::ParseTree::Symbol->new
688             ( { name => _qualify( $self, $name, $type ),
689             sigil => $sigil,
690             } );
691             }
692              
693             sub _parse_maybe_subscript_rest {
694 658     658   950 my( $self, $subscripted, $arrow_only ) = @_;
695 658         1923 my $next = $self->lexer->peek( X_OPERATOR );
696              
697             # array/hash element
698 658 100 33     2286 if( $next->[O_TYPE] == T_ARROW ) {
    100 33        
    50          
699 8         20 _lex_token( $self, T_ARROW );
700 8         25 my $bracket = $self->lexer->peek( X_OPERATOR );
701              
702 8 50 33     39 if( $bracket->[O_TYPE] == T_OPPAR
      33        
703             || $bracket->[O_TYPE] == T_OPSQ
704             || $bracket->[O_TYPE] == T_OPBRK ) {
705 8         57 return _parse_dereference_rest( $self, $subscripted, $bracket );
706             } else {
707 0         0 return _parse_maybe_direct_method_call( $self, $subscripted );
708             }
709             } elsif( $arrow_only ) {
710 638         1731 return $subscripted;
711             } elsif( $next->[O_TYPE] == T_OPPAR
712             || $next->[O_TYPE] == T_OPSQ
713             || $next->[O_TYPE] == T_OPBRK ) {
714 0         0 return _parse_dereference_rest( $self, $subscripted, $next );
715             } else {
716 12         73 return $subscripted;
717             }
718             }
719              
720             sub _parse_indirect_function_call {
721 8     8   17 my( $self, $subscripted, $with_arguments, $ampersand ) = @_;
722              
723 8         9 my $args;
724 8 50       16 if( $with_arguments ) {
725 8         16 _lex_token( $self, T_OPPAR );
726 8         16 ( $args, undef ) = _parse_arglist( $self, PREC_LOWEST, 0, 0 );
727 8         21 _lex_token( $self, T_CLPAR );
728             }
729              
730             # $foo->() requires an additional dereference, while
731             # &{...}(...) does not construct a reference but might need it
732 8 50 66     42 if( !$subscripted->is_symbol || $subscripted->sigil != VALUE_SUB ) {
733 8         84 $subscripted = Language::P::ParseTree::Dereference->new
734             ( { left => $subscripted,
735             op => OP_DEREFERENCE_SUB,
736             } );
737             }
738              
739             # treat &foo; separately from all other cases
740 8 50 33     40 if( $ampersand && !$with_arguments ) {
741 0         0 return Language::P::ParseTree::SpecialFunctionCall->new
742             ( { function => $subscripted,
743             flags => FLAG_IMPLICITARGUMENTS,
744             } );
745             } else {
746 8         47 return Language::P::ParseTree::FunctionCall->new
747             ( { function => $subscripted,
748             arguments => $args,
749             } );
750             }
751             }
752              
753             sub _parse_dereference_rest {
754 8     8   13 my( $self, $subscripted, $bracket ) = @_;
755 8         11 my $term;
756              
757 8 50       21 if( $bracket->[O_TYPE] == T_OPPAR ) {
758 8         21 $term = _parse_indirect_function_call( $self, $subscripted, 1, 0 );
759             } else {
760 0         0 my $subscript = _parse_bracketed_expr( $self, $bracket->[O_TYPE], 0 );
761 0 0       0 $term = Language::P::ParseTree::Subscript->new
762             ( { subscripted => $subscripted,
763             subscript => $subscript,
764             type => $bracket->[O_TYPE] == T_OPBRK ?
765             VALUE_HASH : VALUE_ARRAY,
766             reference => 1,
767             } );
768             }
769              
770 8         28 return _parse_maybe_subscript_rest( $self, $term );
771             }
772              
773             sub _parse_bracketed_expr {
774 6     6   13 my( $self, $bracket, $allow_empty, $no_consume_opening ) = @_;
775 6 50       97 my $close = $bracket == T_OPBRK ? T_CLBRK :
    50          
776             $bracket == T_OPSQ ? T_CLSQ :
777             T_CLPAR;
778              
779 6 50       25 _lex_token( $self, $bracket ) unless $no_consume_opening;
780 6 50       22 if( $allow_empty ) {
781 0         0 my $next = $self->lexer->peek( X_TERM );
782 0 0       0 if( $next->[O_TYPE] == $close ) {
783 0         0 _lex_token( $self, $close );
784 0         0 return undef;
785             }
786             }
787 6         23 my $subscript = _parse_expr( $self );
788 6         26 _lex_token( $self, $close );
789              
790 6         19 return $subscript;
791             }
792              
793             sub _parse_maybe_indirect_method_call {
794 0     0   0 my( $self, $op, $next ) = @_;
795 0         0 my $indir = _parse_indirobj( $self, 1 );
796              
797 0 0       0 if( $indir ) {
798             # if FH -> no method
799             # proto FH -> no method
800             # Foo $bar (?) -> no method
801             # foo $bar -> method
802              
803             # print xxx -> no method, but print is handled before getting
804             # there, since it is a non-overridable builtin
805              
806             # foo pack:: -> method
807              
808             # use Data::Dumper;
809             # print Dumper( $indir ) . ' ' . Dumper( $next );
810              
811 0         0 my $args = _parse_term( $self, PREC_COMMA );
812 0 0       0 if( $args ) {
813 0 0       0 if( $args->isa( 'Language::P::ParseTree::List' ) ) {
814 0 0       0 $args = @{$args->expressions} ? $args->expressions : undef;
  0         0  
815             } else {
816 0         0 $args = [ $args ];
817             }
818             }
819 0 0       0 $indir = Language::P::ParseTree::Constant->new
820             ( { flags => CONST_STRING,
821             value => $indir->[O_VALUE],
822             } )
823             if ref( $indir ) eq 'ARRAY';
824 0         0 my $term = Language::P::ParseTree::MethodCall->new
825             ( { invocant => $indir,
826             method => $op->[O_VALUE],
827             arguments => $args,
828             indirect => 0,
829             } );
830              
831 0         0 return _parse_maybe_subscript_rest( $self, $term );
832             }
833              
834 0         0 return Language::P::ParseTree::Constant->new
835             ( { value => $op->[O_VALUE],
836             flags => CONST_STRING|STRING_BARE
837             } );
838             }
839              
840             sub _parse_maybe_direct_method_call {
841 0     0   0 my( $self, $invocant ) = @_;
842 0         0 my $token = $self->lexer->lex( X_TERM );
843 0         0 my( $method, $indirect );
844              
845 0 0       0 if( $token->[O_TYPE] == T_ID ) {
    0          
846 0         0 ( $method, $indirect ) = ( $token->[O_VALUE], 0 );
847             } elsif( $token->[O_TYPE] == T_DOLLAR ) {
848 0         0 my $id = $self->lexer->lex_identifier( 0 );
849 0         0 $method = _find_symbol( $self, VALUE_SCALAR, $id->[O_VALUE], $id->[O_ID_TYPE] );
850 0         0 $indirect = 1;
851             } else {
852 0         0 _syntax_error( $self, $token );
853             }
854              
855 0         0 my $oppar = $self->lexer->peek( X_OPERATOR );
856 0         0 my $args;
857 0 0       0 if( $oppar->[O_TYPE] == T_OPPAR ) {
858 0         0 _lex_token( $self, T_OPPAR );
859 0         0 ( $args ) = _parse_arglist( $self, PREC_LOWEST, 0, 0 );
860 0         0 _lex_token( $self, T_CLPAR );
861             }
862              
863 0         0 my $term = Language::P::ParseTree::MethodCall->new
864             ( { invocant => $invocant,
865             method => $method,
866             arguments => $args,
867             indirect => $indirect,
868             } );
869              
870 0         0 return _parse_maybe_subscript_rest( $self, $term );
871             }
872              
873             sub _parse_match {
874 0     0   0 my( $self, $token ) = @_;
875              
876 0 0       0 if( $token->[O_RX_INTERPOLATED] ) {
877 0         0 my $string = _parse_string_rest( $self, $token, 1 );
878 0         0 my $match = Language::P::ParseTree::InterpolatedPattern->new
879             ( { string => $string,
880             op => $token->[O_VALUE],
881             flags => $token->[O_RX_FLAGS],
882             } );
883              
884 0         0 return $match;
885             } else {
886 0         0 my $parts = Language::P::Parser::Regex->new
887             ( { generator => $self->generator,
888             runtime => $self->runtime,
889             interpolate => $token->[O_QS_INTERPOLATE],
890             } )->parse_string( $token->[O_QS_BUFFER] );
891 0         0 my $match = Language::P::ParseTree::Pattern->new
892             ( { components => $parts,
893             op => $token->[O_VALUE],
894             flags => $token->[O_RX_FLAGS],
895             } );
896              
897 0         0 return $match;
898             }
899             }
900              
901             sub _parse_substitution {
902 0     0   0 my( $self, $token ) = @_;
903 0         0 my $match = _parse_match( $self, $token );
904              
905 0         0 my $replace;
906 0 0       0 if( $match->flags & FLAG_RX_EVAL ) {
907 0         0 local $self->{lexer} = Language::P::Lexer->new
908             ( { string => $token->[O_RX_SECOND_HALF]->[O_QS_BUFFER],
909             symbol_table => $self->runtime->symbol_table,
910             _heredoc_lexer => $self->lexer,
911             } );
912 0         0 $replace = _parse_block_rest( $self, BLOCK_OPEN_SCOPE, T_EOF );
913             } else {
914 0         0 $replace = _parse_string_rest( $self, $token->[O_RX_SECOND_HALF], 0 );
915             }
916              
917 0         0 my $sub = Language::P::ParseTree::Substitution->new
918             ( { pattern => $match,
919             replacement => $replace,
920             } );
921              
922 0         0 return $sub;
923             }
924              
925             sub _parse_string_rest {
926 171     171   243 my( $self, $token, $pattern ) = @_;
927 171         211 my @values;
928 171         755 local $self->{lexer} = Language::P::Lexer->new
929             ( { string => $token->[O_QS_BUFFER],
930             symbol_table => $self->runtime->symbol_table,
931             } );
932              
933 171         724 $self->lexer->quote( { interpolate => $token->[O_QS_INTERPOLATE],
934             pattern => 0,
935             interpolated_pattern => $pattern,
936             } );
937 171         1989 for(;;) {
938 392         1076 my $value = $self->lexer->lex_quote;
939              
940 392 100 33     2198 if( $value->[O_TYPE] == T_STRING ) {
    100          
    50          
941 192         1707 push @values, Language::P::ParseTree::Constant->new
942             ( { flags => CONST_STRING,
943             value => $value->[O_VALUE],
944             } );
945             } elsif( $value->[O_TYPE] == T_EOF ) {
946 171         380 last;
947             } elsif( $value->[O_TYPE] == T_DOLLAR || $value->[O_TYPE] == T_AT ) {
948 29         85 push @values, _parse_indirobj_maybe_subscripts( $self, $value );
949             } else {
950 0         0 _syntax_error( $self, $value );
951             }
952             }
953              
954 171         496 $self->lexer->quote( undef );
955              
956 171         1411 my $string;
957 171 100 66     889 if( @values == 1 && $values[0]->is_constant ) {
    100          
958 144         228 $string = $values[0];
959             } elsif( @values == 0 ) {
960 2         23 $string = Language::P::ParseTree::Constant->new
961             ( { value => "",
962             flags => CONST_STRING,
963             } );
964             } else {
965 25         207 $string = Language::P::ParseTree::QuotedString->new
966             ( { components => \@values,
967             } );
968             }
969              
970 171         424 my $quote = $token->[O_VALUE];
971 171 50       574 if( $quote == OP_QL_QX ) {
    50          
972 0         0 $string = Language::P::ParseTree::UnOp->new
973             ( { op => OP_BACKTICK,
974             left => $string,
975             } );
976             } elsif( $quote == OP_QL_QW ) {
977 0         0 my @words = map Language::P::ParseTree::Constant->new
978             ( { value => $_,
979             flags => CONST_STRING,
980             } ),
981             split /[\s\r\n]+/, $string->value;
982              
983 0         0 $string = Language::P::ParseTree::List->new
984             ( { expressions => \@words,
985             } );
986             }
987              
988 171         1219 return $string;
989             }
990              
991             sub _parse_term_terminal {
992 1048     1048   1471 my( $self, $token, $is_bind ) = @_;
993              
994 1048 100 100     12459 if( $token->[O_TYPE] == T_QUOTE ) {
    50 66        
    100 66        
    50 33        
    50 66        
    100          
    100          
    50          
    50          
995 171         530 my $qstring = _parse_string_rest( $self, $token, 0 );
996              
997 171 50       540 if( $token->[O_VALUE] == OP_QL_LT ) {
998             # simple scalar: readline, anything else: glob
999 0 0 0     0 if( $qstring->isa( 'Language::P::ParseTree::QuotedString' )
  0 0 0     0  
1000             && $#{$qstring->components} == 0
1001             && $qstring->components->[0]->is_symbol ) {
1002 0         0 return Language::P::ParseTree::Overridable
1003             ->new( { function => OP_READLINE,
1004             arguments => [ $qstring->components->[0] ] } );
1005             } elsif( $qstring->is_constant ) {
1006 0 0       0 if( $qstring->value =~ /^[a-zA-Z_]/ ) {
1007             # FIXME simpler method, make lex_identifier static
1008 0         0 my $lexer = Language::P::Lexer->new
1009             ( { string => $qstring->value } );
1010 0         0 my $id = $lexer->lex_identifier( 0 );
1011              
1012 0 0 0     0 if( $id && !length( ${$lexer->buffer} ) ) {
  0         0  
1013 0         0 my $glob = Language::P::ParseTree::Symbol->new
1014             ( { name => _qualify( $self, $id->[O_VALUE], $id->[O_ID_TYPE] ),
1015             sigil => VALUE_GLOB,
1016             } );
1017 0         0 return Language::P::ParseTree::Overridable
1018             ->new( { function => OP_READLINE,
1019             arguments => [ $glob ],
1020             } );
1021             }
1022             }
1023 0         0 return Language::P::ParseTree::Glob
1024             ->new( { arguments => [ $qstring ] } );
1025             } else {
1026 0         0 return Language::P::ParseTree::Glob
1027             ->new( { arguments => [ $qstring ] } );
1028             }
1029             }
1030              
1031 171         393 return $qstring;
1032             } elsif( $token->[O_TYPE] == T_PATTERN ) {
1033 0         0 my $pattern;
1034 0 0 0     0 if( $token->[O_VALUE] == OP_QL_M || $token->[O_VALUE] == OP_QL_QR ) {
    0          
1035 0         0 $pattern = _parse_match( $self, $token );
1036             } elsif( $token->[O_VALUE] == OP_QL_S ) {
1037 0         0 $pattern = _parse_substitution( $self, $token );
1038             } else {
1039 0         0 die;
1040             }
1041              
1042 0 0 0     0 if( !$is_bind && $token->[O_VALUE] != OP_QL_QR ) {
1043 0         0 $pattern = Language::P::ParseTree::BinOp->new
1044             ( { op => OP_MATCH,
1045             left => _find_symbol( $self, VALUE_SCALAR, '_', T_FQ_ID ),
1046             right => $pattern,
1047             } );
1048             }
1049              
1050 0         0 return $pattern;
1051             } elsif( $token->[O_TYPE] == T_NUMBER ) {
1052 244         1868 return Language::P::ParseTree::Constant->new
1053             ( { value => $token->[O_VALUE],
1054             flags => $token->[O_NUM_FLAGS]|CONST_NUMBER,
1055             } );
1056             } elsif( $token->[O_TYPE] == T_PACKAGE ) {
1057 0         0 return Language::P::ParseTree::Constant->new
1058             ( { value => $self->_package,
1059             flags => CONST_STRING,
1060             } );
1061             } elsif( $token->[O_TYPE] == T_STRING ) {
1062 0         0 return Language::P::ParseTree::Constant->new
1063             ( { value => $token->[O_VALUE],
1064             flags => CONST_STRING,
1065             } );
1066             } elsif( $token->[O_TYPE] == T_DOLLAR
1067             || $token->[O_TYPE] == T_AT
1068             || $token->[O_TYPE] == T_PERCENT
1069             || $token->[O_TYPE] == T_STAR
1070             || $token->[O_TYPE] == T_AMPERSAND
1071             || $token->[O_TYPE] == T_ARYLEN ) {
1072 288         756 return ( _parse_indirobj_maybe_subscripts( $self, $token ), 1 );
1073             } elsif( $token->[O_TYPE] == T_ID ) {
1074 230         366 my $tokidt = $token->[O_ID_TYPE];
1075              
1076 230 100 66     656 if( !is_keyword( $token->[O_ID_TYPE] ) ) {
    100 66        
    100 100        
    100 100        
    100 100        
1077 183         593 return _parse_listop( $self, $token );
1078             } elsif( $tokidt == OP_MY
1079             || $tokidt == OP_OUR
1080             || $tokidt == OP_STATE ) {
1081 8         30 return _parse_lexical( $self, $token->[O_ID_TYPE] );
1082             } elsif( $tokidt == KEY_SUB ) {
1083 4         36 return _parse_sub( $self, 2, 1 );
1084             } elsif( $tokidt == OP_GOTO
1085             || $tokidt == OP_LAST
1086             || $tokidt == OP_NEXT
1087             || $tokidt == OP_REDO ) {
1088 15         53 my $id = $self->lexer->lex;
1089 15         36 my $dest;
1090 15 100 100     99 if( $id->[O_TYPE] == T_ID && $id->[O_ID_TYPE] == T_ID ) {
1091 6         15 $dest = $id->[O_VALUE];
1092             } else {
1093 9         31 $self->lexer->unlex( $id );
1094 9         67 $dest = _parse_term( $self, PREC_LOWEST );
1095 9 50       25 if( $dest ) {
1096 0 0       0 $dest = $dest->left
1097             if $dest->isa( 'Language::P::ParseTree::Parentheses' );
1098 0 0       0 $dest = $dest->value if $dest->is_constant;
1099             }
1100             }
1101              
1102 15         183 my $jump = Language::P::ParseTree::Jump->new
1103             ( { op => $tokidt,
1104             left => $dest,
1105             } );
1106 15 100 66     90 push @{$self->_lexical_state->[-1]{sub}{jumps}}, $jump
  3         17  
1107             if $tokidt == OP_GOTO && !ref( $dest );
1108              
1109 15         70 return $jump;
1110             } elsif( $tokidt == KEY_LOCAL ) {
1111 14         65 return Language::P::ParseTree::Local->new
1112             ( { left => _parse_term_list_if_parens( $self, PREC_NAMED_UNOP ),
1113             } );
1114             }
1115             } elsif( $token->[O_TYPE] == T_OPHASH ) {
1116 0         0 my $expr = _parse_bracketed_expr( $self, T_OPBRK, 1, 1 );
1117              
1118 0         0 return Language::P::ParseTree::ReferenceConstructor->new
1119             ( { expression => $expr,
1120             type => VALUE_HASH,
1121             } );
1122             } elsif( $token->[O_TYPE] == T_OPSQ ) {
1123 0         0 my $expr = _parse_bracketed_expr( $self, T_OPSQ, 1, 1 );
1124              
1125 0         0 return Language::P::ParseTree::ReferenceConstructor->new
1126             ( { expression => $expr,
1127             type => VALUE_ARRAY,
1128             } );
1129             }
1130              
1131 121         309 return undef;
1132             }
1133              
1134             sub _parse_term_terminal_maybe_subscripts {
1135 1048     1048   1417 my( $self, $token, $is_bind ) = @_;
1136 1048         3057 my( $term, $no_subscr ) = _parse_term_terminal( $self, $token, $is_bind );
1137              
1138 1048 100 100     5697 return $term if $no_subscr || !$term;
1139 639         1488 return _parse_maybe_subscript_rest( $self, $term, 1 );
1140             }
1141              
1142             sub _parse_indirobj_maybe_subscripts {
1143 317     317   477 my( $self, $token ) = @_;
1144 317         779 my $indir = _parse_indirobj( $self, 0 );
1145 317         1036 my $sigil = $token_to_sigil{$token->[O_TYPE]};
1146 317   33     2112 my $is_id = ref( $indir ) eq 'ARRAY' && $indir->[O_TYPE] == T_ID;
1147              
1148             # no subscripting/slicing possible for '%'
1149 317 50       755 if( $sigil == VALUE_HASH ) {
1150 0 0       0 return $is_id ? _find_symbol( $self, $sigil, $indir->[O_VALUE], $indir->[O_ID_TYPE] ) :
1151             Language::P::ParseTree::Dereference->new
1152             ( { left => $indir,
1153             op => OP_DEREFERENCE_HASH,
1154             } );
1155             }
1156              
1157 317         978 my $next = $self->lexer->peek( X_OPERATOR );
1158              
1159 317 50       860 if( $sigil == VALUE_SUB ) {
1160 0 0       0 my $deref = $is_id ? _find_symbol( $self, $sigil, $indir->[O_VALUE], $indir->[O_ID_TYPE] ) :
1161             $indir;
1162              
1163 0         0 return _parse_indirect_function_call( $self, $deref,
1164             $next->[O_TYPE] == T_OPPAR, 1 );
1165             }
1166              
1167             # simplify the code below by resolving the symbol here, so a
1168             # dereference will be constructed below (probably an unary
1169             # operator would be more consistent)
1170 317 100 66     980 if( $sigil == VALUE_ARRAY_LENGTH && $is_id ) {
1171 1         21 $indir = _find_symbol( $self, VALUE_ARRAY, $indir->[O_VALUE], $indir->[O_ID_TYPE] );
1172 1         5 $is_id = 0;
1173             }
1174              
1175 317 100       859 if( $next->[O_TYPE] == T_ARROW ) {
1176 5 50       24 my $deref = $is_id ? _find_symbol( $self, $sigil, $indir->[O_VALUE], $indir->[O_ID_TYPE] ) :
1177             Language::P::ParseTree::Dereference->new
1178             ( { left => $indir,
1179             op => $dereference_type{$sigil},
1180             } );
1181              
1182 5         18 return _parse_maybe_subscript_rest( $self, $deref );
1183             }
1184              
1185 312         453 my( $is_slice, $sym_sigil );
1186 312 100 100     3676 if( ( $sigil == VALUE_ARRAY || $sigil == VALUE_SCALAR )
    50 66        
      66        
      33        
1187             && ( $next->[O_TYPE] == T_OPSQ || $next->[O_TYPE] == T_OPBRK ) ) {
1188 6 50       23 $sym_sigil = $next->[O_TYPE] == T_OPBRK ? VALUE_HASH : VALUE_ARRAY;
1189 6         23 $is_slice = $sigil == VALUE_ARRAY;
1190             } elsif( $sigil == VALUE_GLOB && $next->[O_TYPE] == T_OPBRK ) {
1191 0         0 $sym_sigil = VALUE_GLOB;
1192             } else {
1193 306 100       1183 return $is_id ? _find_symbol( $self, $sigil, $indir->[O_VALUE], $indir->[O_ID_TYPE] ) :
1194             Language::P::ParseTree::Dereference->new
1195             ( { left => $indir,
1196             op => $dereference_type{$sigil},
1197             } );
1198             }
1199              
1200 6         31 my $subscript = _parse_bracketed_expr( $self, $next->[O_TYPE], 0 );
1201 6 50       34 my $subscripted = $is_id ? _find_symbol( $self, $sym_sigil, $indir->[O_VALUE], $indir->[O_ID_TYPE] ) :
1202             $indir;
1203 6 50       31 my $subscript_type = $next->[O_TYPE] == T_OPBRK ? VALUE_HASH : VALUE_ARRAY;
1204              
1205 6 50       24 if( $is_slice ) {
1206 0 0       0 return Language::P::ParseTree::Slice->new
1207             ( { subscripted => $subscripted,
1208             subscript => $subscript,
1209             type => $subscript_type,
1210             reference => $is_id ? 0 : 1,
1211             } );
1212             } else {
1213 6 50       85 my $term = Language::P::ParseTree::Subscript->new
1214             ( { subscripted => $subscripted,
1215             subscript => $subscript,
1216             type => $subscript_type,
1217             reference => $is_id ? 0 : 1,
1218             } );
1219              
1220 6         26 return _parse_maybe_subscript_rest( $self, $term );
1221             }
1222             }
1223              
1224             sub _parse_lexical {
1225 8     8   17 my( $self, $keyword ) = @_;
1226              
1227 8 50 33     29 die $keyword unless $keyword == OP_MY || $keyword == OP_OUR;
1228              
1229 8         25 local $self->{_in_declaration} = 1;
1230 8         24 my $term = _parse_term_list_if_parens( $self, PREC_NAMED_UNOP );
1231              
1232 8         33 return _process_declaration( $self, $term, $keyword );
1233             }
1234              
1235             sub _process_declaration {
1236 15     15   43 my( $self, $decl, $keyword ) = @_;
1237              
1238 15 100       161 if( $decl->isa( 'Language::P::ParseTree::List' ) ) {
    50          
1239 4         19 foreach my $e ( @{$decl->expressions} ) {
  4         13  
1240 4         26 $e = _process_declaration( $self, $e, $keyword );
1241             }
1242              
1243 4         18 return $decl;
1244             } elsif( $decl->isa( 'Language::P::ParseTree::Symbol' ) ) {
1245 11         54 my $decl = Language::P::ParseTree::LexicalDeclaration->new
1246             ( { name => $decl->name,
1247             sigil => $decl->sigil,
1248             flags => $declaration_to_flags{$keyword},
1249             } );
1250 11         44 push @{$self->_pending_lexicals}, $decl;
  11         45  
1251              
1252 11         142 return $decl;
1253             } else {
1254 0         0 die 'Invalid node ', ref( $decl ), ' in declaration';
1255             }
1256             }
1257              
1258             sub _parse_term_p {
1259 1048     1048   1701 my( $self, $prec, $token, $lookahead, $is_bind ) = @_;
1260 1048         2385 my $terminal = _parse_term_terminal_maybe_subscripts( $self, $token, $is_bind );
1261              
1262 1048 100 100     5040 return $terminal if $terminal && !$lookahead;
1263              
1264 710 100       2157 if( $terminal ) {
    50          
    100          
    100          
1265 589         1689 my $la = $self->lexer->peek( X_OPERATOR );
1266 589         1946 my $binprec = $prec_assoc_bin{$la->[O_TYPE]};
1267              
1268 589 100 100     2763 if( !$binprec || $binprec->[0] > $prec ) {
    100          
    50          
1269 370         852 return $terminal;
1270             } elsif( $la->[O_TYPE] == T_INTERR ) {
1271 9         25 _lex_token( $self, T_INTERR );
1272 9         31 return _parse_ternary( $self, PREC_TERNARY, $terminal );
1273             } elsif( $binprec ) {
1274 210         650 return _parse_term_n( $self, $binprec->[0],
1275             $terminal );
1276             } else {
1277 0         0 _syntax_error( $self, $la );
1278             }
1279             } elsif( $token->[O_TYPE] == T_FILETEST ) {
1280 0         0 return _parse_listop_like( $self, undef, 1,
1281             Language::P::ParseTree::Builtin->new
1282             ( { function => $token->[O_FT_OP],
1283             } ) );
1284             } elsif( my $p = $prec_assoc_un{$token->[O_TYPE]} ) {
1285 6         44 my $rest = _parse_term_n( $self, $p->[0] );
1286              
1287 6         94 return Language::P::ParseTree::UnOp->new
1288             ( { op => $p->[2],
1289             left => $rest,
1290             } );
1291             } elsif( $token->[O_TYPE] == T_OPPAR ) {
1292 15         47 my $term = _parse_expr( $self );
1293 15         51 _lex_token( $self, T_CLPAR );
1294              
1295 15 50       193 if( !$term ) {
    100          
1296             # empty list
1297 0         0 return Language::P::ParseTree::List->new
1298             ( { expressions => [],
1299             } );
1300             } elsif( !$term->isa( 'Language::P::ParseTree::List' ) ) {
1301             # record that there were prentheses, unless it is a list
1302 9         83 return Language::P::ParseTree::Parentheses->new
1303             ( { left => $term,
1304             } );
1305             } else {
1306 6         18 return $term;
1307             }
1308             }
1309              
1310 100         223 return undef;
1311             }
1312              
1313             sub _parse_ternary {
1314 67     67   165 my( $self, $prec, $terminal ) = @_;
1315              
1316 67         197 my $iftrue = _parse_term_n( $self, PREC_TERNARY_COLON - 1 );
1317 67         234 _lex_token( $self, T_COLON );
1318 67         196 my $iffalse = _parse_term( $self, $prec );
1319              
1320 67         638 return Language::P::ParseTree::Ternary->new
1321             ( { condition => $terminal,
1322             iftrue => $iftrue,
1323             iffalse => $iffalse,
1324             } );
1325             }
1326              
1327             sub _parse_term_n {
1328 1310     1310   2024 my( $self, $prec, $terminal, $is_bind ) = @_;
1329              
1330 1310 100       2652 if( !$terminal ) {
1331 347         1028 my $token = $self->lexer->lex( X_TERM );
1332 347         1078 $terminal = _parse_term_p( $self, $prec, $token, undef, $is_bind );
1333              
1334 347 50       1310 if( !$terminal ) {
1335 0         0 $self->lexer->unlex( $token );
1336 0         0 return undef;
1337             }
1338             }
1339              
1340 1310         1384 for(;;) {
1341 1642         4438 my $token = $self->lexer->lex( X_OPERATOR );
1342              
1343 1642 50 33     13735 if( $token->[O_TYPE] == T_PLUSPLUS
1344             || $token->[O_TYPE] == T_MINUSMINUS ) {
1345 0 0       0 my $op = $token->[O_TYPE] == T_PLUSPLUS ? OP_POSTINC : OP_POSTDEC;
1346 0         0 $terminal = Language::P::ParseTree::UnOp->new
1347             ( { op => $op,
1348             left => $terminal,
1349             } );
1350 0         0 $token = $self->lexer->lex( X_OPERATOR );
1351             }
1352              
1353 1642         3092 my $bin = $prec_assoc_bin{$token->[O_TYPE]};
1354 1642 100 100     5617 if( !$bin || $bin->[0] > $prec ) {
    100          
1355 1310         3423 $self->lexer->unlex( $token );
1356 1310         6298 last;
1357             } elsif( $token->[O_TYPE] == T_INTERR ) {
1358 58         204 $terminal = _parse_ternary( $self, PREC_TERNARY, $terminal );
1359             } else {
1360             # do not try to use colon as binary
1361 274 50       749 _syntax_error( $self, $token )
1362             if $token->[O_TYPE] == T_COLON;
1363              
1364 274 100       795 my $q = $bin->[1] == ASSOC_RIGHT ? $bin->[0] : $bin->[0] - 1;
1365 274   33     1939 my $rterm = _parse_term_n( $self, $q, undef,
1366             ( $token->[O_TYPE] == T_MATCH
1367             || $token->[O_TYPE] == T_NOTMATCH ) );
1368              
1369 274 100       730 if( $token->[O_TYPE] == T_COMMA ) {
1370 21 100       206 if( $terminal->isa( 'Language::P::ParseTree::List' ) ) {
1371 7 50       24 if( $rterm ) {
1372 7         11 push @{$terminal->expressions}, $rterm;
  7         26  
1373 7         128 $rterm->set_parent( $terminal );
1374             }
1375             } else {
1376 14 50       149 $terminal = Language::P::ParseTree::List->new
1377             ( { expressions => [ $terminal, $rterm ? $rterm : () ],
1378             } );
1379             }
1380             } else {
1381 253         2386 $terminal = Language::P::ParseTree::BinOp->new
1382             ( { op => $bin->[2],
1383             left => $terminal,
1384             right => $rterm,
1385             } );
1386             }
1387             }
1388             }
1389              
1390 1310         2639 return $terminal;
1391             }
1392              
1393             sub _parse_term {
1394 701     701   1080 my( $self, $prec ) = @_;
1395 701         1862 my $token = $self->lexer->lex( X_TERM );
1396 701         3654 my $terminal = _parse_term_p( $self, $prec, $token, 1, 0 );
1397              
1398 701 100       1758 if( $terminal ) {
1399 601         1272 $terminal = _parse_term_n( $self, $prec, $terminal );
1400              
1401 601         1714 return $terminal;
1402             }
1403              
1404 100         346 $self->lexer->unlex( $token );
1405              
1406 100         606 return undef;
1407             }
1408              
1409             sub _parse_term_list_if_parens {
1410 22     22   53 my( $self, $prec ) = @_;
1411 22         63 my $term = _parse_term( $self, $prec );
1412              
1413 22 100       244 if( $term->isa( 'Language::P::ParseTree::Parentheses' ) ) {
1414 4         13 return Language::P::ParseTree::List->new
1415             ( { expressions => [ $term->left ],
1416             } );
1417             }
1418              
1419 18         121 return $term;
1420             }
1421              
1422             sub _add_implicit_return {
1423 28     28   91 my( $line ) = @_;
1424              
1425 28 100       139 return $line unless $line->can_implicit_return;
1426 14 100       146 if( !$line->is_compound ) {
1427 8         60 return Language::P::ParseTree::Builtin->new
1428             ( { arguments => [ $line ],
1429             function => OP_RETURN,
1430             } );
1431             }
1432              
1433             # compound and can implicitly return
1434 6 100 66     79 if( $line->isa( 'Language::P::ParseTree::Block' ) && @{$line->lines} ) {
  3 100       44  
    50          
1435 3         27 $line->lines->[-1] = _add_implicit_return( $line->lines->[-1] );
1436             } elsif( $line->isa( 'Language::P::ParseTree::Conditional' ) ) {
1437 1         3 _add_implicit_return( $_ ) foreach @{$line->iftrues};
  1         5  
1438 1 50       4 _add_implicit_return( $line->iffalse ) if $line->iffalse;
1439             } elsif( $line->isa( 'Language::P::ParseTree::ConditionalBlock' ) ) {
1440 2         6 _add_implicit_return( $line->block )
1441             } else {
1442 0         0 Carp::confess( "Unhandled statement type: ", ref( $line ) );
1443             }
1444              
1445 6         43 return $line;
1446             }
1447              
1448             sub _parse_block_rest {
1449 78     78   162 my( $self, $flags, $end_token ) = @_;
1450              
1451 78   50     335 $end_token ||= T_CLBRK;
1452 78 100       296 $self->_enter_scope if $flags & BLOCK_OPEN_SCOPE;
1453              
1454 78         404 my @lines;
1455 78         115 for(;;) {
1456 211         669 my $token = $self->lexer->lex( X_STATE );
1457 211 100       711 if( $token->[O_TYPE] == $end_token ) {
1458 78 100 66     419 if( $flags & BLOCK_IMPLICIT_RETURN && @lines ) {
1459 21         84 for( my $i = $#lines; $i >= 0; --$i ) {
1460 21 50       193 next if $lines[$i]->is_declaration;
1461 21         158 $lines[$i] = _add_implicit_return( $lines[$i] );
1462 21         155 last;
1463             }
1464             }
1465              
1466 78 100       359 $self->_leave_scope if $flags & BLOCK_OPEN_SCOPE;
1467 78 100       197 if( $flags & BLOCK_BARE ) {
1468 7         32 my $continue = _parse_continue( $self );
1469 7         132 return Language::P::ParseTree::BareBlock->new
1470             ( { lines => \@lines,
1471             continue => $continue,
1472             } );
1473             } else {
1474 71         591 return Language::P::ParseTree::Block->new
1475             ( { lines => \@lines,
1476             } );
1477             }
1478             } else {
1479 133         419 $self->lexer->unlex( $token );
1480 133         847 my $line = _parse_line( $self );
1481              
1482 133 50       710 push @lines, $line if $line; # skip empty satements
1483             }
1484             }
1485             }
1486              
1487             sub _parse_indirobj {
1488 317     317   600 my( $self, $allow_fail ) = @_;
1489 317         923 my $id = $self->lexer->lex_identifier( 0 );
1490              
1491 317 50       786 if( $id ) {
1492 317         625 return $id;
1493             }
1494              
1495 0         0 my $token = $self->lexer->lex( X_OPERATOR );
1496              
1497 0 0       0 if( $token->[O_TYPE] == T_OPBRK ) {
    0          
    0          
1498 0         0 my $block = _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
1499              
1500 0         0 return $block;
1501             } elsif( $token->[O_TYPE] == T_DOLLAR ) {
1502 0         0 my $indir = _parse_indirobj( $self, 0 );
1503              
1504 0 0 0     0 if( ref( $indir ) eq 'ARRAY' && $indir->[O_TYPE] == T_ID ) {
1505 0         0 return _find_symbol( $self, VALUE_SCALAR, $indir->[O_VALUE], $indir->[O_ID_TYPE] );
1506             } else {
1507 0         0 return Language::P::ParseTree::Dereference->new
1508             ( { left => $indir,
1509             op => OP_DEREFERENCE_SCALAR,
1510             } );
1511             }
1512             } elsif( $allow_fail ) {
1513 0         0 $self->lexer->unlex( $token );
1514              
1515 0         0 return undef;
1516             } else {
1517 0         0 _syntax_error( $self, $token );
1518             }
1519             }
1520              
1521             sub _declared_id {
1522 183     183   258 my( $self, $op ) = @_;
1523 183         336 my $call;
1524 183         287 my $opidt = $op->[O_ID_TYPE];
1525              
1526 183 100       535 if( is_overridable( $opidt ) ) {
    100          
1527 7         24 my $st = $self->runtime->symbol_table;
1528              
1529 7 50       57 if( $st->get_symbol( _qualify( $self, $op->[O_VALUE], $opidt ), '&' ) ) {
1530 0         0 die "Overriding '" . $op->[O_VALUE] . "' not implemented";
1531             }
1532 7         70 $call = Language::P::ParseTree::Overridable->new
1533             ( { function => $KEYWORD_TO_OP{$opidt},
1534             } );
1535              
1536 7         25 return ( $call, 1 );
1537             } elsif( is_builtin( $opidt ) ) {
1538 140         1450 $call = Language::P::ParseTree::Builtin->new
1539             ( { function => $KEYWORD_TO_OP{$opidt},
1540             } );
1541              
1542 140         511 return ( $call, 1 );
1543             } else {
1544 36         120 my $st = $self->runtime->symbol_table;
1545              
1546 36 100       304 if( $st->get_symbol( _qualify( $self, $op->[O_VALUE], $opidt ), '&' ) ) {
1547 33         84 return ( undef, 1 );
1548             }
1549             }
1550              
1551 3         9 return ( undef, 0 );
1552             }
1553              
1554             sub _parse_listop {
1555 183     183   270 my( $self, $op ) = @_;
1556 183         438 my( $call, $declared ) = _declared_id( $self, $op );
1557              
1558 183         684 return _parse_listop_like( $self, $op, $declared, $call );
1559             }
1560              
1561             sub _parse_listop_like {
1562 183     183   337 my( $self, $op, $declared, $call ) = @_;
1563 183 100       705 my $proto = $call ? $call->parsing_prototype : undef;
1564 183 50       1487 my $expect = !$proto ? X_TERM :
    100          
    100          
1565             $proto->[2] & (PROTO_FILEHANDLE|PROTO_INDIROBJ) ? X_REF :
1566             $proto->[2] & (PROTO_BLOCK|PROTO_SUB) ? X_BLOCK :
1567             X_TERM;
1568 183         566 my $next = $self->lexer->peek( $expect );
1569 183         299 my( $args, $fh );
1570              
1571 183 100 66     714 if( !$call || !$declared ) {
1572 36         107 my $st = $self->runtime->symbol_table;
1573              
1574 36 50 66     440 if( $next->[O_TYPE] == T_ARROW ) {
    50          
1575 0         0 _lex_token( $self, T_ARROW );
1576 0         0 my $la = $self->lexer->peek( X_OPERATOR );
1577              
1578 0 0 0     0 if( $la->[O_TYPE] == T_ID || $la->[O_TYPE] == T_DOLLAR ) {
    0          
1579             # here we are calling the method on a bareword
1580 0         0 my $invocant = Language::P::ParseTree::Constant->new
1581             ( { value => $op->[O_VALUE],
1582             flags => CONST_STRING,
1583             } );
1584              
1585 0         0 return _parse_maybe_direct_method_call( $self, $invocant );
1586             } elsif( $la->[O_TYPE] == T_OPPAR ) {
1587             # parsed as a normal sub call; go figure
1588 0         0 $next = $la;
1589             } else {
1590 0         0 _syntax_error( $self, $la );
1591             }
1592             } elsif( !$declared && $next->[O_TYPE] != T_OPPAR ) {
1593             # not a declared subroutine, nor followed by parenthesis
1594             # try to see if it is some sort of (indirect) method call
1595 0         0 return _parse_maybe_indirect_method_call( $self, $op, $next );
1596             }
1597              
1598             # foo Bar:: is always a method call
1599 36 50 33     129 if( $next->[O_TYPE] == T_ID
1600             && $st->get_package( $next->[O_VALUE] ) ) {
1601 0         0 return _parse_maybe_indirect_method_call( $self, $op, $next );
1602             }
1603              
1604 36         107 my $symbol = Language::P::ParseTree::Symbol->new
1605             ( { name => _qualify( $self, $op->[O_VALUE], $op->[O_ID_TYPE] ),
1606             sigil => VALUE_SUB,
1607             } );
1608 36         341 $call = Language::P::ParseTree::FunctionCall->new
1609             ( { function => $symbol,
1610             arguments => undef,
1611             } );
1612 36         143 $proto = $call->parsing_prototype;
1613             }
1614              
1615 183 100       934 if( $next->[O_TYPE] == T_OPPAR ) {
    100          
    100          
1616 47         165 _lex_token( $self, T_OPPAR );
1617 47         190 ( $args, $fh ) = _parse_arglist( $self, PREC_LOWEST, 0, $proto->[2] );
1618 47         115 _lex_token( $self, T_CLPAR );
1619             } elsif( $proto->[1] == 1 ) {
1620 5         37 ( $args, undef ) = _parse_arglist( $self, PREC_NAMED_UNOP, 1, $proto->[2] );
1621             } elsif( $proto->[1] != 0 ) {
1622 125 50       291 Carp::confess( "Undeclared identifier '" . $op->[O_VALUE] . "'" )
1623             unless $declared;
1624 125         759 ( $args, $fh ) = _parse_arglist( $self, PREC_COMMA, 0, $proto->[2] );
1625             }
1626              
1627             # FIXME avoid reconstructing the call?
1628 183 100       700 if( $proto->[2] & (PROTO_INDIROBJ|PROTO_FILEHANDLE) ) {
    100          
1629 112         1264 $call = Language::P::ParseTree::BuiltinIndirect->new
1630             ( { function => $KEYWORD_TO_OP{$op->[O_ID_TYPE]},
1631             arguments => $args,
1632             indirect => $fh,
1633             } );
1634             } elsif( $args ) {
1635             # FIXME encapsulation
1636 38         84 $call->{arguments} = $args;
1637 38         212 $_->set_parent( $call ) foreach @$args;
1638             }
1639              
1640 183         643 _apply_prototype( $self, $call );
1641              
1642 183         1302 return $call;
1643             }
1644              
1645             sub _apply_prototype {
1646 183     183   336 my( $self, $call ) = @_;
1647 183         649 my $proto = $call->parsing_prototype;
1648 183   100     1125 my $args = $call->arguments || [];
1649              
1650 183 50       1286 if( @$args < $proto->[0] ) {
1651 0         0 die "Too few arguments for call";
1652             }
1653 183 50 66     1614 if( $proto->[1] != -1 && @$args > $proto->[1] ) {
1654 0         0 die "Too many arguments for call";
1655             }
1656              
1657 183         577 foreach my $i ( 3 .. $#$proto ) {
1658 177 100       556 last if $i - 3 > $#$args;
1659 150         280 my $proto_char = $proto->[$i];
1660 150         246 my $term = $args->[$i - 3];
1661              
1662             # defined/exists &foo
1663 150 100       374 if( $proto_char & PROTO_AMPER ) {
1664 11 50 33     113 if( $term->isa( 'Language::P::ParseTree::SpecialFunctionCall' )
1665             && $term->flags & FLAG_IMPLICITARGUMENTS ) {
1666 0         0 $args->[$i - 3] = $term->function;
1667             }
1668             }
1669 150 50 66     769 if( $proto_char & PROTO_MAKE_GLOB && $term->is_bareword ) {
1670 0         0 $args->[$i - 3] = Language::P::ParseTree::Symbol->new
1671             ( { name => $term->value,
1672             sigil => VALUE_GLOB,
1673             } );
1674             }
1675             }
1676             }
1677              
1678             sub _parse_arglist {
1679 188     188   383 my( $self, $prec, $is_unary, $proto_char ) = @_;
1680 188         294 my $indirect_term = $proto_char & (PROTO_INDIROBJ|PROTO_FILEHANDLE);
1681 188 100       566 my $la = $self->lexer->peek( $indirect_term ? X_REF : X_TERM );
1682 188 100       501 my $term_prec = $prec > PREC_LISTEXPR ? PREC_LISTEXPR : $prec;
1683              
1684 188         266 my $term;
1685 188 100 33     639 if( $indirect_term ) {
    50          
1686 112 50 66     929 if( $la->[O_TYPE] == T_OPBRK ) {
    50 66        
1687 0         0 $term = _parse_indirobj( $self, 0 );
1688             } elsif( $proto_char & PROTO_FILEHANDLE
1689             && $la->[O_TYPE] == T_ID
1690             && $la->[O_ID_TYPE] == T_ID ) {
1691             # check if it is a declared id
1692 0         0 my $declared = $self->runtime->symbol_table
1693             ->get_symbol( _qualify( $self, $la->[O_VALUE], $la->[O_ID_TYPE] ), '&' );
1694             # look ahead one more token
1695 0         0 _lex_token( $self );
1696 0         0 my $la2 = $self->lexer->peek( X_TERM );
1697              
1698             # approximate what would happen in Perl LALR parser
1699 0         0 my $tt = $la2->[O_TYPE];
1700 0 0 0     0 if( $declared ) {
    0 0        
    0 0        
      0        
      0        
      0        
1701 0         0 $self->lexer->unlex( $la );
1702 0         0 $indirect_term = 0;
1703             } elsif( $prec_assoc_bin{$tt}
1704             && !$prec_assoc_un{$tt}
1705             && $tt != T_STAR
1706             && $tt != T_PERCENT
1707             && $tt != T_DOLLAR
1708             && $tt != T_AMPERSAND
1709             ) {
1710 0         0 $self->lexer->unlex( $la );
1711 0         0 $indirect_term = 0;
1712             } elsif( $tt == T_ID && is_id( $la2->[O_ID_TYPE] ) ) {
1713 0         0 $self->lexer->unlex( $la );
1714 0         0 $indirect_term = 0;
1715             } else {
1716 0         0 $term = Language::P::ParseTree::Symbol->new
1717             ( { name => $la->[O_VALUE],
1718             sigil => VALUE_GLOB,
1719             } );
1720             }
1721             } else {
1722 112         1761 $term = _parse_term( $self, $term_prec );
1723              
1724 112 50 66     820 if( !$term ) {
    100          
1725 0         0 $indirect_term = 0;
1726             } elsif( !( $term->is_symbol && $term->sigil == VALUE_SCALAR )
1727             && !$term->isa( 'Language::P::ParseTree::Block' ) ) {
1728 109         196 $indirect_term = 0;
1729             }
1730             }
1731             } elsif( $proto_char & (PROTO_BLOCK|PROTO_SUB)
1732             && $la->[O_TYPE] == T_OPBRK ) {
1733 0         0 _lex_token( $self );
1734 0         0 $term = _parse_block_rest( $self, BLOCK_OPEN_SCOPE );
1735             }
1736              
1737 188   100     652 $term ||= _parse_term( $self, $term_prec );
1738              
1739 188 100       1478 return unless $term;
1740 158 100       1230 return [ $term ] if $is_unary;
1741              
1742 155 100       472 if( $indirect_term ) {
1743 3         12 my $la = $self->lexer->peek( X_TERM );
1744              
1745 3 50       10 if( $la->[O_TYPE] != T_COMMA ) {
1746 3         16 my $args = _parse_arglist( $self, $prec, 0, 0 );
1747              
1748 3 50 33     16 if( !$args && $term->is_symbol && $term->sigil == VALUE_SCALAR ) {
      33        
1749 3         24 return ( [ $term ] );
1750             } else {
1751 0         0 return ( $args, $term );
1752             }
1753             }
1754             }
1755              
1756 152         384 $term = _parse_term_n( $self, $prec, $term, 0 );
1757              
1758 152 50 33     1981 return $term && $term->isa( 'Language::P::ParseTree::List' ) ?
1759             $term->expressions : [ $term ];
1760             }
1761              
1762             1;