File Coverage

blib/lib/Text/Xslate/Parser.pm
Criterion Covered Total %
statement 865 890 97.1
branch 217 248 87.5
condition 65 77 84.4
subroutine 116 118 98.3
pod 1 99 1.0
total 1264 1432 88.2


line stmt bran cond sub pod time code
1             package Text::Xslate::Parser;
2 172     172   225108 use Mouse;
  172         124281  
  172         989  
3              
4 172     172   47538 use Scalar::Util ();
  172         358  
  172         3281  
5              
6 172     172   90993 use Text::Xslate::Symbol;
  172         17387  
  172         7169  
7 172         29428 use Text::Xslate::Util qw(
8             $DEBUG
9             $STRING $NUMBER
10             is_int any_in
11             neat
12             literal_to_value
13             make_error
14             p
15 172     172   1090 );
  172         295  
16              
17 172     172   958 use constant _DUMP_PROTO => scalar($DEBUG =~ /\b dump=proto \b/xmsi);
  172         316  
  172         11898  
18 172     172   839 use constant _DUMP_TOKEN => scalar($DEBUG =~ /\b dump=token \b/xmsi);
  172         320  
  172         1979458  
19              
20             our @CARP_NOT = qw(Text::Xslate::Compiler Text::Xslate::Symbol);
21              
22             my $CODE = qr/ (?: $STRING | [^'"] ) /xms;
23             my $COMMENT = qr/\# [^\n;]* (?= [;\n] | \z)/xms;
24              
25             # Operator tokens that the parser recognizes.
26             # All the single characters are tokenized as an operator.
27             my $OPERATOR_TOKEN = sprintf '(?:%s|[^ \t\r\n])', join('|', map{ quotemeta } qw(
28             ...
29             ..
30             == != <=> <= >=
31             << >>
32             += -= *= /= %= ~=
33             &&= ||= //=
34             ~~ =~
35              
36             && || //
37             -> =>
38             ::
39             ++ --
40             +| +& +^ +< +> +~
41             ), ',');
42              
43             my %shortcut_table = (
44             '=' => 'print',
45             );
46              
47             my $CHOMP_FLAGS = qr/-/xms;
48              
49              
50             has identity_pattern => (
51             is => 'ro',
52             isa => 'RegexpRef',
53              
54             builder => '_build_identity_pattern',
55             init_arg => undef,
56             );
57              
58             sub _build_identity_pattern {
59 182     182   28669 return qr/(?: (?:[A-Za-z_]|\$\~?) [A-Za-z0-9_]* )/xms;
60             }
61              
62             has [qw(compiler engine)] => (
63             is => 'rw',
64             required => 0,
65             weak_ref => 1,
66             );
67              
68             has symbol_table => ( # the global symbol table
69             is => 'ro',
70             isa => 'HashRef',
71              
72             default => sub{ {} },
73              
74             init_arg => undef,
75             );
76              
77             has iterator_element => (
78             is => 'ro',
79             isa => 'HashRef',
80              
81             lazy => 1,
82             builder => '_build_iterator_element',
83              
84             init_arg => undef,
85             );
86              
87             has scope => (
88             is => 'rw',
89             isa => 'ArrayRef[HashRef]',
90              
91             clearer => 'init_scope',
92              
93             lazy => 1,
94             default => sub{ [ {} ] },
95              
96             init_arg => undef,
97             );
98              
99             has token => (
100             is => 'rw',
101             isa => 'Maybe[Object]',
102              
103             init_arg => undef,
104             );
105              
106             has next_token => ( # to peek the next token
107             is => 'rw',
108             isa => 'Maybe[ArrayRef]',
109              
110             init_arg => undef,
111             );
112              
113             has statement_is_finished => (
114             is => 'rw',
115             isa => 'Bool',
116              
117             init_arg => undef,
118             );
119              
120             has following_newline => (
121             is => 'rw',
122             isa => 'Int',
123              
124             default => 0,
125             init_arg => undef,
126             );
127              
128             has input => (
129             is => 'rw',
130             isa => 'Str',
131              
132             init_arg => undef,
133             );
134              
135             has line_start => (
136             is => 'ro',
137             isa => 'Maybe[Str]',
138             builder => '_build_line_start',
139             );
140 176     176   6508 sub _build_line_start { ':' }
141              
142             has tag_start => (
143             is => 'ro',
144             isa => 'Str',
145             builder => '_build_tag_start',
146             );
147 177     177   6330 sub _build_tag_start { '<:' }
148              
149             has tag_end => (
150             is => 'ro',
151             isa => 'Str',
152             builder => '_build_tag_end',
153             );
154 177     177   7175 sub _build_tag_end { ':>' }
155              
156             has comment_pattern => (
157             is => 'ro',
158             isa => 'RegexpRef',
159             builder => '_build_comment_pattern',
160             );
161 241     241   7490 sub _build_comment_pattern { $COMMENT }
162              
163             has shortcut_table => (
164             is => 'ro',
165             isa => 'HashRef[Str]',
166             builder => '_build_shortcut_table',
167             );
168 241     241   5653 sub _build_shortcut_table { \%shortcut_table }
169              
170             has in_given => (
171             is => 'rw',
172             isa => 'Bool',
173             init_arg => undef,
174             );
175              
176             # attributes for error messages
177              
178             has near_token => (
179             is => 'rw',
180              
181             init_arg => undef,
182             );
183              
184             has file => (
185             is => 'rw',
186             required => 0,
187             );
188              
189             has line => (
190             is => 'rw',
191             required => 0,
192             );
193              
194             has input_layer => (
195             is => 'ro',
196             default => ':utf8',
197             );
198              
199             sub symbol_class() { 'Text::Xslate::Symbol' }
200              
201             # the entry point
202             sub parse {
203 3458     3458 0 30177 my($parser, $input, %args) = @_;
204              
205 3458   100     16732 local $parser->{file} = $args{file} || \$input;
206 3458   50     17618 local $parser->{line} = $args{line} || 1;
207 3458         8424 local $parser->{in_given} = 0;
208 3458         6357 local $parser->{scope} = [ map { +{ %{$_} } } @{ $parser->scope } ];
  3458         5919  
  3458         20135  
  3458         15762  
209 3458         6683 local $parser->{symbol_table} = { %{ $parser->symbol_table } };
  3458         173673  
210 3458         29557 local $parser->{near_token};
211 3458         8161 local $parser->{next_token};
212 3458         7753 local $parser->{token};
213 3458         7439 local $parser->{input};
214              
215 3458         11185 $parser->input( $parser->preprocess($input) );
216              
217 3453         11385 $parser->next_token( $parser->tokenize() );
218 3453         10956 $parser->advance();
219 3452         10253 my $ast = $parser->statements();
220              
221 3411 100       14274 if(my $input_pos = pos $parser->{input}) {
222 3408 100       12845 if($input_pos != length($parser->{input})) {
223 2         8 $parser->_error("Syntax error", $parser->token);
224             }
225             }
226              
227 3409         76499 return $ast;
228             }
229              
230             sub trim_code {
231 5197     5197 0 9942 my($parser, $s) = @_;
232              
233 5197         15902 $s =~ s/\A [ \t]+ //xms;
234 5197         22424 $s =~ s/ [ \t]+ \n?\z//xms;
235              
236 5197         15781 return $s;
237             }
238              
239             sub auto_chomp {
240 10377     10377 0 18620 my($parser, $tokens_ref, $i, $s_ref) = @_;
241              
242 10377         14528 my $p;
243 10377         15541 my $nl = 0;
244              
245             # postchomp
246 10377 100 100     49135 if($i >= 1
247             and ($p = $tokens_ref->[$i-1])->[0] eq 'postchomp') {
248             # [ CODE ][*][ TEXT ]
249             # <: ... -:> \nfoobar
250             # ^^^^
251 391         446 ${$s_ref} =~ s/\A [ \t]* (\n)//xms;
  391         1567  
252 391 100       1211 if($1) {
253 386         543 $nl++;
254             }
255             }
256              
257             # prechomp
258 10377 100 100     16132 if(($i+1) < @{$tokens_ref}
  10377 100 100     52825  
      66        
      100        
259             and ($p = $tokens_ref->[$i+1])->[0] eq 'prechomp') {
260 51 100       62 if(${$s_ref} !~ / [^ \t] /xms) {
  51         167  
261             # HERE
262             # [ TEXT ][*][ CODE ]
263             # <:- ... :>
264             # ^^^^^^^^
265 34         44 ${$s_ref} = '';
  34         62  
266             }
267             else {
268             # HERE
269             # [ TEXT ][*][ CODE ]
270             # \n<:- ... :>
271             # ^^
272 17         34 $nl += chomp ${$s_ref};
  17         55  
273             }
274             }
275 10326         59886 elsif(($i+2) < @{$tokens_ref}
276             and ($p = $tokens_ref->[$i+2])->[0] eq 'prechomp'
277             and ($p = $tokens_ref->[$i+1])->[0] eq 'text'
278             and $p->[1] !~ / [^ \t] /xms) {
279             # HERE
280             # [ TEXT ][ TEXT ][*][ CODE ]
281             # \n <:- ... :>
282             # ^^^^^^^^^^
283 16         30 $p->[1] = '';
284 16         22 $nl += (${$s_ref} =~ s/\n\z//xms);
  16         43  
285             }
286 10377         26432 return $nl;
287             }
288              
289             # split templates by tags before tokenizing
290             sub split :method {
291 3458     3458 0 6460 my $parser = shift;
292 3458         8351 local($_) = @_;
293              
294 3458         6283 my @tokens;
295              
296 3458         11298 my $line_start = $parser->line_start;
297 3458         9917 my $tag_start = $parser->tag_start;
298 3458         9763 my $tag_end = $parser->tag_end;
299              
300 3458   66     37247 my $lex_line_code = defined($line_start)
301             && qr/\A ^ [ \t]* \Q$line_start\E ([^\n]* \n?) /xms;
302              
303 3458         19649 my $lex_tag_start = qr/\A \Q$tag_start\E ($CHOMP_FLAGS?)/xms;
304              
305             # 'text' is a something without newlines
306             # following a newline, $tag_start, or end of the input
307 3458         19542 my $lex_text = qr/\A ( [^\n]*? (?: \n | (?= \Q$tag_start\E ) | \z ) ) /xms;
308              
309 3458         11244 my $lex_comment = $parser->comment_pattern;
310 3458         29577 my $lex_code = qr/(?: $lex_comment | $CODE )/xms;
311              
312 3458         7435 my $in_tag = 0;
313              
314 3458         10716 while($_ ne '') {
315 18244 100 100     3218739 if($in_tag) {
    100 66        
    100 100        
    50          
316 2652         4970 my $start = 0;
317 2652         4775 my $pos;
318 2652         11367 while( ($pos = index $_, $tag_end, $start) >= 0 ) {
319 2651         8358 my $code = substr $_, 0, $pos;
320 2651         44947 $code =~ s/$lex_code//xmsg;
321 2651 100       9029 if(length($code) == 0) {
322 2648         7719 last;
323             }
324 3         11 $start = $pos + 1;
325             }
326              
327 2652 100       6977 if($pos >= 0) {
328 2648         9308 my $code = substr $_, 0, $pos, '';
329 2648         15720 $code =~ s/($CHOMP_FLAGS?) \z//xmso;
330 2648         6877 my $chomp = $1;
331              
332 2648 50       16201 s/\A \Q$tag_end\E //xms or die "Oops!";
333              
334 2648         8971 push @tokens, [ code => $code ];
335 2648 100       7895 if($chomp) {
336 393         932 push @tokens, [ postchomp => $chomp ];
337             }
338 2648         13817 $in_tag = 0;
339             }
340             else {
341 4         8 last; # the end tag is not found
342             }
343             }
344             # not $in_tag
345             elsif($lex_line_code
346             && (@tokens == 0 || $tokens[-1][1] =~ /\n\z/xms)
347             && s/$lex_line_code//xms) {
348 2554         12560 push @tokens, [ code => $1 ];
349             }
350             elsif(s/$lex_tag_start//xms) {
351 2653         5517 $in_tag = 1;
352              
353 2653         6848 my $chomp = $1;
354 2653 100       13366 if($chomp) {
355 60         258 push @tokens, [ prechomp => $chomp ];
356             }
357             }
358             elsif(s/$lex_text//xms) {
359 10385         57292 push @tokens, [ text => $1 ];
360             }
361             else {
362 0         0 confess "Oops: Unreached code, near" . p($_);
363             }
364             }
365              
366 3458 100       9511 if($in_tag) {
367             # calculate line number
368 5         10 my $orig_src = $_[0];
369 5         21 substr $orig_src, -length($_), length($_), '';
370 5         13 my $line = ($orig_src =~ tr/\n/\n/);
371 5         32 $parser->_error("Malformed templates detected",
372             neat((split /\n/, $_)[0]), ++$line,
373             );
374             }
375             #p(\@tokens);
376 3453         20276 return \@tokens;
377             }
378              
379             sub preprocess {
380 3458     3458 0 7118 my($parser, $input) = @_;
381              
382             # tokenization
383              
384 3458         9832 my $tokens_ref = $parser->split($input);
385 3453         7138 my $code = '';
386              
387 3453         11553 my $shortcut_table = $parser->shortcut_table;
388 3453         9431 my $shortcut = join('|', map{ quotemeta } keys %shortcut_table);
  3453         14286  
389 3453         17051 my $shortcut_rx = qr/\A ($shortcut)/xms;
390              
391 3453         7619 for(my $i = 0; $i < @{$tokens_ref}; $i++) {
  19484         62494  
392 16031         23404 my($type, $s) = @{ $tokens_ref->[$i] };
  16031         42616  
393              
394 16031 100       42701 if($type eq 'text') {
    100          
    100          
    50          
395 10377         26642 my $nl = $parser->auto_chomp($tokens_ref, $i, \$s);
396              
397 10377         24203 $s =~ s/(["\\])/\\$1/gxms; # " for poor editors
398              
399             # $s may have single new line
400 10377         31567 $nl += ($s =~ s/\n/\\n/xms);
401              
402 10377         27412 $code .= qq{print_raw "$s";}; # must set even if $s is empty
403 10377 100       44023 $code .= qq{\n} if $nl > 0;
404             }
405             elsif($type eq 'code') {
406             # shortcut commands
407 5201 50       27413 $s =~ s/$shortcut_rx/$shortcut_table->{$1}/xms
408             if $shortcut;
409              
410 5201         14859 $s = $parser->trim_code($s);
411              
412 5201 100       24576 if($s =~ /\A \s* [}] \s* \z/xms){
    100          
413 546         1248 $code .= $s;
414             }
415             elsif($s =~ s/\n\z//xms) {
416 2028         6710 $code .= qq{$s\n};
417             }
418             else {
419 2627         15006 $code .= qq{$s;}; # auto semicolon insertion
420             }
421             }
422             elsif($type eq 'prechomp') {
423             # noop, just a marker
424             }
425             elsif($type eq 'postchomp') {
426             # noop, just a marker
427             }
428             else {
429 0         0 $parser->_error("Oops: Unknown token: $s ($type)");
430             }
431             }
432 3453         5889 print STDOUT $code, "\n" if _DUMP_PROTO;
433 3453         27627 return $code;
434             }
435              
436             sub BUILD {
437 241     241 1 2121 my($parser) = @_;
438 241         3524 $parser->_init_basic_symbols();
439 241         2876 $parser->init_symbols();
440 241         7230 return;
441             }
442              
443             # The grammer
444              
445             sub _init_basic_symbols {
446 241     241   2282 my($parser) = @_;
447              
448 241         3264 $parser->symbol('(end)')->is_block_end(1); # EOF
449              
450             # prototypes of value symbols
451 241         2384 foreach my $type (qw(name variable literal)) {
452 723         7518 my $s = $parser->symbol("($type)");
453 723         7663 $s->arity($type);
454 723         17951 $s->set_nud( $parser->can("nud_$type") );
455             }
456              
457             # common separators
458 241         2520 $parser->symbol(';')->set_nud(\&nud_separator);
459 241         3053 $parser->define_pair('(' => ')');
460 241         2513 $parser->define_pair('{' => '}');
461 241         2439 $parser->define_pair('[' => ']');
462 241         2710 $parser->symbol(',') ->is_comma(1);
463 241         2412 $parser->symbol('=>') ->is_comma(1);
464              
465             # common commands
466 241         2310 $parser->symbol('print') ->set_std(\&std_print);
467 241         2489 $parser->symbol('print_raw')->set_std(\&std_print);
468              
469             # special literals
470 241         3164 $parser->define_literal(nil => undef);
471 241         2288 $parser->define_literal(true => 1);
472 241         2348 $parser->define_literal(false => 0);
473              
474             # special tokens
475 241         2332 $parser->symbol('__FILE__')->set_nud(\&nud_current_file);
476 241         2492 $parser->symbol('__LINE__')->set_nud(\&nud_current_line);
477 241         2360 $parser->symbol('__ROOT__')->set_nud(\&nud_current_vars);
478              
479 241         3844 return;
480             }
481              
482             sub init_basic_operators {
483 241     241 0 2230 my($parser) = @_;
484              
485             # define operator precedence
486              
487 241         3331 $parser->prefix('{', 256, \&nud_brace);
488 241         2410 $parser->prefix('[', 256, \&nud_brace);
489              
490 241         3216 $parser->infix('(', 256, \&led_call);
491 241         3057 $parser->infix('.', 256, \&led_dot);
492 241         2858 $parser->infix('[', 256, \&led_fetch);
493              
494 241         4006 $parser->prefix('(', 256, \&nud_paren);
495              
496 241         2854 $parser->prefix('!', 200)->is_logical(1);
497 241         2917 $parser->prefix('+', 200);
498 241         2323 $parser->prefix('-', 200);
499 241         2306 $parser->prefix('+^', 200); # numeric bitwise negate
500              
501 241         2341 $parser->infix('*', 190);
502 241         2477 $parser->infix('/', 190);
503 241         2400 $parser->infix('%', 190);
504 241         2514 $parser->infix('x', 190);
505 241         2280 $parser->infix('+&', 190); # numeric bitwise and
506              
507 241         2282 $parser->infix('+', 180);
508 241         2332 $parser->infix('-', 180);
509 241         2705 $parser->infix('~', 180); # connect
510 241         2416 $parser->infix('+|', 180); # numeric bitwise or
511 241         2298 $parser->infix('+^', 180); # numeric bitwise xor
512              
513              
514 241         2401 $parser->prefix('defined', 170, \&nud_defined); # named unary operator
515              
516 241         2313 $parser->infix('<', 160)->is_logical(1);
517 241         2275 $parser->infix('<=', 160)->is_logical(1);
518 241         2293 $parser->infix('>', 160)->is_logical(1);
519 241         2328 $parser->infix('>=', 160)->is_logical(1);
520              
521 241         2306 $parser->infix('==', 150)->is_logical(1);
522 241         2344 $parser->infix('!=', 150)->is_logical(1);
523 241         2341 $parser->infix('<=>', 150);
524 241         2494 $parser->infix('cmp', 150);
525 241         2412 $parser->infix('~~', 150);
526              
527 241         2402 $parser->infix('|', 140, \&led_pipe);
528              
529 241         2323 $parser->infix('&&', 130)->is_logical(1);
530              
531 241         2484 $parser->infix('||', 120)->is_logical(1);
532 241         2412 $parser->infix('//', 120)->is_logical(1);
533 241         2422 $parser->infix('min', 120);
534 241         2300 $parser->infix('max', 120);
535              
536 241         2571 $parser->infix('..', 110, \&led_range);
537              
538 241         2282 $parser->symbol(':');
539 241         3153 $parser->infixr('?', 100, \&led_ternary);
540              
541 241         3907 $parser->assignment('=', 90);
542 241         2534 $parser->assignment('+=', 90);
543 241         2356 $parser->assignment('-=', 90);
544 241         2264 $parser->assignment('*=', 90);
545 241         2384 $parser->assignment('/=', 90);
546 241         2481 $parser->assignment('%=', 90);
547 241         2403 $parser->assignment('~=', 90);
548 241         2361 $parser->assignment('&&=', 90);
549 241         2794 $parser->assignment('||=', 90);
550 241         2300 $parser->assignment('//=', 90);
551              
552 241         3135 $parser->make_alias('!' => 'not')->ubp(70);
553 241         3629 $parser->make_alias('&&' => 'and')->lbp(60);
554 241         2629 $parser->make_alias('||' => 'or') ->lbp(50);
555 241         5667 return;
556             }
557              
558             sub init_symbols {
559 182     182 0 2033 my($parser) = @_;
560 182         1976 my $s;
561              
562             # syntax specific separators
563 182         2125 $parser->symbol('{');
564 182         2084 $parser->symbol('}')->is_block_end(1); # block end
565 182         2297 $parser->symbol('->');
566 182         2130 $parser->symbol('else');
567 182         2111 $parser->symbol('with');
568 182         2152 $parser->symbol('::');
569              
570             # operators
571 182         2719 $parser->init_basic_operators();
572              
573             # statements
574 182         2253 $s = $parser->symbol('if');
575 182         2448 $s->set_std(\&std_if);
576 182         2569 $s->can_be_modifier(1);
577              
578 182         2172 $parser->symbol('for') ->set_std(\&std_for);
579 182         2287 $parser->symbol('while' ) ->set_std(\&std_while);
580 182         2200 $parser->symbol('given') ->set_std(\&std_given);
581 182         2322 $parser->symbol('when') ->set_std(\&std_when);
582 182         2131 $parser->symbol('default') ->set_std(\&std_when);
583              
584 182         2166 $parser->symbol('include') ->set_std(\&std_include);
585              
586 182         2227 $parser->symbol('last') ->set_std(\&std_last);
587 182         2221 $parser->symbol('next') ->set_std(\&std_next);
588              
589             # macros
590              
591 182         2348 $parser->symbol('cascade') ->set_std(\&std_cascade);
592 182         2143 $parser->symbol('macro') ->set_std(\&std_proc);
593 182         2222 $parser->symbol('around') ->set_std(\&std_proc);
594 182         2368 $parser->symbol('before') ->set_std(\&std_proc);
595 182         2257 $parser->symbol('after') ->set_std(\&std_proc);
596 182         2244 $parser->symbol('block') ->set_std(\&std_macro_block);
597 182         2319 $parser->symbol('super') ->set_std(\&std_super);
598 182         2418 $parser->symbol('override') ->set_std(\&std_override);
599              
600 182         2385 $parser->symbol('->') ->set_nud(\&nud_lambda);
601              
602             # lexical variables/constants stuff
603 182         2180 $parser->symbol('constant')->set_nud(\&nud_constant);
604 182         2253 $parser->symbol('my' )->set_nud(\&nud_constant);
605              
606 182         3712 return;
607             }
608              
609             sub _build_iterator_element {
610             return {
611 4     4   90 index => \&iterator_index,
612             count => \&iterator_count,
613             is_first => \&iterator_is_first,
614             is_last => \&iterator_is_last,
615             body => \&iterator_body,
616             size => \&iterator_size,
617             max_index => \&iterator_max_index,
618             peek_next => \&iterator_peek_next,
619             peek_prev => \&iterator_peek_prev,
620             cycle => \&iterator_cycle,
621             };
622             }
623              
624              
625             sub symbol {
626 52955     52955 0 284756 my($parser, $id, $lbp) = @_;
627              
628 52955         314049 my $stash = $parser->symbol_table;
629 52955         285198 my $s = $stash->{$id};
630 52955 100       300576 if(defined $s) {
631 25240 100       98762 if(defined $lbp) {
632 1205         27549 $s->lbp($lbp);
633             }
634             }
635             else { # create a new symbol
636 27715   100     509024 $s = $parser->symbol_class->new(id => $id, lbp => $lbp || 0);
637 27715         464240 $stash->{$id} = $s;
638             }
639              
640 52955         573156 return $s;
641             }
642              
643             sub define_pair {
644 723     723 0 6468 my($parser, $left, $right) = @_;
645 723         6689 $parser->symbol($left) ->counterpart($right);
646 723         6765 $parser->symbol($right)->counterpart($left);
647 723         11528 return;
648             }
649              
650             # the low-level tokenizer. Don't use it directly, use advance() instead.
651             sub tokenize {
652 64596     64596 0 103673 my($parser) = @_;
653              
654 64596         139145 local *_ = \$parser->{input};
655              
656 64596         154679 my $comment_rx = $parser->comment_pattern;
657 64596         139842 my $id_rx = $parser->identity_pattern;
658 64596         92633 my $count = 0;
659             TRY: {
660 64596         91740 /\G (\s*) /xmsgc;
  64642         168784  
661 64642         138551 $count += ( $1 =~ tr/\n/\n/);
662 64642         166816 $parser->following_newline( $count );
663              
664 64642 100       587028 if(/\G $comment_rx /xmsgc) {
    100          
    100          
    100          
    50          
665 46         103 redo TRY; # retry
666             }
667             elsif(/\G ($id_rx)/xmsgc){
668 19446         122033 return [ name => $1 ];
669             }
670             elsif(/\G ($NUMBER | $STRING)/xmsogc){
671 17591         102855 return [ literal => $1 ];
672             }
673             elsif(/\G ($OPERATOR_TOKEN)/xmsogc){
674 24143         139451 return [ operator => $1 ];
675             }
676             elsif(/\G (\S+)/xmsgc) {
677 0         0 Carp::confess("Oops: Unexpected token '$1'");
678             }
679             else { # empty
680 3416         20292 return [ special => '(end)' ];
681             }
682             }
683             }
684              
685             sub next_token_is {
686 19485     19485 0 35035 my($parser, $token) = @_;
687 19485         116975 return $parser->next_token->[1] eq $token;
688             }
689              
690             # the high-level tokenizer
691             sub advance {
692 64567     64567 0 105548 my($parser, $expect) = @_;
693              
694 64567         143247 my $t = $parser->token;
695 64567 100 100     176111 if(defined($expect) && $t->id ne $expect) {
696 7         24 $parser->_unexpected(neat($expect), $t);
697             }
698              
699 64560         151685 $parser->near_token($t);
700              
701 64560         254737 my $stash = $parser->symbol_table;
702              
703 64560         144333 $t = $parser->next_token;
704              
705 64560 100       160247 if($t->[0] eq 'special') {
706 3417         19636 return $parser->token( $stash->{ $t->[1] } );
707             }
708 61143         206893 $parser->statement_is_finished( $parser->following_newline != 0 );
709 61143         238938 my $line = $parser->line( $parser->line + $parser->following_newline );
710              
711 61143         143639 $parser->next_token( $parser->tokenize() );
712              
713 61143         96847 my($arity, $id) = @{$t};
  61143         153597  
714 61143 100 100     190231 if( $arity eq "name" && $parser->next_token_is("=>") ) {
715 63         111 $arity = "literal";
716             }
717              
718 61143         83296 print STDOUT "[$arity => $id] #$line\n" if _DUMP_TOKEN;
719              
720 61143         80323 my $symbol;
721 61143 100       154175 if($arity eq "literal") {
    100          
722 17653         40238 $symbol = $parser->symbol('(literal)')->clone(
723             id => $id,
724             value => $parser->parse_literal($id)
725             );
726             }
727             elsif($arity eq "operator") {
728 24114         47024 $symbol = $stash->{$id};
729 24114 100       54368 if(not defined $symbol) {
730 3         13 $parser->_error("Unknown operator '$id'");
731             }
732 24111         71742 $symbol = $symbol->clone(
733             arity => $arity, # to make error messages clearer
734             );
735             }
736             else { # name
737             # find_or_create() returns a cloned symbol,
738             # so there's not need to clone() here
739 19376         46502 $symbol = $parser->find_or_create($id);
740             }
741              
742 61140         863923 $symbol->line($line);
743 61140         276667 return $parser->token($symbol);
744             }
745              
746             sub parse_literal {
747 17653     17653 0 29080 my($parser, $literal) = @_;
748 17653         50407 return literal_to_value($literal);
749             }
750              
751             sub nud_name {
752 341     341 0 548 my($parser, $symbol) = @_;
753 341         946 return $symbol->clone(
754             arity => 'name',
755             );
756             }
757             sub nud_variable {
758 2774     2774 0 5845 my($parser, $symbol) = @_;
759 2774         8684 return $symbol->clone(
760             arity => 'variable',
761             );
762             }
763             sub nud_literal {
764 17632     17632 0 27182 my($parser, $symbol) = @_;
765 17632         46009 return $symbol->clone(
766             arity => 'literal',
767             );
768             }
769              
770             sub default_nud {
771 377     377 0 547 my($parser, $symbol) = @_;
772 377         1006 return $symbol->clone(); # as is
773             }
774              
775             sub default_led {
776 0     0 0 0 my($parser, $symbol) = @_;
777 0         0 $parser->near_token($parser->token);
778 0         0 $parser->_error(
779             sprintf 'Missing operator (%s): %s',
780             $symbol->arity, $symbol->id);
781             }
782              
783             sub default_std {
784 0     0 0 0 my($parser, $symbol) = @_;
785 0         0 $parser->near_token($parser->token);
786 0         0 $parser->_error(
787             sprintf 'Not a statement (%s): %s',
788             $symbol->arity, $symbol->id);
789             }
790              
791             sub expression {
792 21883     21883 0 35308 my($parser, $rbp) = @_;
793              
794 21883         47638 my $t = $parser->token;
795              
796 21883         46353 $parser->advance();
797              
798 21883         64374 my $left = $t->nud($parser);
799              
800 21868         520658 while($rbp < $parser->token->lbp) {
801 1923         9694 $t = $parser->token;
802 1923         5101 $parser->advance();
803 1923         5717 $left = $t->led($parser, $left);
804             }
805              
806 21850         88589 return $left;
807             }
808              
809             sub expression_list {
810 12211     12211 0 21176 my($parser) = @_;
811 12211         18469 my @list;
812 12211         19069 while(1) {
813 17521 100       68774 if($parser->token->is_value) {
814 17273         39008 push @list, $parser->expression(0);
815             }
816              
817 17521 100       72067 if(!$parser->token->is_comma) {
818 12211         27474 last;
819             }
820              
821 5310         9534 $parser->advance(); # comma
822             }
823 12211         39446 return \@list;
824             }
825              
826             # for left associative infix operators
827             sub led_infix {
828 863     863 0 1353 my($parser, $symbol, $left) = @_;
829 863         2799 return $parser->binary( $symbol, $left, $parser->expression($symbol->lbp) );
830             }
831              
832             sub infix {
833 6989     6989 0 59473 my($parser, $id, $bp, $led) = @_;
834              
835 6989         60403 my $symbol = $parser->symbol($id, $bp);
836 6989   100     79911 $symbol->set_led($led || \&led_infix);
837 6989         109350 return $symbol;
838             }
839              
840             # for right associative infix operators
841             sub led_infixr {
842 26     26 0 48 my($parser, $symbol, $left) = @_;
843 26         113 return $parser->binary( $symbol, $left, $parser->expression($symbol->lbp - 1) );
844             }
845              
846             sub infixr {
847 241     241 0 2516 my($parser, $id, $bp, $led) = @_;
848              
849 241         4517 my $symbol = $parser->symbol($id, $bp);
850 241   50     3322 $symbol->set_led($led || \&led_infixr);
851 241         4045 return $symbol;
852             }
853              
854             # for prefix operators
855             sub prefix {
856 1928     1928 0 16500 my($parser, $id, $bp, $nud) = @_;
857              
858 1928         16991 my $symbol = $parser->symbol($id);
859 1928         18980 $symbol->ubp($bp);
860 1928   100     39238 $symbol->set_nud($nud || \&nud_prefix);
861 1928         30340 return $symbol;
862             }
863              
864             sub nud_prefix {
865 51     51 0 88 my($parser, $symbol) = @_;
866 51         186 my $un = $symbol->clone(arity => 'unary');
867 51         1110 $parser->reserve($un);
868 51         190 $un->first($parser->expression($symbol->ubp));
869 50         115 return $un;
870             }
871              
872             sub led_assignment {
873 11     11 0 18 my($parser, $symbol, $left) = @_;
874              
875 11         49 $parser->_error("Assignment ($symbol) is forbidden", $left);
876             }
877              
878             sub assignment {
879 1820     1820 0 20428 my($parser, $id, $bp) = @_;
880              
881 1820         22268 $parser->symbol($id, $bp)->set_led(\&led_assignment);
882 1820         35085 return;
883             }
884              
885             # the ternary is a right associative operator
886             sub led_ternary {
887 115     115 0 193 my($parser, $symbol, $left) = @_;
888              
889 115         312 my $if = $symbol->clone(arity => 'if');
890              
891 115         2373 $if->first($left);
892 115         422 $if->second([$parser->expression( $symbol->lbp - 1 )]);
893 113         284 $parser->advance(":");
894 113         434 $if->third([$parser->expression( $symbol->lbp - 1 )]);
895 113         608 return $if;
896             }
897              
898             sub is_valid_field {
899 447     447 0 614 my($parser, $token) = @_;
900 447         1186 my $arity = $token->arity;
901              
902 447 100       1099 if($arity eq "name") {
    100          
903 409         1579 return 1;
904             }
905             elsif($arity eq "literal") {
906 9         45 return is_int($token->id);
907             }
908 29         288 return 0;
909             }
910              
911             sub led_dot {
912 447     447 0 715 my($parser, $symbol, $left) = @_;
913              
914 447         1042 my $t = $parser->token;
915 447 50       1203 if(!$parser->is_valid_field($t)) {
916 0         0 $parser->_unexpected("a field name", $t);
917             }
918              
919 447         1467 my $dot = $symbol->clone(
920             arity => "field",
921             first => $left,
922             second => $t->clone(arity => 'literal'),
923             );
924              
925 447         9635 $t = $parser->advance();
926 447 100       1797 if($t->id eq "(") {
927 230         638 $parser->advance(); # "("
928 230         564 $dot->third( $parser->expression_list() );
929 230         561 $parser->advance(")");
930 230         652 $dot->arity("methodcall");
931             }
932              
933 447         3308 return $dot;
934             }
935              
936             sub led_fetch { # $h[$field]
937 90     90 0 150 my($parser, $symbol, $left) = @_;
938              
939 90         276 my $fetch = $symbol->clone(
940             arity => "field",
941             first => $left,
942             second => $parser->expression(0),
943             );
944 90         2121 $parser->advance("]");
945 90         498 return $fetch;
946             }
947              
948             sub call {
949 193     193 0 409 my($parser, $function, @args) = @_;
950 193 100       629 if(not ref $function) {
951 4         11 $function = $parser->symbol('(name)')->clone(
952             arity => 'name',
953             id => $function,
954             line => $parser->line,
955             );
956             }
957              
958 193         566 return $parser->symbol('(call)')->clone(
959             arity => 'call',
960             first => $function,
961             second => \@args,
962             );
963             }
964              
965             sub led_call {
966 295     295 0 521 my($parser, $symbol, $left) = @_;
967              
968 295         816 my $call = $symbol->clone(arity => 'call');
969 295         5992 $call->first($left);
970 295         776 $call->second( $parser->expression_list() );
971 295         704 $parser->advance(")");
972              
973 294         1578 return $call;
974             }
975              
976             sub led_pipe { # filter
977 64     64 0 123 my($parser, $symbol, $left) = @_;
978             # a | b -> b(a)
979 64         239 return $parser->call($parser->expression($symbol->lbp), $left);
980             }
981              
982             sub led_range { # x .. y
983 7     7 0 12 my($parser, $symbol, $left) = @_;
984 7         19 return $symbol->clone(
985             arity => 'range',
986             first => $left,
987             second => $parser->expression(0),
988             );
989             }
990              
991             sub nil {
992 26     26 0 113 my($parser) = @_;
993 26         71 return $parser->symbol('nil')->nud($parser);
994             }
995              
996             sub nud_defined {
997 23     23 0 39 my($parser, $symbol) = @_;
998 23         65 $parser->reserve( $symbol->clone() );
999             # prefix: is a syntactic sugar to $a != nil
1000 23         111 return $parser->binary(
1001             '!=',
1002             $parser->expression($symbol->ubp),
1003             $parser->nil,
1004             );
1005             }
1006              
1007             # for special literals (e.g. nil, true, false)
1008             sub nud_special {
1009 170     170 0 270 my($parser, $symbol) = @_;
1010 170         640 return $symbol->first;
1011             }
1012              
1013             sub define_literal { # special literals
1014 723     723 0 6160 my($parser, $id, $value) = @_;
1015              
1016 723         6358 my $symbol = $parser->symbol($id);
1017 723 100       8468 $symbol->first( $symbol->clone(
1018             arity => defined($value) ? 'literal' : 'nil',
1019             value => $value,
1020             ) );
1021 723         14443 $symbol->set_nud(\&nud_special);
1022 723         7136 $symbol->is_defined(1);
1023 723         10882 return $symbol;
1024             }
1025              
1026             sub new_scope {
1027 918     918 0 1296 my($parser) = @_;
1028 918         1194 push @{ $parser->scope }, {};
  918         2865  
1029 918         1718 return;
1030             }
1031              
1032             sub pop_scope {
1033 901     901 0 1355 my($parser) = @_;
1034 901         1112 pop @{ $parser->scope };
  901         2319  
1035 901         2596 return;
1036             }
1037              
1038             sub undefined_name {
1039 3615     3615 0 7844 my($parser, $name) = @_;
1040 3615 100       12770 if($name =~ /\A \$/xms) {
1041 2844         13884 return $parser->symbol_table->{'(variable)'}->clone(
1042             id => $name,
1043             );
1044             }
1045             else {
1046 771         3397 return $parser->symbol_table->{'(name)'}->clone(
1047             id => $name,
1048             );
1049             }
1050             }
1051              
1052             sub find_or_create { # find a name from all the scopes
1053 19435     19435 0 35838 my($parser, $name) = @_;
1054 19435         28352 my $s;
1055 19435         29529 foreach my $scope(reverse @{$parser->scope}){
  19435         68095  
1056 22628         42717 $s = $scope->{$name};
1057 22628 100       64415 if(defined $s) {
1058 6016         18196 return $s->clone();
1059             }
1060             }
1061 13419         43746 $s = $parser->symbol_table->{$name};
1062 13419 100       47881 return defined($s) ? $s : $parser->undefined_name($name);
1063             }
1064              
1065             sub reserve { # reserve a name to the scope
1066 13814     13814 0 24199 my($parser, $symbol) = @_;
1067 13814 100 100     93722 if($symbol->arity ne 'name' or $symbol->is_reserved) {
1068 13243         24059 return $symbol;
1069             }
1070              
1071 571         5068 my $top = $parser->scope->[-1];
1072 571         5050 my $t = $top->{$symbol->id};
1073 571 50       4854 if($t) {
1074 0 0       0 if($t->is_reserved) {
1075 0         0 return $symbol;
1076             }
1077 0 0       0 if($t->arity eq "name") {
1078 0         0 $parser->_error("Already defined: $symbol");
1079             }
1080             }
1081 571         5123 $top->{$symbol->id} = $symbol;
1082 571         5231 $symbol->is_reserved(1);
1083             #$symbol->scope($top);
1084 571         7668 return $symbol;
1085             }
1086              
1087             sub define { # define a name to the scope
1088 595     595 0 952 my($parser, $symbol) = @_;
1089 595         1508 my $top = $parser->scope->[-1];
1090              
1091 595         1572 my $t = $top->{$symbol->id};
1092 595 100       1352 if(defined $t) {
1093 1 50       6 $parser->_error($t->is_reserved ? "Already is_reserved: $t" : "Already defined: $t");
1094             }
1095              
1096 594         1866 $top->{$symbol->id} = $symbol;
1097              
1098 594         1586 $symbol->is_defined(1);
1099 594         1760 $symbol->is_reserved(0);
1100 594         1591 $symbol->remove_nud();
1101 594         1357 $symbol->remove_led();
1102 594         1223 $symbol->remove_std();
1103 594         1303 $symbol->lbp(0);
1104             #$symbol->scope($top);
1105 594         1163 return $symbol;
1106             }
1107              
1108             sub print {
1109 1223     1223 0 2522 my($parser, @args) = @_;
1110 1223         2893 return $parser->symbol('print')->clone(
1111             arity => 'print',
1112             first => \@args,
1113             line => $parser->line,
1114             );
1115             }
1116              
1117             sub binary {
1118 994     994 0 1910 my($parser, $symbol, $lhs, $rhs) = @_;
1119 994 100       2392 if(!ref $symbol) {
1120             # operator
1121 109         239 $symbol = $parser->symbol($symbol);
1122             }
1123 994 50       2130 if(!ref $lhs) {
1124             # literal
1125 0         0 $lhs = $parser->symbol('(literal)')->clone(
1126             id => $lhs,
1127             );
1128             }
1129 994 100       2079 if(!ref $rhs) {
1130             # literal
1131 39         81 $rhs = $parser->symbol('(literal)')->clone(
1132             id => $rhs,
1133             );
1134             }
1135 994         3663 return $symbol->clone(
1136             arity => 'binary',
1137             first => $lhs,
1138             second => $rhs,
1139             );
1140             }
1141              
1142             sub define_function {
1143 497     497 0 12545 my($parser, @names) = @_;
1144              
1145 497         2785 foreach my $name(@names) {
1146 6035         52398 my $s = $parser->symbol($name);
1147 6035         109448 $s->set_nud(\&nud_name);
1148 6035         59709 $s->is_defined(1);
1149             }
1150 497         6669 return;
1151             }
1152              
1153             sub finish_statement {
1154 14063     14063 0 25918 my($parser, $expr) = @_;
1155              
1156 14063         35521 my $t = $parser->token;
1157 14063 100       45196 if($t->can_be_modifier) {
1158 30         65 $parser->advance();
1159 30         93 $expr = $t->std($parser, $expr);
1160 30         74 $t = $parser->token;
1161             }
1162              
1163 14063 100 100     103071 if($t->is_block_end or $parser->statement_is_finished) {
    100          
1164             # noop
1165             }
1166             elsif($t->id eq ";") {
1167 12614         30384 $parser->advance();
1168             }
1169             else {
1170 4         28 $parser->_unexpected("a semicolon or block end", $t);
1171             }
1172 14057         133195 return $expr;
1173             }
1174              
1175             sub statement { # process one or more statements
1176 15326     15326 0 25020 my($parser) = @_;
1177 15326         36446 my $t = $parser->token;
1178              
1179 15326 100       51248 if($t->id eq ";"){
1180 448         1003 $parser->advance(); # ";"
1181 448         2293 return;
1182             }
1183              
1184 14878 100       48615 if($t->has_std) { # is $t a statement?
1185 13652         32253 $parser->reserve($t);
1186 13652         32060 $parser->advance();
1187              
1188             # std() can return a list of nodes
1189 13652         43115 return $t->std($parser);
1190             }
1191              
1192 1226         2965 my $expr = $parser->auto_command( $parser->expression(0) );
1193 1200         25310 return $parser->finish_statement($expr);
1194             }
1195              
1196             sub auto_command {
1197 1200     1200 0 1897 my($parser, $expr) = @_;
1198 1200 100       3702 if($expr->is_statement) {
1199             # expressions can produce pure statements (e.g. assignment )
1200 81         164 return $expr;
1201             }
1202             else {
1203 1119         3032 return $parser->print($expr);
1204             }
1205             }
1206              
1207             sub statements { # process statements
1208 4316     4316 0 8117 my($parser) = @_;
1209 4316         7347 my @a;
1210              
1211 4316         21763 for(my $t = $parser->token; !$t->is_block_end; $t = $parser->token) {
1212 15276         40331 push @a, $parser->statement();
1213             }
1214              
1215 4265         14087 return \@a;
1216             }
1217              
1218             sub block {
1219 212     212 0 307 my($parser) = @_;
1220 212         519 $parser->new_scope();
1221 212         451 $parser->advance("{");
1222 212         476 my $a = $parser->statements();
1223 212         499 $parser->advance("}");
1224 211         506 $parser->pop_scope();
1225 211         642 return $a;
1226             }
1227              
1228             sub nud_paren {
1229 121     121 0 213 my($parser, $symbol) = @_;
1230 121         321 my $expr = $parser->expression(0);
1231 121         446 $parser->advance( $symbol->counterpart );
1232 121         275 return $expr;
1233             }
1234              
1235             # for object literals
1236             sub nud_brace {
1237 141     141 0 286 my($parser, $symbol) = @_;
1238              
1239 141         407 my $list = $parser->expression_list();
1240              
1241 141         543 $parser->advance($symbol->counterpart);
1242 141         463 return $symbol->clone(
1243             arity => 'composer',
1244             first => $list,
1245             );
1246             }
1247              
1248             # iterator variables ($~iterator)
1249             # $~iterator . NAME | NAME()
1250             sub nud_iterator {
1251 55     55 0 89 my($parser, $symbol) = @_;
1252              
1253 55         136 my $iterator = $symbol->clone();
1254 55 100       1047 if($parser->token->id eq ".") {
1255 51         105 $parser->advance();
1256              
1257 51         114 my $t = $parser->token;
1258 51 50       214 if(!any_in($t->arity, qw(variable name))) {
1259 0         0 $parser->_unexpected("a field name", $t);
1260             }
1261              
1262 51         393 my $generator = $parser->iterator_element->{$t->value};
1263 51 50       123 if(!$generator) {
1264 0         0 $parser->_error("Undefined iterator element: $t");
1265             }
1266              
1267 51         101 $parser->advance(); # element name
1268              
1269 51         57 my $args;
1270 51 100       245 if($parser->token->id eq "(") {
1271 15         31 $parser->advance();
1272 15         36 $args = $parser->expression_list();
1273 15         36 $parser->advance(")");
1274             }
1275              
1276 51         128 $iterator->second($t);
1277 51         62 return $generator->($parser, $iterator, @{$args});
  51         157  
1278             }
1279 4         11 return $iterator;
1280             }
1281              
1282             sub nud_constant {
1283 70     70 0 111 my($parser, $symbol) = @_;
1284 70         178 my $t = $parser->token;
1285              
1286 70 50       352 my $expect = $symbol->id eq 'constant' ? 'name'
    100          
1287             : $symbol->id eq 'my' ? 'variable'
1288             : die "Oops: $symbol";
1289              
1290 70 50       245 if($t->arity ne $expect) {
1291 0         0 $parser->_unexpected("a $expect", $t);
1292             }
1293 70         196 $parser->define($t)->arity("name");
1294              
1295 69         163 $parser->advance();
1296 69         153 $parser->advance("=");
1297              
1298 69         202 return $symbol->clone(
1299             arity => 'constant',
1300             first => $t,
1301             second => $parser->expression(0),
1302             is_statement => 1,
1303             );
1304             }
1305              
1306             my $lambda_id = 0;
1307             sub lambda {
1308 56     56 0 86 my($parser, $proto) = @_;
1309 56         131 my $name = $parser->symbol('(name)')->clone(
1310             id => sprintf('lambda@%s:%d', $parser->file, $lambda_id++),
1311             );
1312              
1313 56         1116 return $parser->symbol('(name)')->clone(
1314             arity => 'proc',
1315             id => 'macro',
1316             first => $name,
1317             line => $proto->line,
1318             );
1319             }
1320              
1321             # -> $x { ... }
1322             sub nud_lambda {
1323 39     39 0 61 my($parser, $symbol) = @_;
1324              
1325 39         108 my $pointy = $parser->lambda($symbol);
1326              
1327 39         897 $parser->new_scope();
1328 39         49 my @params;
1329 39 50       170 if($parser->token->id ne "{") { # has params
1330 39         124 my $paren = ($parser->token->id eq "(");
1331              
1332 39 50       86 $parser->advance("(") if $paren; # optional
1333              
1334 39         87 my $t = $parser->token;
1335 39         129 while($t->arity eq "variable") {
1336 54         78 push @params, $t;
1337 54         122 $parser->define($t);
1338              
1339 54         119 $t = $parser->advance();
1340 54 100       164 if($t->id eq ",") {
1341 15         32 $t = $parser->advance(); # ","
1342             }
1343             else {
1344 39         57 last;
1345             }
1346             }
1347              
1348 39 50       97 $parser->advance(")") if $paren;
1349             }
1350 39         134 $pointy->second( \@params );
1351              
1352 39         88 $parser->advance("{");
1353 39         98 $pointy->third($parser->statements());
1354 39         96 $parser->advance("}");
1355 39         97 $parser->pop_scope();
1356              
1357 39         118 return $symbol->clone(
1358             arity => 'lambda',
1359             first => $pointy,
1360             );
1361             }
1362              
1363             sub nud_current_file {
1364 1     1 0 3 my($self, $symbol) = @_;
1365 1         6 my $file = $self->file;
1366 1 50       6 return $symbol->clone(
1367             arity => 'literal',
1368             value => ref($file) ? '' : $file,
1369             );
1370             }
1371              
1372             sub nud_current_line {
1373 14     14 0 20 my($self, $symbol) = @_;
1374 14         52 return $symbol->clone(
1375             arity => 'literal',
1376             value => $symbol->line,
1377             );
1378             }
1379              
1380             sub nud_current_vars {
1381 5     5 0 10 my($self, $symbol) = @_;
1382 5         13 return $symbol->clone(
1383             arity => 'vars',
1384             );
1385             }
1386              
1387             sub nud_separator {
1388 4     4 0 8 my($self, $symbol) = @_;
1389 4         11 $self->_error("Invalid expression found", $symbol);
1390             }
1391              
1392             # -> VARS { STATEMENTS }
1393             # -> { STATEMENTS }
1394             # { STATEMENTS }
1395             sub pointy {
1396 436     436 0 733 my($parser, $pointy, $in_for) = @_;
1397              
1398 436         548 my @params;
1399              
1400 436         1156 $parser->new_scope();
1401              
1402 436 100       2063 if($parser->token->id eq "->") {
1403 416         880 $parser->advance();
1404 416 100       1968 if($parser->token->id ne "{") {
1405 225         829 my $paren = ($parser->token->id eq "(");
1406              
1407 225 100       648 $parser->advance("(") if $paren;
1408              
1409 225         536 my $t = $parser->token;
1410 225         842 while($t->arity eq "variable") {
1411 231         447 push @params, $t;
1412 231         654 $parser->define($t);
1413              
1414 231 100       547 if($in_for) {
1415 149         473 $parser->define_iterator($t);
1416             }
1417              
1418 231         515 $t = $parser->advance();
1419              
1420 231 100       995 if($t->id eq ",") {
1421 7         20 $t = $parser->advance(); # ","
1422             }
1423             else {
1424 224         346 last;
1425             }
1426             }
1427              
1428 225 100       760 $parser->advance(")") if $paren;
1429             }
1430             }
1431 434         1531 $pointy->second( \@params );
1432              
1433 434         1199 $parser->advance("{");
1434 432         1163 $pointy->third($parser->statements());
1435 422         1025 $parser->advance("}");
1436 422         1235 $parser->pop_scope();
1437              
1438 422         778 return;
1439             }
1440              
1441             sub iterator_name {
1442 149     149 0 230 my($parser, $var) = @_;
1443             # $foo -> $~foo
1444 149         1122 (my $it_name = $var->id) =~ s/\A (\$?) /${1}~/xms;
1445 149         593 return $it_name;
1446             }
1447              
1448             sub define_iterator {
1449 184     184 0 311 my($parser, $var) = @_;
1450              
1451 184         556 my $it = $parser->symbol( $parser->iterator_name($var) )->clone(
1452             arity => 'iterator',
1453             first => $var,
1454             );
1455 184         3954 $parser->define($it);
1456 184         1261 $it->set_nud(\&nud_iterator);
1457 184         450 return $it;
1458             }
1459              
1460             sub std_for {
1461 149     149 0 248 my($parser, $symbol) = @_;
1462              
1463 149         434 my $proc = $symbol->clone(arity => 'for');
1464 149         3076 $proc->first( $parser->expression(0) );
1465 149         562 $parser->pointy($proc, 1);
1466              
1467             # for-else support
1468 139 100       2024 if($parser->token eq 'else') {
1469 5         12 $parser->advance();
1470 5         19 my $else = $parser->block();
1471 5         17 $proc = $symbol->clone( arity => 'for_else',
1472             first => $proc,
1473             second => $else,
1474             )
1475             }
1476 139         1034 return $proc;
1477             }
1478              
1479             sub std_while {
1480 15     15 0 25 my($parser, $symbol) = @_;
1481              
1482 15         44 my $proc = $symbol->clone(arity => 'while');
1483 15         338 $proc->first( $parser->expression(0) );
1484 15         45 $parser->pointy($proc);
1485 15         90 return $proc;
1486             }
1487              
1488             # macro name -> { ... }
1489             sub std_proc {
1490 150     150 0 386 my($parser, $symbol) = @_;
1491              
1492 150         435 my $macro = $symbol->clone(arity => "proc");
1493 150         3094 my $name = $parser->token;
1494              
1495 150 50       639 if($name->arity ne "name") {
1496 0         0 $parser->_unexpected("a name", $name);
1497             }
1498              
1499 150         519 $parser->define_function($name->id);
1500 150         412 $macro->first($name);
1501 150         335 $parser->advance();
1502 150         456 $parser->pointy($macro);
1503 146         956 return $macro;
1504             }
1505              
1506             # block name -> { ... }
1507             # block name | filter -> { ... }
1508             sub std_macro_block {
1509 92     92 0 160 my($parser, $symbol) = @_;
1510              
1511 92         288 my $macro = $symbol->clone(arity => "proc");
1512 92         1963 my $name = $parser->token;
1513              
1514 92 50       371 if($name->arity ne "name") {
1515 0         0 $parser->_unexpected("a name", $name);
1516             }
1517              
1518             # auto filters
1519 92         156 my @filters;
1520 92         218 my $t = $parser->advance();
1521 92         410 while($t->id eq "|") {
1522 11         57 $t = $parser->advance();
1523              
1524 11 50       80 if($t->arity ne "name") {
1525 0         0 $parser->_unexpected("a name", $name);
1526             }
1527 11         42 my $filter = $t->clone();
1528 11         236 $t = $parser->advance();
1529              
1530 11         22 my $args;
1531 11 100       86 if($t->id eq "(") {
1532 2         8 $parser->advance();
1533 2         8 $args = $parser->expression_list();
1534 2         9 $t = $parser->advance(")");
1535             }
1536             push @filters, $args
1537 11 100       66 ? $parser->call($filter, @{$args})
  2         9  
1538             : $filter;
1539             }
1540              
1541 92         393 $parser->define_function($name->id);
1542 92         263 $macro->first($name);
1543 92         269 $parser->pointy($macro);
1544              
1545 92         471 my $call = $parser->call($macro->first);
1546 92 100       2145 if(@filters) {
1547 9         22 foreach my $filter(@filters) { # apply filters
1548 11         81 $call = $parser->call($filter, $call);
1549             }
1550             }
1551             # std() can return a list
1552 92         542 return( $macro, $parser->print($call) );
1553             }
1554              
1555             sub std_override { # synonym to 'around'
1556 6     6 0 11 my($parser, $symbol) = @_;
1557              
1558 6         21 return $parser->std_proc($symbol->clone(id => 'around'));
1559             }
1560              
1561             sub std_if {
1562 112     112 0 190 my($parser, $symbol, $expr) = @_;
1563              
1564 112         334 my $if = $symbol->clone(arity => "if");
1565              
1566 112         2342 $if->first( $parser->expression(0) );
1567              
1568 112 100       306 if(defined $expr) { # statement modifier
1569 13         48 $if->second([$expr]);
1570 13         35 return $if;
1571             }
1572              
1573 99         298 $if->second( $parser->block() );
1574              
1575 98         139 my $top_if = $if;
1576              
1577 98         230 my $t = $parser->token;
1578 98         387 while($t->id eq "elsif") {
1579 3         8 $parser->reserve($t);
1580 3         8 $parser->advance(); # "elsif"
1581              
1582 3         10 my $elsif = $t->clone(arity => "if");
1583 3         57 $elsif->first( $parser->expression(0) );
1584 3         9 $elsif->second( $parser->block() );
1585 3         10 $if->third([$elsif]);
1586 3         4 $if = $elsif;
1587 3         14 $t = $parser->token;
1588             }
1589              
1590 98 100       388 if($t->id eq "else") {
1591 56         125 $parser->reserve($t);
1592 56         130 $t = $parser->advance(); # "else"
1593              
1594 56 100       290 $if->third( $t->id eq "if"
1595             ? [$parser->statement()]
1596             : $parser->block());
1597             }
1598 98         793 return $top_if;
1599             }
1600              
1601             sub std_given {
1602 30     30 0 49 my($parser, $symbol) = @_;
1603              
1604 30         81 my $given = $symbol->clone(arity => 'given');
1605 30         602 $given->first( $parser->expression(0) );
1606              
1607 30         72 local $parser->{in_given} = 1;
1608 30         74 $parser->pointy($given);
1609              
1610 30 100 66     106 if(!(defined $given->second && @{$given->second})) { # if no topic vars
  30         141  
1611 14         34 $given->second([
1612             $parser->symbol('($_)')->clone(arity => 'variable' )
1613             ]);
1614             }
1615              
1616 30         342 $parser->build_given_body($given, "when");
1617 30         198 return $given;
1618             }
1619              
1620             # when/default
1621             sub std_when {
1622 60     60 0 81 my($parser, $symbol) = @_;
1623              
1624 60 50       200 if(!$parser->in_given) {
1625 0         0 $parser->_error("You cannot use $symbol blocks outside given blocks");
1626             }
1627 60         156 my $proc = $symbol->clone(arity => 'when');
1628 60 100       1219 if($symbol->id eq "when") {
1629 31         243 $proc->first( $parser->expression(0) );
1630             }
1631 60         139 $proc->second( $parser->block() );
1632 60         334 return $proc;
1633             }
1634              
1635             sub _only_white_spaces {
1636 21     21   27 my($s) = @_;
1637 21   33     224 return $s->arity eq "literal"
1638             && $s->value =~ m{\A [ \t\r\n]* \z}xms
1639             }
1640              
1641             sub build_given_body {
1642 40     40 0 61 my($parser, $given, $expect) = @_;
1643 40         59 my($topic) = @{$given->second};
  40         113  
1644              
1645             # make if-elsif-else chain from given-when
1646 40         56 my $if;
1647             my $elsif;
1648 0         0 my $else;
1649 40         67 foreach my $when(@{$given->third}) {
  40         112  
1650 101 100       313 if($when->arity ne $expect) {
1651             # ignore white space
1652 22 100 66     74 if($when->id eq "print_raw"
1653 21         35 && !grep { !_only_white_spaces($_) } @{$when->first}) {
  21         51  
1654 21         34 next;
1655             }
1656 1         5 $parser->_unexpected("$expect blocks", $when);
1657             }
1658 79         180 $when->arity("if"); # change the arity
1659              
1660 79 100       219 if(defined(my $test = $when->first)) { # when
1661 43 100       123 if(!$test->is_logical) {
1662 31         82 $when->first( $parser->binary('~~', $topic, $test) );
1663             }
1664             }
1665             else { # default
1666 36         92 $when->first( $parser->symbol('true')->nud($parser) );
1667 36         56 $else = $when;
1668 36         76 next;
1669             }
1670              
1671 43 100       689 if(!defined $if) {
1672 35         40 $if = $when;
1673 35         64 $elsif = $when;
1674             }
1675             else {
1676 8         26 $elsif->third([$when]);
1677 8         17 $elsif = $when;
1678             }
1679             }
1680 39 100       93 if(defined $else) { # default
1681 36 100       69 if(defined $elsif) {
1682 33         97 $elsif->third([$else]);
1683             }
1684             else {
1685 3         7 $if = $else; # only default
1686             }
1687             }
1688 39 100       150 $given->third(defined $if ? [$if] : undef);
1689 39         125 return;
1690             }
1691              
1692             sub std_include {
1693 1253     1253 0 1792 my($parser, $symbol) = @_;
1694              
1695 1253         3032 my $arg = $parser->barename();
1696 1253         3023 my $vars = $parser->localize_vars();
1697 1253         3631 my $stmt = $symbol->clone(
1698             first => $arg,
1699             second => $vars,
1700             arity => 'include',
1701             );
1702 1253         27881 return $parser->finish_statement($stmt);
1703             }
1704              
1705             sub std_print {
1706 11515     11515 0 21107 my($parser, $symbol) = @_;
1707 11515         17285 my $args;
1708 11515 50       53113 if($parser->token->id ne ";") {
1709 11515         28468 $args = $parser->expression_list();
1710             }
1711 11515         37563 my $stmt = $symbol->clone(
1712             arity => 'print',
1713             first => $args,
1714             );
1715 11515         272744 return $parser->finish_statement($stmt);
1716             }
1717              
1718             # for cascade() and include()
1719             sub barename {
1720 1333     1333 0 1835 my($parser) = @_;
1721              
1722 1333         3075 my $t = $parser->token;
1723 1333 100 100     5149 if($t->arity ne 'name' or $t->is_defined) {
1724             # string literal for 'cascade', or any expression for 'include'
1725 1264         2919 return $parser->expression(0);
1726             }
1727              
1728             # path::to::name
1729 69         95 my @parts;
1730 69         132 push @parts, $t;
1731 69         174 $parser->advance();
1732              
1733 69         100 while(1) {
1734 121         298 my $t = $parser->token;
1735              
1736 121 100       421 if($t->id eq "::") {
1737 52         118 $t = $parser->advance(); # "::"
1738              
1739 52 50       207 if($t->arity ne "name") {
1740 0         0 $parser->_unexpected("a name", $t);
1741             }
1742              
1743 52         83 push @parts, $t;
1744 52         109 $parser->advance();
1745             }
1746             else {
1747 69         166 last;
1748             }
1749             }
1750 69         170 return \@parts;
1751             }
1752              
1753             # NOTHING | { expression-list }
1754             sub localize_vars {
1755 1299     1299 0 2051 my($parser) = @_;
1756 1299 100       5073 if($parser->token->id eq "{") {
1757 13         27 $parser->advance();
1758 13         40 $parser->new_scope();
1759 13         41 my $vars = $parser->expression_list();
1760 13         39 $parser->pop_scope();
1761 13         28 $parser->advance("}");
1762 13         29 return $vars;
1763             }
1764 1286         2074 return undef;
1765             }
1766              
1767             sub std_cascade {
1768 64     64 0 157 my($parser, $symbol) = @_;
1769              
1770 64         104 my $base;
1771 64 100       337 if($parser->token->id ne "with") {
1772 57         220 $base = $parser->barename();
1773             }
1774              
1775 64         95 my $components;
1776 64 100       310 if($parser->token->id eq "with") {
1777 11         25 $parser->advance(); # "with"
1778              
1779 11         30 my @c = $parser->barename();
1780 11         51 while($parser->token->id eq ",") {
1781 2         5 $parser->advance(); # ","
1782 2         5 push @c, $parser->barename();
1783             }
1784 11         22 $components = \@c;
1785             }
1786              
1787 64         228 my $vars = $parser->localize_vars();
1788 64         235 my $stmt = $symbol->clone(
1789             arity => 'cascade',
1790             first => $base,
1791             second => $components,
1792             third => $vars,
1793             );
1794 64         1610 return $parser->finish_statement($stmt);
1795             }
1796              
1797             sub std_super {
1798 7     7 0 15 my($parser, $symbol) = @_;
1799 7         20 my $stmt = $symbol->clone(arity => 'super');
1800 7         155 return $parser->finish_statement($stmt);
1801             }
1802              
1803             sub std_next {
1804 5     5 0 9 my($parser, $symbol) = @_;
1805 5         16 my $stmt = $symbol->clone(arity => 'loop_control', id => 'next');
1806 5         113 return $parser->finish_statement($stmt);
1807             }
1808              
1809             sub std_last {
1810 7     7 0 13 my($parser, $symbol) = @_;
1811 7         23 my $stmt = $symbol->clone(arity => 'loop_control', id => 'last');
1812 7         157 return $parser->finish_statement($stmt);
1813             }
1814              
1815             # iterator elements
1816              
1817             sub bad_iterator_args {
1818 8     8 0 14 my($parser, $iterator) = @_;
1819 8         30 $parser->_error("Wrong number of arguments for $iterator." . $iterator->second);
1820             }
1821              
1822             sub iterator_index {
1823 16     16 0 144 my($parser, $iterator, @args) = @_;
1824 16 100       55 $parser->bad_iterator_args($iterator) if @args != 0;
1825             # $~iterator
1826 15         43 return $iterator;
1827             }
1828              
1829             sub iterator_count {
1830 10     10 0 20 my($parser, $iterator, @args) = @_;
1831 10 100       36 $parser->bad_iterator_args($iterator) if @args != 0;
1832             # $~iterator + 1
1833 9         36 return $parser->binary('+', $iterator, 1);
1834             }
1835              
1836             sub iterator_is_first {
1837 7     7 0 16 my($parser, $iterator, @args) = @_;
1838 7 100       24 $parser->bad_iterator_args($iterator) if @args != 0;
1839             # $~iterator == 0
1840 6         20 return $parser->binary('==', $iterator, 0);
1841             }
1842              
1843             sub iterator_is_last {
1844 4     4 0 10 my($parser, $iterator, @args) = @_;
1845 4 100       17 $parser->bad_iterator_args($iterator) if @args != 0;
1846             # $~iterator == $~iterator.max_index
1847 3         24 return $parser->binary('==', $iterator, $parser->iterator_max_index($iterator));
1848             }
1849              
1850             sub iterator_body {
1851 16     16 0 29 my($parser, $iterator, @args) = @_;
1852 16 50       50 $parser->bad_iterator_args($iterator) if @args != 0;
1853             # $~iterator.body
1854 16         49 return $iterator->clone(
1855             arity => 'iterator_body',
1856             );
1857             }
1858              
1859             sub iterator_size {
1860 3     3 0 10 my($parser, $iterator, @args) = @_;
1861 3 100       14 $parser->bad_iterator_args($iterator) if @args != 0;
1862             # $~iterator.max_index + 1
1863 2         8 return $parser->binary('+', $parser->iterator_max_index($iterator), 1);
1864             }
1865              
1866             sub iterator_max_index {
1867 8     8 0 15 my($parser, $iterator, @args) = @_;
1868 8 100       33 $parser->bad_iterator_args($iterator) if @args != 0;
1869             # __builtin_max_index($~iterator.body)
1870 7         20 return $parser->symbol('max_index')->clone(
1871             arity => 'unary',
1872             first => $parser->iterator_body($iterator),
1873             );
1874             }
1875              
1876             sub _iterator_peek {
1877 6     6   10 my($parser, $iterator, $pos) = @_;
1878             # $~iterator.body[ $~iterator.index + $pos ]
1879 6         18 return $parser->binary('[',
1880             $parser->iterator_body($iterator),
1881             $parser->binary('+', $parser->iterator_index($iterator), $pos),
1882             );
1883             }
1884              
1885             sub iterator_peek_next {
1886 3     3 0 6 my($parser, $iterator, @args) = @_;
1887 3 50       12 $parser->bad_iterator_args($iterator) if @args != 0;
1888 3         22 return $parser->_iterator_peek($iterator, +1);
1889             }
1890              
1891             sub iterator_peek_prev {
1892 5     5 0 12 my($parser, $iterator, @args) = @_;
1893 5 100       23 $parser->bad_iterator_args($iterator) if @args != 0;
1894             # $~iterator.is_first ? nil :
1895 3         9 return $parser->symbol('?')->clone(
1896             arity => 'if',
1897             first => $parser->iterator_is_first($iterator),
1898             second => [$parser->nil],
1899             third => [$parser->_iterator_peek($iterator, -1)],
1900             );
1901             }
1902              
1903             sub iterator_cycle {
1904 6     6 0 15 my($parser, $iterator, @args) = @_;
1905 6 50       16 $parser->bad_iterator_args($iterator) if @args < 2;
1906             # $iterator.cycle("foo", "bar", "baz") makes:
1907             # ($tmp = $~iterator % n) == 0 ? "foo"
1908             # : $tmp == 1 ? "bar"
1909             # : "baz"
1910 6         16 $parser->new_scope();
1911              
1912 6         16 my $mod = $parser->binary('%', $iterator, scalar @args);
1913              
1914             # for the second time
1915 6         127 my $tmp = $parser->symbol('($cycle)')->clone(arity => 'name');
1916              
1917             # for the first time
1918 6         114 my $cond = $iterator->clone(
1919             arity => 'constant',
1920             first => $tmp,
1921             second => $mod,
1922             );
1923              
1924 6         121 my $parent = $iterator->clone(
1925             arity => 'if',
1926             first => $parser->binary('==', $cond, 0),
1927             second => [ $args[0] ],
1928             );
1929 6         121 my $child = $parent;
1930              
1931 6         10 my $last = pop @args;
1932 6         21 for(my $i = 1; $i < @args; $i++) {
1933 4         17 my $nth = $iterator->clone(
1934             arity => 'if',
1935             id => "$iterator.cycle: $i",
1936             first => $parser->binary('==', $tmp, $i),
1937             second => [$args[$i]],
1938             );
1939              
1940 4         101 $child->third([$nth]);
1941 4         16 $child = $nth;
1942             }
1943 6         18 $child->third([$last]);
1944              
1945 6         14 $parser->pop_scope();
1946 6         18 return $parent;
1947             }
1948              
1949             # utils
1950              
1951             sub make_alias { # alas(from => to)
1952 3260     3260 0 10460 my($parser, $from, $to) = @_;
1953              
1954 3260         12482 my $stash = $parser->symbol_table;
1955 3260 50       14922 if(exists $parser->symbol_table->{$to}) {
1956             Carp::confess(
1957             "Cannot make an alias to an existing symbol ($from => $to / "
1958 0         0 . p($parser->symbol_table->{$to}) .")");
1959             }
1960              
1961             # make a snapshot
1962 3260         11419 return $stash->{$to} = $parser->symbol($from)->clone(
1963             value => $to, # real id
1964             );
1965             }
1966              
1967             sub not_supported {
1968 2     2 0 3 my($parser, $symbol) = @_;
1969 2         52 $parser->_error("'$symbol' is not supported");
1970             }
1971              
1972             sub _unexpected {
1973 13     13   24 my($parser, $expected, $got) = @_;
1974 13 100 66     161 if(defined($got) && $got ne ";") {
1975 12 100       32 if($got eq '(end)') {
1976 2         12 $parser->_error("Expected $expected, but reached EOF");
1977             }
1978             else {
1979 10         35 $parser->_error("Expected $expected, but got " . neat("$got"));
1980             }
1981             }
1982             else {
1983 1         5 $parser->_error("Expected $expected");
1984             }
1985             }
1986              
1987             sub _error {
1988 49     49   99 my($parser, $message, $near, $line) = @_;
1989              
1990 49   100     330 $near ||= $parser->near_token || ";";
      66        
1991 49 100 100     215 if($near ne ";" && $message !~ /\b \Q$near\E \b/xms) {
1992 39         117 $message .= ", near $near";
1993             }
1994 49   66     557 die $parser->make_error($message . ", while parsing templates",
1995             $parser->file, $line || $parser->line);
1996             }
1997              
1998 172     172   1675 no Mouse;
  172         351  
  172         1387  
1999             __PACKAGE__->meta->make_immutable;
2000             __END__