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 175     175   153362 use Mouse;
  175         78413  
  175         727  
3              
4 175     175   35459 use Scalar::Util ();
  175         227  
  175         2205  
5              
6 175     175   55302 use Text::Xslate::Symbol;
  175         12074  
  175         5945  
7 175         22489 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 175     175   908 );
  175         189  
16              
17 175     175   730 use constant _DUMP_PROTO => scalar($DEBUG =~ /\b dump=proto \b/xmsi);
  175         192  
  175         10341  
18 175     175   615 use constant _DUMP_TOKEN => scalar($DEBUG =~ /\b dump=token \b/xmsi);
  175         202  
  175         1252860  
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   18651 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   3925 sub _build_line_start { ':' }
141              
142             has tag_start => (
143             is => 'ro',
144             isa => 'Str',
145             builder => '_build_tag_start',
146             );
147 177     177   3633 sub _build_tag_start { '<:' }
148              
149             has tag_end => (
150             is => 'ro',
151             isa => 'Str',
152             builder => '_build_tag_end',
153             );
154 177     177   3809 sub _build_tag_end { ':>' }
155              
156             has comment_pattern => (
157             is => 'ro',
158             isa => 'RegexpRef',
159             builder => '_build_comment_pattern',
160             );
161 241     241   4080 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   3568 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 3479     3479 0 19337 my($parser, $input, %args) = @_;
204              
205 3479   100     10470 local $parser->{file} = $args{file} || \$input;
206 3479   50     11728 local $parser->{line} = $args{line} || 1;
207 3479         4786 local $parser->{in_given} = 0;
208 3479         3874 local $parser->{scope} = [ map { +{ %{$_} } } @{ $parser->scope } ];
  3479         3376  
  3479         13415  
  3479         9978  
209 3479         3990 local $parser->{symbol_table} = { %{ $parser->symbol_table } };
  3479         118309  
210 3479         14809 local $parser->{near_token};
211 3479         4353 local $parser->{next_token};
212 3479         4246 local $parser->{token};
213 3479         4036 local $parser->{input};
214              
215 3479         7138 $parser->input( $parser->preprocess($input) );
216              
217 3474         6830 $parser->next_token( $parser->tokenize() );
218 3474         6437 $parser->advance();
219 3473         6568 my $ast = $parser->statements();
220              
221 3432 100       9853 if(my $input_pos = pos $parser->{input}) {
222 3429 100       8551 if($input_pos != length($parser->{input})) {
223 2         6 $parser->_error("Syntax error", $parser->token);
224             }
225             }
226              
227 3430         52563 return $ast;
228             }
229              
230             sub trim_code {
231 5223     5223 0 6103 my($parser, $s) = @_;
232              
233 5223         11211 $s =~ s/\A [ \t]+ //xms;
234 5223         14117 $s =~ s/ [ \t]+ \n?\z//xms;
235              
236 5223         9190 return $s;
237             }
238              
239             sub auto_chomp {
240 10376     10376 0 10136 my($parser, $tokens_ref, $i, $s_ref) = @_;
241              
242 10376         7997 my $p;
243 10376         8695 my $nl = 0;
244              
245             # postchomp
246 10376 100 100     30223 if($i >= 1
247             and ($p = $tokens_ref->[$i-1])->[0] eq 'postchomp') {
248             # [ CODE ][*][ TEXT ]
249             # <: ... -:> \nfoobar
250             # ^^^^
251 391         267 ${$s_ref} =~ s/\A [ \t]* (\n)//xms;
  391         1118  
252 391 100       880 if($1) {
253 386         332 $nl++;
254             }
255             }
256              
257             # prechomp
258 10376 100 100     9433 if(($i+1) < @{$tokens_ref}
  10376 100 100     32581  
      66        
      100        
259             and ($p = $tokens_ref->[$i+1])->[0] eq 'prechomp') {
260 51 100       38 if(${$s_ref} !~ / [^ \t] /xms) {
  51         114  
261             # HERE
262             # [ TEXT ][*][ CODE ]
263             # <:- ... :>
264             # ^^^^^^^^
265 34         32 ${$s_ref} = '';
  34         39  
266             }
267             else {
268             # HERE
269             # [ TEXT ][*][ CODE ]
270             # \n<:- ... :>
271             # ^^
272 17         15 $nl += chomp ${$s_ref};
  17         42  
273             }
274             }
275 10325         36841 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         18 $p->[1] = '';
284 16         15 $nl += (${$s_ref} =~ s/\n\z//xms);
  16         32  
285             }
286 10376         14687 return $nl;
287             }
288              
289             # split templates by tags before tokenizing
290             sub split :method {
291 3479     3479 0 3854 my $parser = shift;
292 3479         5415 local($_) = @_;
293              
294 3479         4074 my @tokens;
295              
296 3479         7101 my $line_start = $parser->line_start;
297 3479         5796 my $tag_start = $parser->tag_start;
298 3479         6349 my $tag_end = $parser->tag_end;
299              
300 3479   66     29798 my $lex_line_code = defined($line_start)
301             && qr/\A ^ [ \t]* \Q$line_start\E ([^\n]* \n?) /xms;
302              
303 3479         12899 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 3479         12466 my $lex_text = qr/\A ( [^\n]*? (?: \n | (?= \Q$tag_start\E ) | \z ) ) /xms;
308              
309 3479         6916 my $lex_comment = $parser->comment_pattern;
310 3479         18772 my $lex_code = qr/(?: $lex_comment | $CODE )/xms;
311              
312 3479         4209 my $in_tag = 0;
313              
314 3479         7119 while($_ ne '') {
315 18288 100 100     2649773 if($in_tag) {
    100 66        
    100 100        
    50          
316 2671         2949 my $start = 0;
317 2671         2902 my $pos;
318 2671         7647 while( ($pos = index $_, $tag_end, $start) >= 0 ) {
319 2670         5583 my $code = substr $_, 0, $pos;
320 2670         30780 $code =~ s/$lex_code//xmsg;
321 2670 100       5677 if(length($code) == 0) {
322 2667         4960 last;
323             }
324 3         7 $start = $pos + 1;
325             }
326              
327 2671 100       4382 if($pos >= 0) {
328 2667         6155 my $code = substr $_, 0, $pos, '';
329 2667         11249 $code =~ s/($CHOMP_FLAGS?) \z//xmso;
330 2667         4357 my $chomp = $1;
331              
332 2667 50       11001 s/\A \Q$tag_end\E //xms or die "Oops!";
333              
334 2667         5593 push @tokens, [ code => $code ];
335 2667 100       4797 if($chomp) {
336 393         574 push @tokens, [ postchomp => $chomp ];
337             }
338 2667         8537 $in_tag = 0;
339             }
340             else {
341 4         6 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 2561         8019 push @tokens, [ code => $1 ];
349             }
350             elsif(s/$lex_tag_start//xms) {
351 2672         3266 $in_tag = 1;
352              
353 2672         4377 my $chomp = $1;
354 2672 100       8390 if($chomp) {
355 60         195 push @tokens, [ prechomp => $chomp ];
356             }
357             }
358             elsif(s/$lex_text//xms) {
359 10384         40540 push @tokens, [ text => $1 ];
360             }
361             else {
362 0         0 confess "Oops: Unreached code, near" . p($_);
363             }
364             }
365              
366 3479 100       6194 if($in_tag) {
367             # calculate line number
368 5         8 my $orig_src = $_[0];
369 5         17 substr $orig_src, -length($_), length($_), '';
370 5         9 my $line = ($orig_src =~ tr/\n/\n/);
371 5         26 $parser->_error("Malformed templates detected",
372             neat((split /\n/, $_)[0]), ++$line,
373             );
374             }
375             #p(\@tokens);
376 3474         13389 return \@tokens;
377             }
378              
379             sub preprocess {
380 3479     3479 0 4634 my($parser, $input) = @_;
381              
382             # tokenization
383              
384 3479         6077 my $tokens_ref = $parser->split($input);
385 3474         4289 my $code = '';
386              
387 3474         7575 my $shortcut_table = $parser->shortcut_table;
388 3474         6806 my $shortcut = join('|', map{ quotemeta } keys %shortcut_table);
  3474         9826  
389 3474         10888 my $shortcut_rx = qr/\A ($shortcut)/xms;
390              
391 3474         4822 for(my $i = 0; $i < @{$tokens_ref}; $i++) {
  19530         35964  
392 16056         12861 my($type, $s) = @{ $tokens_ref->[$i] };
  16056         24651  
393              
394 16056 100       24461 if($type eq 'text') {
    100          
    100          
    50          
395 10376         15076 my $nl = $parser->auto_chomp($tokens_ref, $i, \$s);
396              
397 10376         14292 $s =~ s/(["\\])/\\$1/gxms; # " for poor editors
398              
399             # $s may have single new line
400 10376         19403 $nl += ($s =~ s/\n/\\n/xms);
401              
402 10376         16433 $code .= qq{print_raw "$s";}; # must set even if $s is empty
403 10376 100       25410 $code .= qq{\n} if $nl > 0;
404             }
405             elsif($type eq 'code') {
406             # shortcut commands
407 5227 50       18351 $s =~ s/$shortcut_rx/$shortcut_table->{$1}/xms
408             if $shortcut;
409              
410 5227         9376 $s = $parser->trim_code($s);
411              
412 5227 100       16098 if($s =~ /\A \s* [}] \s* \z/xms){
    100          
413 548         716 $code .= $s;
414             }
415             elsif($s =~ s/\n\z//xms) {
416 2032         3946 $code .= qq{$s\n};
417             }
418             else {
419 2647         9224 $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 3474         3456 print STDOUT $code, "\n" if _DUMP_PROTO;
433 3474         18154 return $code;
434             }
435              
436             sub BUILD {
437 241     241 1 1433 my($parser) = @_;
438 241         2307 $parser->_init_basic_symbols();
439 241         1852 $parser->init_symbols();
440 241         4629 return;
441             }
442              
443             # The grammer
444              
445             sub _init_basic_symbols {
446 241     241   1312 my($parser) = @_;
447              
448 241         2075 $parser->symbol('(end)')->is_block_end(1); # EOF
449              
450             # prototypes of value symbols
451 241         1545 foreach my $type (qw(name variable literal)) {
452 723         4442 my $s = $parser->symbol("($type)");
453 723         4437 $s->arity($type);
454 723         10889 $s->set_nud( $parser->can("nud_$type") );
455             }
456              
457             # common separators
458 241         1595 $parser->symbol(';')->set_nud(\&nud_separator);
459 241         1929 $parser->define_pair('(' => ')');
460 241         1469 $parser->define_pair('{' => '}');
461 241         1407 $parser->define_pair('[' => ']');
462 241         1417 $parser->symbol(',') ->is_comma(1);
463 241         1504 $parser->symbol('=>') ->is_comma(1);
464              
465             # common commands
466 241         1442 $parser->symbol('print') ->set_std(\&std_print);
467 241         1466 $parser->symbol('print_raw')->set_std(\&std_print);
468              
469             # special literals
470 241         2017 $parser->define_literal(nil => undef);
471 241         1405 $parser->define_literal(true => 1);
472 241         1447 $parser->define_literal(false => 0);
473              
474             # special tokens
475 241         1415 $parser->symbol('__FILE__')->set_nud(\&nud_current_file);
476 241         1559 $parser->symbol('__LINE__')->set_nud(\&nud_current_line);
477 241         1508 $parser->symbol('__ROOT__')->set_nud(\&nud_current_vars);
478              
479 241         2169 return;
480             }
481              
482             sub init_basic_operators {
483 241     241 0 1283 my($parser) = @_;
484              
485             # define operator precedence
486              
487 241         2151 $parser->prefix('{', 256, \&nud_brace);
488 241         1563 $parser->prefix('[', 256, \&nud_brace);
489              
490 241         2076 $parser->infix('(', 256, \&led_call);
491 241         1962 $parser->infix('.', 256, \&led_dot);
492 241         1781 $parser->infix('[', 256, \&led_fetch);
493              
494 241         2481 $parser->prefix('(', 256, \&nud_paren);
495              
496 241         1800 $parser->prefix('!', 200)->is_logical(1);
497 241         1855 $parser->prefix('+', 200);
498 241         1456 $parser->prefix('-', 200);
499 241         1534 $parser->prefix('+^', 200); # numeric bitwise negate
500              
501 241         1415 $parser->infix('*', 190);
502 241         1496 $parser->infix('/', 190);
503 241         1441 $parser->infix('%', 190);
504 241         1441 $parser->infix('x', 190);
505 241         1440 $parser->infix('+&', 190); # numeric bitwise and
506              
507 241         1411 $parser->infix('+', 180);
508 241         1413 $parser->infix('-', 180);
509 241         1386 $parser->infix('~', 180); # connect
510 241         1381 $parser->infix('+|', 180); # numeric bitwise or
511 241         1379 $parser->infix('+^', 180); # numeric bitwise xor
512              
513              
514 241         1473 $parser->prefix('defined', 170, \&nud_defined); # named unary operator
515              
516 241         1481 $parser->infix('<', 160)->is_logical(1);
517 241         1460 $parser->infix('<=', 160)->is_logical(1);
518 241         1398 $parser->infix('>', 160)->is_logical(1);
519 241         1728 $parser->infix('>=', 160)->is_logical(1);
520              
521 241         1377 $parser->infix('==', 150)->is_logical(1);
522 241         1459 $parser->infix('!=', 150)->is_logical(1);
523 241         1391 $parser->infix('<=>', 150);
524 241         1479 $parser->infix('cmp', 150);
525 241         1447 $parser->infix('~~', 150);
526              
527 241         1512 $parser->infix('|', 140, \&led_pipe);
528              
529 241         1407 $parser->infix('&&', 130)->is_logical(1);
530              
531 241         1494 $parser->infix('||', 120)->is_logical(1);
532 241         1469 $parser->infix('//', 120)->is_logical(1);
533 241         1442 $parser->infix('min', 120);
534 241         1421 $parser->infix('max', 120);
535              
536 241         1523 $parser->infix('..', 110, \&led_range);
537              
538 241         1483 $parser->symbol(':');
539 241         2116 $parser->infixr('?', 100, \&led_ternary);
540              
541 241         2553 $parser->assignment('=', 90);
542 241         1489 $parser->assignment('+=', 90);
543 241         1555 $parser->assignment('-=', 90);
544 241         1466 $parser->assignment('*=', 90);
545 241         1504 $parser->assignment('/=', 90);
546 241         1620 $parser->assignment('%=', 90);
547 241         1514 $parser->assignment('~=', 90);
548 241         1388 $parser->assignment('&&=', 90);
549 241         1634 $parser->assignment('||=', 90);
550 241         1487 $parser->assignment('//=', 90);
551              
552 241         2075 $parser->make_alias('!' => 'not')->ubp(70);
553 241         2587 $parser->make_alias('&&' => 'and')->lbp(60);
554 241         1630 $parser->make_alias('||' => 'or') ->lbp(50);
555 241         2325 return;
556             }
557              
558             sub init_symbols {
559 182     182 0 1233 my($parser) = @_;
560 182         1216 my $s;
561              
562             # syntax specific separators
563 182         1404 $parser->symbol('{');
564 182         1391 $parser->symbol('}')->is_block_end(1); # block end
565 182         1311 $parser->symbol('->');
566 182         1328 $parser->symbol('else');
567 182         1267 $parser->symbol('with');
568 182         1308 $parser->symbol('::');
569              
570             # operators
571 182         1686 $parser->init_basic_operators();
572              
573             # statements
574 182         1313 $s = $parser->symbol('if');
575 182         1470 $s->set_std(\&std_if);
576 182         1625 $s->can_be_modifier(1);
577              
578 182         1293 $parser->symbol('for') ->set_std(\&std_for);
579 182         1308 $parser->symbol('while' ) ->set_std(\&std_while);
580 182         1279 $parser->symbol('given') ->set_std(\&std_given);
581 182         1280 $parser->symbol('when') ->set_std(\&std_when);
582 182         1325 $parser->symbol('default') ->set_std(\&std_when);
583              
584 182         1294 $parser->symbol('include') ->set_std(\&std_include);
585              
586 182         1581 $parser->symbol('last') ->set_std(\&std_last);
587 182         1259 $parser->symbol('next') ->set_std(\&std_next);
588              
589             # macros
590              
591 182         1265 $parser->symbol('cascade') ->set_std(\&std_cascade);
592 182         1265 $parser->symbol('macro') ->set_std(\&std_proc);
593 182         1271 $parser->symbol('around') ->set_std(\&std_proc);
594 182         1305 $parser->symbol('before') ->set_std(\&std_proc);
595 182         1263 $parser->symbol('after') ->set_std(\&std_proc);
596 182         1304 $parser->symbol('block') ->set_std(\&std_macro_block);
597 182         1259 $parser->symbol('super') ->set_std(\&std_super);
598 182         1252 $parser->symbol('override') ->set_std(\&std_override);
599              
600 182         1286 $parser->symbol('->') ->set_nud(\&nud_lambda);
601              
602             # lexical variables/constants stuff
603 182         1446 $parser->symbol('constant')->set_nud(\&nud_constant);
604 182         1612 $parser->symbol('my' )->set_nud(\&nud_constant);
605              
606 182         2193 return;
607             }
608              
609             sub _build_iterator_element {
610             return {
611 4     4   93 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 52983     52983 0 163312 my($parser, $id, $lbp) = @_;
627              
628 52983         178242 my $stash = $parser->symbol_table;
629 52983         165138 my $s = $stash->{$id};
630 52983 100       176122 if(defined $s) {
631 25265 100       61488 if(defined $lbp) {
632 1205         16317 $s->lbp($lbp);
633             }
634             }
635             else { # create a new symbol
636 27718   100     283527 $s = $parser->symbol_class->new(id => $id, lbp => $lbp || 0);
637 27718         273308 $stash->{$id} = $s;
638             }
639              
640 52983         331759 return $s;
641             }
642              
643             sub define_pair {
644 723     723 0 3675 my($parser, $left, $right) = @_;
645 723         3786 $parser->symbol($left) ->counterpart($right);
646 723         3885 $parser->symbol($right)->counterpart($left);
647 723         6237 return;
648             }
649              
650             # the low-level tokenizer. Don't use it directly, use advance() instead.
651             sub tokenize {
652 64703     64703 0 56962 my($parser) = @_;
653              
654 64703         93428 local *_ = \$parser->{input};
655              
656 64703         82597 my $comment_rx = $parser->comment_pattern;
657 64703         80973 my $id_rx = $parser->identity_pattern;
658 64703         51179 my $count = 0;
659             TRY: {
660 64703         52753 /\G (\s*) /xmsgc;
  64749         136663  
661 64749         101015 $count += ( $1 =~ tr/\n/\n/);
662 64749         91326 $parser->following_newline( $count );
663              
664 64749 100       414404 if(/\G $comment_rx /xmsgc) {
    100          
    100          
    100          
    50          
665 46         117 redo TRY; # retry
666             }
667             elsif(/\G ($id_rx)/xmsgc){
668 19483         79145 return [ name => $1 ];
669             }
670             elsif(/\G ($NUMBER | $STRING)/xmsogc){
671 17593         67032 return [ literal => $1 ];
672             }
673             elsif(/\G ($OPERATOR_TOKEN)/xmsogc){
674 24190         89089 return [ operator => $1 ];
675             }
676             elsif(/\G (\S+)/xmsgc) {
677 0         0 Carp::confess("Oops: Unexpected token '$1'");
678             }
679             else { # empty
680 3437         12882 return [ special => '(end)' ];
681             }
682             }
683             }
684              
685             sub next_token_is {
686 19522     19522 0 20920 my($parser, $token) = @_;
687 19522         74775 return $parser->next_token->[1] eq $token;
688             }
689              
690             # the high-level tokenizer
691             sub advance {
692 64674     64674 0 61861 my($parser, $expect) = @_;
693              
694 64674         77375 my $t = $parser->token;
695 64674 100 100     113976 if(defined($expect) && $t->id ne $expect) {
696 7         20 $parser->_unexpected(neat($expect), $t);
697             }
698              
699 64667         84830 $parser->near_token($t);
700              
701 64667         156766 my $stash = $parser->symbol_table;
702              
703 64667         79828 $t = $parser->next_token;
704              
705 64667 100       108411 if($t->[0] eq 'special') {
706 3438         11690 return $parser->token( $stash->{ $t->[1] } );
707             }
708 61229         122625 $parser->statement_is_finished( $parser->following_newline != 0 );
709 61229         131046 my $line = $parser->line( $parser->line + $parser->following_newline );
710              
711 61229         79712 $parser->next_token( $parser->tokenize() );
712              
713 61229         54590 my($arity, $id) = @{$t};
  61229         94061  
714 61229 100 100     121572 if( $arity eq "name" && $parser->next_token_is("=>") ) {
715 63         58 $arity = "literal";
716             }
717              
718 61229         48962 print STDOUT "[$arity => $id] #$line\n" if _DUMP_TOKEN;
719              
720 61229         46049 my $symbol;
721 61229 100       90358 if($arity eq "literal") {
    100          
722 17655         26035 $symbol = $parser->symbol('(literal)')->clone(
723             id => $id,
724             value => $parser->parse_literal($id)
725             );
726             }
727             elsif($arity eq "operator") {
728 24161         28625 $symbol = $stash->{$id};
729 24161 100       34706 if(not defined $symbol) {
730 3         8 $parser->_error("Unknown operator '$id'");
731             }
732 24158         47094 $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 19413         28126 $symbol = $parser->find_or_create($id);
740             }
741              
742 61226         559053 $symbol->line($line);
743 61226         152772 return $parser->token($symbol);
744             }
745              
746             sub parse_literal {
747 17655     17655 0 16630 my($parser, $literal) = @_;
748 17655         37286 return literal_to_value($literal);
749             }
750              
751             sub nud_name {
752 341     341 0 324 my($parser, $symbol) = @_;
753 341         607 return $symbol->clone(
754             arity => 'name',
755             );
756             }
757             sub nud_variable {
758 2807     2807 0 3351 my($parser, $symbol) = @_;
759 2807         5388 return $symbol->clone(
760             arity => 'variable',
761             );
762             }
763             sub nud_literal {
764 17634     17634 0 15463 my($parser, $symbol) = @_;
765 17634         27224 return $symbol->clone(
766             arity => 'literal',
767             );
768             }
769              
770             sub default_nud {
771 377     377 0 317 my($parser, $symbol) = @_;
772 377         604 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 21921     21921 0 19572 my($parser, $rbp) = @_;
793              
794 21921         26490 my $t = $parser->token;
795              
796 21921         27265 $parser->advance();
797              
798 21921         38853 my $left = $t->nud($parser);
799              
800 21906         297371 while($rbp < $parser->token->lbp) {
801 1937         5213 $t = $parser->token;
802 1937         3165 $parser->advance();
803 1937         3677 $left = $t->led($parser, $left);
804             }
805              
806 21888         54252 return $left;
807             }
808              
809             sub expression_list {
810 12209     12209 0 11829 my($parser) = @_;
811 12209         11692 my @list;
812 12209         11376 while(1) {
813 17519 100       40821 if($parser->token->is_value) {
814 17270         23927 push @list, $parser->expression(0);
815             }
816              
817 17519 100       40349 if(!$parser->token->is_comma) {
818 12209         17315 last;
819             }
820              
821 5310         5910 $parser->advance(); # comma
822             }
823 12209         23821 return \@list;
824             }
825              
826             # for left associative infix operators
827             sub led_infix {
828 877     877 0 785 my($parser, $symbol, $left) = @_;
829 877         1856 return $parser->binary( $symbol, $left, $parser->expression($symbol->lbp) );
830             }
831              
832             sub infix {
833 6989     6989 0 34356 my($parser, $id, $bp, $led) = @_;
834              
835 6989         34835 my $symbol = $parser->symbol($id, $bp);
836 6989   100     47528 $symbol->set_led($led || \&led_infix);
837 6989         63232 return $symbol;
838             }
839              
840             # for right associative infix operators
841             sub led_infixr {
842 26     26 0 34 my($parser, $symbol, $left) = @_;
843 26         95 return $parser->binary( $symbol, $left, $parser->expression($symbol->lbp - 1) );
844             }
845              
846             sub infixr {
847 241     241 0 1617 my($parser, $id, $bp, $led) = @_;
848              
849 241         2871 my $symbol = $parser->symbol($id, $bp);
850 241   50     2003 $symbol->set_led($led || \&led_infixr);
851 241         2274 return $symbol;
852             }
853              
854             # for prefix operators
855             sub prefix {
856 1928     1928 0 9692 my($parser, $id, $bp, $nud) = @_;
857              
858 1928         10167 my $symbol = $parser->symbol($id);
859 1928         10489 $symbol->ubp($bp);
860 1928   100     23275 $symbol->set_nud($nud || \&nud_prefix);
861 1928         17674 return $symbol;
862             }
863              
864             sub nud_prefix {
865 51     51 0 58 my($parser, $symbol) = @_;
866 51         150 my $un = $symbol->clone(arity => 'unary');
867 51         704 $parser->reserve($un);
868 51         134 $un->first($parser->expression($symbol->ubp));
869 50         62 return $un;
870             }
871              
872             sub led_assignment {
873 11     11 0 10 my($parser, $symbol, $left) = @_;
874              
875 11         40 $parser->_error("Assignment ($symbol) is forbidden", $left);
876             }
877              
878             sub assignment {
879 1820     1820 0 12222 my($parser, $id, $bp) = @_;
880              
881 1820         13207 $parser->symbol($id, $bp)->set_led(\&led_assignment);
882 1820         20624 return;
883             }
884              
885             # the ternary is a right associative operator
886             sub led_ternary {
887 115     115 0 118 my($parser, $symbol, $left) = @_;
888              
889 115         213 my $if = $symbol->clone(arity => 'if');
890              
891 115         1289 $if->first($left);
892 115         311 $if->second([$parser->expression( $symbol->lbp - 1 )]);
893 113         189 $parser->advance(":");
894 113         333 $if->third([$parser->expression( $symbol->lbp - 1 )]);
895 113         336 return $if;
896             }
897              
898             sub is_valid_field {
899 447     447 0 366 my($parser, $token) = @_;
900 447         768 my $arity = $token->arity;
901              
902 447 100       707 if($arity eq "name") {
    100          
903 409         920 return 1;
904             }
905             elsif($arity eq "literal") {
906 9         26 return is_int($token->id);
907             }
908 29         189 return 0;
909             }
910              
911             sub led_dot {
912 447     447 0 386 my($parser, $symbol, $left) = @_;
913              
914 447         591 my $t = $parser->token;
915 447 50       792 if(!$parser->is_valid_field($t)) {
916 0         0 $parser->_unexpected("a field name", $t);
917             }
918              
919 447         910 my $dot = $symbol->clone(
920             arity => "field",
921             first => $left,
922             second => $t->clone(arity => 'literal'),
923             );
924              
925 447         5128 $t = $parser->advance();
926 447 100       1092 if($t->id eq "(") {
927 230         369 $parser->advance(); # "("
928 230         407 $dot->third( $parser->expression_list() );
929 230         372 $parser->advance(")");
930 230         411 $dot->arity("methodcall");
931             }
932              
933 447         2048 return $dot;
934             }
935              
936             sub led_fetch { # $h[$field]
937 90     90 0 98 my($parser, $symbol, $left) = @_;
938              
939 90         198 my $fetch = $symbol->clone(
940             arity => "field",
941             first => $left,
942             second => $parser->expression(0),
943             );
944 90         1218 $parser->advance("]");
945 90         312 return $fetch;
946             }
947              
948             sub call {
949 194     194 0 242 my($parser, $function, @args) = @_;
950 194 100       406 if(not ref $function) {
951 4         5 $function = $parser->symbol('(name)')->clone(
952             arity => 'name',
953             id => $function,
954             line => $parser->line,
955             );
956             }
957              
958 194         333 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 283 my($parser, $symbol, $left) = @_;
967              
968 295         525 my $call = $symbol->clone(arity => 'call');
969 295         3412 $call->first($left);
970 295         512 $call->second( $parser->expression_list() );
971 295         436 $parser->advance(")");
972              
973 294         1007 return $call;
974             }
975              
976             sub led_pipe { # filter
977 64     64 0 64 my($parser, $symbol, $left) = @_;
978             # a | b -> b(a)
979 64         173 return $parser->call($parser->expression($symbol->lbp), $left);
980             }
981              
982             sub led_range { # x .. y
983 7     7 0 5 my($parser, $symbol, $left) = @_;
984 7         12 return $symbol->clone(
985             arity => 'range',
986             first => $left,
987             second => $parser->expression(0),
988             );
989             }
990              
991             sub nil {
992 26     26 0 80 my($parser) = @_;
993 26         49 return $parser->symbol('nil')->nud($parser);
994             }
995              
996             sub nud_defined {
997 23     23 0 24 my($parser, $symbol) = @_;
998 23         52 $parser->reserve( $symbol->clone() );
999             # prefix: is a syntactic sugar to $a != nil
1000 23         78 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 221 my($parser, $symbol) = @_;
1010 170         420 return $symbol->first;
1011             }
1012              
1013             sub define_literal { # special literals
1014 723     723 0 3628 my($parser, $id, $value) = @_;
1015              
1016 723         3840 my $symbol = $parser->symbol($id);
1017 723 100       5236 $symbol->first( $symbol->clone(
1018             arity => defined($value) ? 'literal' : 'nil',
1019             value => $value,
1020             ) );
1021 723         8434 $symbol->set_nud(\&nud_special);
1022 723         4096 $symbol->is_defined(1);
1023 723         6307 return $symbol;
1024             }
1025              
1026             sub new_scope {
1027 921     921 0 790 my($parser) = @_;
1028 921         703 push @{ $parser->scope }, {};
  921         2038  
1029 921         1035 return;
1030             }
1031              
1032             sub pop_scope {
1033 904     904 0 815 my($parser) = @_;
1034 904         641 pop @{ $parser->scope };
  904         1402  
1035 904         1620 return;
1036             }
1037              
1038             sub undefined_name {
1039 3651     3651 0 4415 my($parser, $name) = @_;
1040 3651 100       8749 if($name =~ /\A \$/xms) {
1041 2879         9000 return $parser->symbol_table->{'(variable)'}->clone(
1042             id => $name,
1043             );
1044             }
1045             else {
1046 772         2205 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 19472     19472 0 20442 my($parser, $name) = @_;
1054 19472         17108 my $s;
1055 19472         16686 foreach my $scope(reverse @{$parser->scope}){
  19472         44912  
1056 22671         24699 $s = $scope->{$name};
1057 22671 100       40268 if(defined $s) {
1058 6013         11684 return $s->clone();
1059             }
1060             }
1061 13459         25120 $s = $parser->symbol_table->{$name};
1062 13459 100       29374 return defined($s) ? $s : $parser->undefined_name($name);
1063             }
1064              
1065             sub reserve { # reserve a name to the scope
1066 13814     13814 0 13991 my($parser, $symbol) = @_;
1067 13814 100 100     60996 if($symbol->arity ne 'name' or $symbol->is_reserved) {
1068 13243         14069 return $symbol;
1069             }
1070              
1071 571         3061 my $top = $parser->scope->[-1];
1072 571         3026 my $t = $top->{$symbol->id};
1073 571 50       2980 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         3152 $top->{$symbol->id} = $symbol;
1082 571         3169 $symbol->is_reserved(1);
1083             #$symbol->scope($top);
1084 571         4578 return $symbol;
1085             }
1086              
1087             sub define { # define a name to the scope
1088 598     598 0 589 my($parser, $symbol) = @_;
1089 598         959 my $top = $parser->scope->[-1];
1090              
1091 598         988 my $t = $top->{$symbol->id};
1092 598 100       1003 if(defined $t) {
1093 1 50       5 $parser->_error($t->is_reserved ? "Already is_reserved: $t" : "Already defined: $t");
1094             }
1095              
1096 597         1139 $top->{$symbol->id} = $symbol;
1097              
1098 597         980 $symbol->is_defined(1);
1099 597         1113 $symbol->is_reserved(0);
1100 597         972 $symbol->remove_nud();
1101 597         780 $symbol->remove_led();
1102 597         704 $symbol->remove_std();
1103 597         821 $symbol->lbp(0);
1104             #$symbol->scope($top);
1105 597         685 return $symbol;
1106             }
1107              
1108             sub print {
1109 1246     1246 0 1512 my($parser, @args) = @_;
1110 1246         1948 return $parser->symbol('print')->clone(
1111             arity => 'print',
1112             first => \@args,
1113             line => $parser->line,
1114             );
1115             }
1116              
1117             sub binary {
1118 1008     1008 0 1113 my($parser, $symbol, $lhs, $rhs) = @_;
1119 1008 100       1855 if(!ref $symbol) {
1120             # operator
1121 109         163 $symbol = $parser->symbol($symbol);
1122             }
1123 1008 50       1524 if(!ref $lhs) {
1124             # literal
1125 0         0 $lhs = $parser->symbol('(literal)')->clone(
1126             id => $lhs,
1127             );
1128             }
1129 1008 100       1427 if(!ref $rhs) {
1130             # literal
1131 39         55 $rhs = $parser->symbol('(literal)')->clone(
1132             id => $rhs,
1133             );
1134             }
1135 1008         2240 return $symbol->clone(
1136             arity => 'binary',
1137             first => $lhs,
1138             second => $rhs,
1139             );
1140             }
1141              
1142             sub define_function {
1143 498     498 0 7984 my($parser, @names) = @_;
1144              
1145 498         1801 foreach my $name(@names) {
1146 6036         30213 my $s = $parser->symbol($name);
1147 6036         63603 $s->set_nud(\&nud_name);
1148 6036         33577 $s->is_defined(1);
1149             }
1150 498         4069 return;
1151             }
1152              
1153             sub finish_statement {
1154 14083     14083 0 14695 my($parser, $expr) = @_;
1155              
1156 14083         19451 my $t = $parser->token;
1157 14083 100       27965 if($t->can_be_modifier) {
1158 30         38 $parser->advance();
1159 30         74 $expr = $t->std($parser, $expr);
1160 30         44 $t = $parser->token;
1161             }
1162              
1163 14083 100 100     69531 if($t->is_block_end or $parser->statement_is_finished) {
    100          
1164             # noop
1165             }
1166             elsif($t->id eq ";") {
1167 12634         17659 $parser->advance();
1168             }
1169             else {
1170 4         21 $parser->_unexpected("a semicolon or block end", $t);
1171             }
1172 14077         82644 return $expr;
1173             }
1174              
1175             sub statement { # process one or more statements
1176 15349     15349 0 14979 my($parser) = @_;
1177 15349         20137 my $t = $parser->token;
1178              
1179 15349 100       32151 if($t->id eq ";"){
1180 448         585 $parser->advance(); # ";"
1181 448         1373 return;
1182             }
1183              
1184 14901 100       29391 if($t->has_std) { # is $t a statement?
1185 13652         19486 $parser->reserve($t);
1186 13652         17896 $parser->advance();
1187              
1188             # std() can return a list of nodes
1189 13652         25886 return $t->std($parser);
1190             }
1191              
1192 1249         2037 my $expr = $parser->auto_command( $parser->expression(0) );
1193 1223         15076 return $parser->finish_statement($expr);
1194             }
1195              
1196             sub auto_command {
1197 1223     1223 0 1239 my($parser, $expr) = @_;
1198 1223 100       2412 if($expr->is_statement) {
1199             # expressions can produce pure statements (e.g. assignment )
1200 82         116 return $expr;
1201             }
1202             else {
1203 1141         1953 return $parser->print($expr);
1204             }
1205             }
1206              
1207             sub statements { # process statements
1208 4340     4340 0 4644 my($parser) = @_;
1209 4340         4122 my @a;
1210              
1211 4340         13422 for(my $t = $parser->token; !$t->is_block_end; $t = $parser->token) {
1212 15299         23911 push @a, $parser->statement();
1213             }
1214              
1215 4289         8604 return \@a;
1216             }
1217              
1218             sub block {
1219 213     213 0 191 my($parser) = @_;
1220 213         312 $parser->new_scope();
1221 213         288 $parser->advance("{");
1222 213         334 my $a = $parser->statements();
1223 213         304 $parser->advance("}");
1224 212         302 $parser->pop_scope();
1225 212         397 return $a;
1226             }
1227              
1228             sub nud_paren {
1229 121     121 0 142 my($parser, $symbol) = @_;
1230 121         223 my $expr = $parser->expression(0);
1231 121         329 $parser->advance( $symbol->counterpart );
1232 121         169 return $expr;
1233             }
1234              
1235             # for object literals
1236             sub nud_brace {
1237 143     143 0 146 my($parser, $symbol) = @_;
1238              
1239 143         268 my $list = $parser->expression_list();
1240              
1241 143         338 $parser->advance($symbol->counterpart);
1242 143         299 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 55 my($parser, $symbol) = @_;
1252              
1253 55         95 my $iterator = $symbol->clone();
1254 55 100       692 if($parser->token->id eq ".") {
1255 51         77 $parser->advance();
1256              
1257 51         87 my $t = $parser->token;
1258 51 50       171 if(!any_in($t->arity, qw(variable name))) {
1259 0         0 $parser->_unexpected("a field name", $t);
1260             }
1261              
1262 51         355 my $generator = $parser->iterator_element->{$t->value};
1263 51 50       97 if(!$generator) {
1264 0         0 $parser->_error("Undefined iterator element: $t");
1265             }
1266              
1267 51         77 $parser->advance(); # element name
1268              
1269 51         49 my $args;
1270 51 100       171 if($parser->token->id eq "(") {
1271 15         27 $parser->advance();
1272 15         28 $args = $parser->expression_list();
1273 15         29 $parser->advance(")");
1274             }
1275              
1276 51         102 $iterator->second($t);
1277 51         51 return $generator->($parser, $iterator, @{$args});
  51         121  
1278             }
1279 4         5 return $iterator;
1280             }
1281              
1282             sub nud_constant {
1283 71     71 0 72 my($parser, $symbol) = @_;
1284 71         96 my $t = $parser->token;
1285              
1286 71 50       221 my $expect = $symbol->id eq 'constant' ? 'name'
    100          
1287             : $symbol->id eq 'my' ? 'variable'
1288             : die "Oops: $symbol";
1289              
1290 71 50       191 if($t->arity ne $expect) {
1291 0         0 $parser->_unexpected("a $expect", $t);
1292             }
1293 71         129 $parser->define($t)->arity("name");
1294              
1295 70         97 $parser->advance();
1296 70         99 $parser->advance("=");
1297              
1298 70         147 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 51 my($parser, $proto) = @_;
1309 56         92 my $name = $parser->symbol('(name)')->clone(
1310             id => sprintf('lambda@%s:%d', $parser->file, $lambda_id++),
1311             );
1312              
1313 56         687 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 36 my($parser, $symbol) = @_;
1324              
1325 39         66 my $pointy = $parser->lambda($symbol);
1326              
1327 39         510 $parser->new_scope();
1328 39         27 my @params;
1329 39 50       115 if($parser->token->id ne "{") { # has params
1330 39         76 my $paren = ($parser->token->id eq "(");
1331              
1332 39 50       49 $parser->advance("(") if $paren; # optional
1333              
1334 39         47 my $t = $parser->token;
1335 39         81 while($t->arity eq "variable") {
1336 54         55 push @params, $t;
1337 54         75 $parser->define($t);
1338              
1339 54         65 $t = $parser->advance();
1340 54 100       111 if($t->id eq ",") {
1341 15         17 $t = $parser->advance(); # ","
1342             }
1343             else {
1344 39         44 last;
1345             }
1346             }
1347              
1348 39 50       67 $parser->advance(")") if $paren;
1349             }
1350 39         100 $pointy->second( \@params );
1351              
1352 39         50 $parser->advance("{");
1353 39         66 $pointy->third($parser->statements());
1354 39         56 $parser->advance("}");
1355 39         59 $parser->pop_scope();
1356              
1357 39         71 return $symbol->clone(
1358             arity => 'lambda',
1359             first => $pointy,
1360             );
1361             }
1362              
1363             sub nud_current_file {
1364 1     1 0 2 my($self, $symbol) = @_;
1365 1         5 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 12 my($self, $symbol) = @_;
1374 14         42 return $symbol->clone(
1375             arity => 'literal',
1376             value => $symbol->line,
1377             );
1378             }
1379              
1380             sub nud_current_vars {
1381 5     5 0 6 my($self, $symbol) = @_;
1382 5         10 return $symbol->clone(
1383             arity => 'vars',
1384             );
1385             }
1386              
1387             sub nud_separator {
1388 4     4 0 11 my($self, $symbol) = @_;
1389 4         10 $self->_error("Invalid expression found", $symbol);
1390             }
1391              
1392             # -> VARS { STATEMENTS }
1393             # -> { STATEMENTS }
1394             # { STATEMENTS }
1395             sub pointy {
1396 438     438 0 483 my($parser, $pointy, $in_for) = @_;
1397              
1398 438         339 my @params;
1399              
1400 438         756 $parser->new_scope();
1401              
1402 438 100       1341 if($parser->token->id eq "->") {
1403 418         556 $parser->advance();
1404 418 100       1303 if($parser->token->id ne "{") {
1405 226         520 my $paren = ($parser->token->id eq "(");
1406              
1407 226 100       401 $parser->advance("(") if $paren;
1408              
1409 226         325 my $t = $parser->token;
1410 226         575 while($t->arity eq "variable") {
1411 232         304 push @params, $t;
1412 232         487 $parser->define($t);
1413              
1414 232 100       362 if($in_for) {
1415 150         329 $parser->define_iterator($t);
1416             }
1417              
1418 232         347 $t = $parser->advance();
1419              
1420 232 100       670 if($t->id eq ",") {
1421 7         11 $t = $parser->advance(); # ","
1422             }
1423             else {
1424 225         259 last;
1425             }
1426             }
1427              
1428 226 100       489 $parser->advance(")") if $paren;
1429             }
1430             }
1431 436         1007 $pointy->second( \@params );
1432              
1433 436         740 $parser->advance("{");
1434 434         781 $pointy->third($parser->statements());
1435 424         655 $parser->advance("}");
1436 424         859 $parser->pop_scope();
1437              
1438 424         425 return;
1439             }
1440              
1441             sub iterator_name {
1442 150     150 0 127 my($parser, $var) = @_;
1443             # $foo -> $~foo
1444 150         949 (my $it_name = $var->id) =~ s/\A (\$?) /${1}~/xms;
1445 150         397 return $it_name;
1446             }
1447              
1448             sub define_iterator {
1449 185     185 0 193 my($parser, $var) = @_;
1450              
1451 185         372 my $it = $parser->symbol( $parser->iterator_name($var) )->clone(
1452             arity => 'iterator',
1453             first => $var,
1454             );
1455 185         2483 $parser->define($it);
1456 185         924 $it->set_nud(\&nud_iterator);
1457 185         245 return $it;
1458             }
1459              
1460             sub std_for {
1461 150     150 0 165 my($parser, $symbol) = @_;
1462              
1463 150         292 my $proc = $symbol->clone(arity => 'for');
1464 150         1798 $proc->first( $parser->expression(0) );
1465 150         441 $parser->pointy($proc, 1);
1466              
1467             # for-else support
1468 140 100       1339 if($parser->token eq 'else') {
1469 5         11 $parser->advance();
1470 5         11 my $else = $parser->block();
1471 5         9 $proc = $symbol->clone( arity => 'for_else',
1472             first => $proc,
1473             second => $else,
1474             )
1475             }
1476 140         657 return $proc;
1477             }
1478              
1479             sub std_while {
1480 15     15 0 15 my($parser, $symbol) = @_;
1481              
1482 15         45 my $proc = $symbol->clone(arity => 'while');
1483 15         218 $proc->first( $parser->expression(0) );
1484 15         29 $parser->pointy($proc);
1485 15         50 return $proc;
1486             }
1487              
1488             # macro name -> { ... }
1489             sub std_proc {
1490 150     150 0 224 my($parser, $symbol) = @_;
1491              
1492 150         270 my $macro = $symbol->clone(arity => "proc");
1493 150         1805 my $name = $parser->token;
1494              
1495 150 50       450 if($name->arity ne "name") {
1496 0         0 $parser->_unexpected("a name", $name);
1497             }
1498              
1499 150         334 $parser->define_function($name->id);
1500 150         236 $macro->first($name);
1501 150         208 $parser->advance();
1502 150         298 $parser->pointy($macro);
1503 146         566 return $macro;
1504             }
1505              
1506             # block name -> { ... }
1507             # block name | filter -> { ... }
1508             sub std_macro_block {
1509 93     93 0 95 my($parser, $symbol) = @_;
1510              
1511 93         265 my $macro = $symbol->clone(arity => "proc");
1512 93         1016 my $name = $parser->token;
1513              
1514 93 50       250 if($name->arity ne "name") {
1515 0         0 $parser->_unexpected("a name", $name);
1516             }
1517              
1518             # auto filters
1519 93         83 my @filters;
1520 93         134 my $t = $parser->advance();
1521 93         287 while($t->id eq "|") {
1522 11         27 $t = $parser->advance();
1523              
1524 11 50       44 if($t->arity ne "name") {
1525 0         0 $parser->_unexpected("a name", $name);
1526             }
1527 11         17 my $filter = $t->clone();
1528 11         110 $t = $parser->advance();
1529              
1530 11         6 my $args;
1531 11 100       25 if($t->id eq "(") {
1532 2         4 $parser->advance();
1533 2         5 $args = $parser->expression_list();
1534 2         3 $t = $parser->advance(")");
1535             }
1536             push @filters, $args
1537 11 100       37 ? $parser->call($filter, @{$args})
  2         4  
1538             : $filter;
1539             }
1540              
1541 93         239 $parser->define_function($name->id);
1542 93         191 $macro->first($name);
1543 93         166 $parser->pointy($macro);
1544              
1545 93         298 my $call = $parser->call($macro->first);
1546 93 100       1273 if(@filters) {
1547 9         10 foreach my $filter(@filters) { # apply filters
1548 11         29 $call = $parser->call($filter, $call);
1549             }
1550             }
1551             # std() can return a list
1552 93         297 return( $macro, $parser->print($call) );
1553             }
1554              
1555             sub std_override { # synonym to 'around'
1556 6     6 0 9 my($parser, $symbol) = @_;
1557              
1558 6         16 return $parser->std_proc($symbol->clone(id => 'around'));
1559             }
1560              
1561             sub std_if {
1562 113     113 0 125 my($parser, $symbol, $expr) = @_;
1563              
1564 113         200 my $if = $symbol->clone(arity => "if");
1565              
1566 113         1424 $if->first( $parser->expression(0) );
1567              
1568 113 100       198 if(defined $expr) { # statement modifier
1569 13         28 $if->second([$expr]);
1570 13         25 return $if;
1571             }
1572              
1573 100         216 $if->second( $parser->block() );
1574              
1575 99         84 my $top_if = $if;
1576              
1577 99         145 my $t = $parser->token;
1578 99         252 while($t->id eq "elsif") {
1579 3         5 $parser->reserve($t);
1580 3         3 $parser->advance(); # "elsif"
1581              
1582 3         6 my $elsif = $t->clone(arity => "if");
1583 3         32 $elsif->first( $parser->expression(0) );
1584 3         8 $elsif->second( $parser->block() );
1585 3         7 $if->third([$elsif]);
1586 3         2 $if = $elsif;
1587 3         11 $t = $parser->token;
1588             }
1589              
1590 99 100       220 if($t->id eq "else") {
1591 56         83 $parser->reserve($t);
1592 56         72 $t = $parser->advance(); # "else"
1593              
1594 56 100       203 $if->third( $t->id eq "if"
1595             ? [$parser->statement()]
1596             : $parser->block());
1597             }
1598 99         475 return $top_if;
1599             }
1600              
1601             sub std_given {
1602 30     30 0 27 my($parser, $symbol) = @_;
1603              
1604 30         51 my $given = $symbol->clone(arity => 'given');
1605 30         368 $given->first( $parser->expression(0) );
1606              
1607 30         44 local $parser->{in_given} = 1;
1608 30         53 $parser->pointy($given);
1609              
1610 30 100 66     66 if(!(defined $given->second && @{$given->second})) { # if no topic vars
  30         90  
1611 14         22 $given->second([
1612             $parser->symbol('($_)')->clone(arity => 'variable' )
1613             ]);
1614             }
1615              
1616 30         193 $parser->build_given_body($given, "when");
1617 30         123 return $given;
1618             }
1619              
1620             # when/default
1621             sub std_when {
1622 60     60 0 42 my($parser, $symbol) = @_;
1623              
1624 60 50       150 if(!$parser->in_given) {
1625 0         0 $parser->_error("You cannot use $symbol blocks outside given blocks");
1626             }
1627 60         100 my $proc = $symbol->clone(arity => 'when');
1628 60 100       696 if($symbol->id eq "when") {
1629 31         118 $proc->first( $parser->expression(0) );
1630             }
1631 60         85 $proc->second( $parser->block() );
1632 60         207 return $proc;
1633             }
1634              
1635             sub _only_white_spaces {
1636 21     21   18 my($s) = @_;
1637 21   33     164 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 44 my($parser, $given, $expect) = @_;
1643 40         32 my($topic) = @{$given->second};
  40         84  
1644              
1645             # make if-elsif-else chain from given-when
1646 40         31 my $if;
1647             my $elsif;
1648 0         0 my $else;
1649 40         27 foreach my $when(@{$given->third}) {
  40         75  
1650 101 100       192 if($when->arity ne $expect) {
1651             # ignore white space
1652 22 100 66     47 if($when->id eq "print_raw"
1653 21         23 && !grep { !_only_white_spaces($_) } @{$when->first}) {
  21         30  
1654 21         23 next;
1655             }
1656 1         3 $parser->_unexpected("$expect blocks", $when);
1657             }
1658 79         93 $when->arity("if"); # change the arity
1659              
1660 79 100       136 if(defined(my $test = $when->first)) { # when
1661 43 100       79 if(!$test->is_logical) {
1662 31         50 $when->first( $parser->binary('~~', $topic, $test) );
1663             }
1664             }
1665             else { # default
1666 36         47 $when->first( $parser->symbol('true')->nud($parser) );
1667 36         37 $else = $when;
1668 36         44 next;
1669             }
1670              
1671 43 100       409 if(!defined $if) {
1672 35         26 $if = $when;
1673 35         38 $elsif = $when;
1674             }
1675             else {
1676 8         17 $elsif->third([$when]);
1677 8         9 $elsif = $when;
1678             }
1679             }
1680 39 100       59 if(defined $else) { # default
1681 36 100       46 if(defined $elsif) {
1682 33         57 $elsif->third([$else]);
1683             }
1684             else {
1685 3         4 $if = $else; # only default
1686             }
1687             }
1688 39 100       81 $given->third(defined $if ? [$if] : undef);
1689 39         71 return;
1690             }
1691              
1692             sub std_include {
1693 1253     1253 0 1055 my($parser, $symbol) = @_;
1694              
1695 1253         1617 my $arg = $parser->barename();
1696 1253         2020 my $vars = $parser->localize_vars();
1697 1253         2442 my $stmt = $symbol->clone(
1698             first => $arg,
1699             second => $vars,
1700             arity => 'include',
1701             );
1702 1253         16143 return $parser->finish_statement($stmt);
1703             }
1704              
1705             sub std_print {
1706 11511     11511 0 11613 my($parser, $symbol) = @_;
1707 11511         10205 my $args;
1708 11511 50       31596 if($parser->token->id ne ";") {
1709 11511         17608 $args = $parser->expression_list();
1710             }
1711 11511         22014 my $stmt = $symbol->clone(
1712             arity => 'print',
1713             first => $args,
1714             );
1715 11511         153197 return $parser->finish_statement($stmt);
1716             }
1717              
1718             # for cascade() and include()
1719             sub barename {
1720 1334     1334 0 1005 my($parser) = @_;
1721              
1722 1334         1655 my $t = $parser->token;
1723 1334 100 100     3403 if($t->arity ne 'name' or $t->is_defined) {
1724             # string literal for 'cascade', or any expression for 'include'
1725 1265         1713 return $parser->expression(0);
1726             }
1727              
1728             # path::to::name
1729 69         56 my @parts;
1730 69         86 push @parts, $t;
1731 69         108 $parser->advance();
1732              
1733 69         57 while(1) {
1734 121         182 my $t = $parser->token;
1735              
1736 121 100       266 if($t->id eq "::") {
1737 52         64 $t = $parser->advance(); # "::"
1738              
1739 52 50       128 if($t->arity ne "name") {
1740 0         0 $parser->_unexpected("a name", $t);
1741             }
1742              
1743 52         60 push @parts, $t;
1744 52         64 $parser->advance();
1745             }
1746             else {
1747 69         90 last;
1748             }
1749             }
1750 69         130 return \@parts;
1751             }
1752              
1753             # NOTHING | { expression-list }
1754             sub localize_vars {
1755 1300     1300 0 1185 my($parser) = @_;
1756 1300 100       2942 if($parser->token->id eq "{") {
1757 13         17 $parser->advance();
1758 13         23 $parser->new_scope();
1759 13         31 my $vars = $parser->expression_list();
1760 13         25 $parser->pop_scope();
1761 13         26 $parser->advance("}");
1762 13         18 return $vars;
1763             }
1764 1287         1210 return undef;
1765             }
1766              
1767             sub std_cascade {
1768 65     65 0 73 my($parser, $symbol) = @_;
1769              
1770 65         48 my $base;
1771 65 100       262 if($parser->token->id ne "with") {
1772 58         151 $base = $parser->barename();
1773             }
1774              
1775 65         60 my $components;
1776 65 100       185 if($parser->token->id eq "with") {
1777 11         17 $parser->advance(); # "with"
1778              
1779 11         23 my @c = $parser->barename();
1780 11         37 while($parser->token->id eq ",") {
1781 2         4 $parser->advance(); # ","
1782 2         5 push @c, $parser->barename();
1783             }
1784 11         14 $components = \@c;
1785             }
1786              
1787 65         163 my $vars = $parser->localize_vars();
1788 65         170 my $stmt = $symbol->clone(
1789             arity => 'cascade',
1790             first => $base,
1791             second => $components,
1792             third => $vars,
1793             );
1794 65         1071 return $parser->finish_statement($stmt);
1795             }
1796              
1797             sub std_super {
1798 7     7 0 9 my($parser, $symbol) = @_;
1799 7         19 my $stmt = $symbol->clone(arity => 'super');
1800 7         93 return $parser->finish_statement($stmt);
1801             }
1802              
1803             sub std_next {
1804 5     5 0 8 my($parser, $symbol) = @_;
1805 5         8 my $stmt = $symbol->clone(arity => 'loop_control', id => 'next');
1806 5         76 return $parser->finish_statement($stmt);
1807             }
1808              
1809             sub std_last {
1810 7     7 0 7 my($parser, $symbol) = @_;
1811 7         14 my $stmt = $symbol->clone(arity => 'loop_control', id => 'last');
1812 7         102 return $parser->finish_statement($stmt);
1813             }
1814              
1815             # iterator elements
1816              
1817             sub bad_iterator_args {
1818 8     8 0 13 my($parser, $iterator) = @_;
1819 8         37 $parser->_error("Wrong number of arguments for $iterator." . $iterator->second);
1820             }
1821              
1822             sub iterator_index {
1823 16     16 0 121 my($parser, $iterator, @args) = @_;
1824 16 100       47 $parser->bad_iterator_args($iterator) if @args != 0;
1825             # $~iterator
1826 15         38 return $iterator;
1827             }
1828              
1829             sub iterator_count {
1830 10     10 0 16 my($parser, $iterator, @args) = @_;
1831 10 100       31 $parser->bad_iterator_args($iterator) if @args != 0;
1832             # $~iterator + 1
1833 9         30 return $parser->binary('+', $iterator, 1);
1834             }
1835              
1836             sub iterator_is_first {
1837 7     7 0 11 my($parser, $iterator, @args) = @_;
1838 7 100       20 $parser->bad_iterator_args($iterator) if @args != 0;
1839             # $~iterator == 0
1840 6         16 return $parser->binary('==', $iterator, 0);
1841             }
1842              
1843             sub iterator_is_last {
1844 4     4 0 7 my($parser, $iterator, @args) = @_;
1845 4 100       16 $parser->bad_iterator_args($iterator) if @args != 0;
1846             # $~iterator == $~iterator.max_index
1847 3         19 return $parser->binary('==', $iterator, $parser->iterator_max_index($iterator));
1848             }
1849              
1850             sub iterator_body {
1851 16     16 0 21 my($parser, $iterator, @args) = @_;
1852 16 50       51 $parser->bad_iterator_args($iterator) if @args != 0;
1853             # $~iterator.body
1854 16         42 return $iterator->clone(
1855             arity => 'iterator_body',
1856             );
1857             }
1858              
1859             sub iterator_size {
1860 3     3 0 9 my($parser, $iterator, @args) = @_;
1861 3 100       15 $parser->bad_iterator_args($iterator) if @args != 0;
1862             # $~iterator.max_index + 1
1863 2         7 return $parser->binary('+', $parser->iterator_max_index($iterator), 1);
1864             }
1865              
1866             sub iterator_max_index {
1867 8     8 0 11 my($parser, $iterator, @args) = @_;
1868 8 100       18 $parser->bad_iterator_args($iterator) if @args != 0;
1869             # __builtin_max_index($~iterator.body)
1870 7         14 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   8 my($parser, $iterator, $pos) = @_;
1878             # $~iterator.body[ $~iterator.index + $pos ]
1879 6         14 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       10 $parser->bad_iterator_args($iterator) if @args != 0;
1888 3         17 return $parser->_iterator_peek($iterator, +1);
1889             }
1890              
1891             sub iterator_peek_prev {
1892 5     5 0 9 my($parser, $iterator, @args) = @_;
1893 5 100       19 $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 12 my($parser, $iterator, @args) = @_;
1905 6 50       17 $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         14 $parser->new_scope();
1911              
1912 6         16 my $mod = $parser->binary('%', $iterator, scalar @args);
1913              
1914             # for the second time
1915 6         103 my $tmp = $parser->symbol('($cycle)')->clone(arity => 'name');
1916              
1917             # for the first time
1918 6         77 my $cond = $iterator->clone(
1919             arity => 'constant',
1920             first => $tmp,
1921             second => $mod,
1922             );
1923              
1924 6         86 my $parent = $iterator->clone(
1925             arity => 'if',
1926             first => $parser->binary('==', $cond, 0),
1927             second => [ $args[0] ],
1928             );
1929 6         83 my $child = $parent;
1930              
1931 6         9 my $last = pop @args;
1932 6         21 for(my $i = 1; $i < @args; $i++) {
1933 4         13 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         59 $child->third([$nth]);
1941 4         10 $child = $nth;
1942             }
1943 6         21 $child->third([$last]);
1944              
1945 6         16 $parser->pop_scope();
1946 6         16 return $parent;
1947             }
1948              
1949             # utils
1950              
1951             sub make_alias { # alas(from => to)
1952 3260     3260 0 5941 my($parser, $from, $to) = @_;
1953              
1954 3260         7184 my $stash = $parser->symbol_table;
1955 3260 50       8813 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         6574 return $stash->{$to} = $parser->symbol($from)->clone(
1963             value => $to, # real id
1964             );
1965             }
1966              
1967             sub not_supported {
1968 2     2 0 1 my($parser, $symbol) = @_;
1969 2         30 $parser->_error("'$symbol' is not supported");
1970             }
1971              
1972             sub _unexpected {
1973 13     13   20 my($parser, $expected, $got) = @_;
1974 13 100 66     128 if(defined($got) && $got ne ";") {
1975 12 100       33 if($got eq '(end)') {
1976 2         9 $parser->_error("Expected $expected, but reached EOF");
1977             }
1978             else {
1979 10         28 $parser->_error("Expected $expected, but got " . neat("$got"));
1980             }
1981             }
1982             else {
1983 1         3 $parser->_error("Expected $expected");
1984             }
1985             }
1986              
1987             sub _error {
1988 49     49   57 my($parser, $message, $near, $line) = @_;
1989              
1990 49   100     233 $near ||= $parser->near_token || ";";
      66        
1991 49 100 100     159 if($near ne ";" && $message !~ /\b \Q$near\E \b/xms) {
1992 39         72 $message .= ", near $near";
1993             }
1994 49   66     329 die $parser->make_error($message . ", while parsing templates",
1995             $parser->file, $line || $parser->line);
1996             }
1997              
1998 175     175   1275 no Mouse;
  175         236  
  175         1067  
1999             __PACKAGE__->meta->make_immutable;
2000             __END__