File Coverage

blib/lib/Parse/FSM/Parser.pm
Criterion Covered Total %
statement 125 142 88.0
branch 22 24 91.6
condition n/a
subroutine 27 43 62.7
pod 1 19 5.2
total 175 228 76.7


line stmt bran cond sub pod time code
1             # $Id: FSM.pm,v 1.10 2013/07/27 00:34:39 Paulo Exp $
2             # Parser generated by Parse::FSM
3              
4             package # hide from CPAN indexer
5             Parse::FSM::Parser;
6              
7 2     2   7 use strict;
  2         2  
  2         49  
8 2     2   6 use warnings;
  2         2  
  2         36  
9              
10 2     2   457 use Parse::FSM::Driver; our @ISA = ('Parse::FSM::Driver');
  2         2  
  2         69  
11              
12              
13 2     2   29 use Data::Dump 'dump';
  2         3  
  2         77  
14 2     2   1134 use Text::Balanced 'extract_quotelike', 'extract_codeblock';
  2         23362  
  2         3321  
15              
16             my $uid = 1;
17              
18              
19              
20             my $start_state = 2;
21             my @state_table = (
22             # [0]
23             { _lst_code1 => 45, _lst_element1 => 21, _lst_epilog1 => 6,
24             _lst_prolog1 => 1, _lst_quantifier1 => 35, _lst_sentence1 => 17,
25             _lst_sentence2 => 15, _lst_sentence3 => 40, _lst_sentence4 => 38,
26             _lst_statement1 => 3, action => 46, code => 53, code_unbraced => 11,
27             directive => 47, element => 25, epilog => 10, name => 51,
28             program => 2, prolog => 9, quantifier => 44, rule => 13,
29             sentence => 23, statement => 12, subrule => 34, subrule_name => 37,
30             token => 52, },
31              
32             # [1] _lst_prolog1 :
33             { CODE => [ 9, \&_act__lst_prolog11 ],
34             __else__ => \&_act__lst_prolog11, },
35              
36             # [2] program :
37             { CODE => [ 1, 5 ], __else__ => [ 1, 5 ], },
38              
39             # [3] _lst_statement1 :
40             { " [ 12, 4 ], NAME => [ 12, 4 ], },
41              
42             # [4] _lst_statement1 : [statement]
43             { " [ 12, 4 ], NAME => [ 12, 4 ],
44             __else__ => \&_act__lst_prolog11, },
45              
46             # [5] program : [_lst_prolog1]
47             { " [ 3, 7 ], NAME => [ 3, 7 ], },
48              
49             # [6] _lst_epilog1 :
50             { CODE => [ 10, \&_act__lst_prolog11 ],
51             __else__ => \&_act__lst_prolog11, },
52              
53             # [7] program : [_lst_prolog1] [_lst_statement1]
54             { CODE => [ 6, 8 ], __else__ => [ 6, 8 ], },
55              
56             # [8] program : [_lst_prolog1] [_lst_statement1] [_lst_epilog1]
57             { "" => \&_act_program1, },
58              
59             # [9] prolog :
60             { CODE => [ 11, \&_act_prolog1 ], },
61              
62             # [10] epilog :
63             { CODE => [ 11, \&_act_epilog1 ], },
64              
65             # [11] code_unbraced :
66             { CODE => [ 53, \&_act_code_unbraced1 ], },
67              
68             # [12] statement :
69             { " [ 47, \&_act_program1 ], NAME => [ 13, \&_act_program1 ], },
70              
71             # [13] rule :
72             { NAME => [ 51, 14 ], },
73              
74             # [14] rule : [name]
75             { ":" => 19, },
76              
77             # [15] _lst_sentence2 :
78             { "|" => 16, },
79              
80             # [16] _lst_sentence2 : "|"
81             { "(" => [ 23, \&_act__lst_sentence21 ],
82             " [ 23, \&_act__lst_sentence21 ],
83             " [ 23, \&_act__lst_sentence21 ],
84             NAME => [ 23, \&_act__lst_sentence21 ],
85             TOKEN => [ 23, \&_act__lst_sentence21 ], },
86              
87             # [17] _lst_sentence1 :
88             { "(" => [ 23, 18 ], " [ 23, 18 ], " [ 23, 18 ],
89             NAME => [ 23, 18 ], TOKEN => [ 23, 18 ], },
90              
91             # [18] _lst_sentence1 : [sentence]
92             { __else__ => \&_act__lst_prolog11, "|" => [ 15, 18 ], },
93              
94             # [19] rule : [name] ":"
95             { "(" => [ 17, 20 ], " [ 17, 20 ], " [ 17, 20 ],
96             NAME => [ 17, 20 ], TOKEN => [ 17, 20 ], },
97              
98             # [20] rule : [name] ":" [_lst_sentence1]
99             { ";" => \&_act_rule1, },
100              
101             # [21] _lst_element1 :
102             { "(" => [ 25, 22 ], " [ 25, 22 ], " [ 25, 22 ],
103             NAME => [ 25, 22 ], TOKEN => [ 25, 22 ], },
104              
105             # [22] _lst_element1 : [element]
106             { "(" => [ 25, 22 ], " [ 25, 22 ], " [ 25, 22 ],
107             NAME => [ 25, 22 ], TOKEN => [ 25, 22 ],
108             __else__ => \&_act__lst_prolog11, },
109              
110             # [23] sentence :
111             { "(" => [ 21, 24 ], " [ 21, 24 ], " [ 21, 24 ],
112             NAME => [ 21, 24 ], TOKEN => [ 21, 24 ], },
113              
114             # [24] sentence : [_lst_element1]
115             { CODE => [ 46, \&_act_sentence1 ],
116             __else__ => [ 46, \&_act_sentence1 ], },
117              
118             # [25] element :
119             { "(" => [ 34, \&_act_element1 ], " 26, " 27,
120             NAME => [ 34, \&_act_element1 ], TOKEN => [ 52, \&_act_element1 ], },
121              
122             # [26] element : "
123             { ">" => \&_act_element2, },
124              
125             # [27] element : "
126             { ":" => 28, },
127              
128             # [28] element : "
129             { "(" => [ 37, 29 ], NAME => [ 37, 29 ], },
130              
131             # [29] element : "
132             { "(" => [ 37, 32 ], NAME => [ 37, 32 ], TOKEN => [ 52, 30 ], },
133              
134             # [30] element : "
135             { "(" => [ 37, 31 ], NAME => [ 37, 31 ], },
136              
137             # [31] element : "
138             { ">" => \&_act_element3, },
139              
140             # [32] element : "
141             { "(" => [ 37, 33 ], NAME => [ 37, 33 ], },
142              
143             # [33] element : "
144             { ">" => \&_act_element4, },
145              
146             # [34] subrule :
147             { "(" => [ 37, 36 ], NAME => [ 37, 36 ], },
148              
149             # [35] _lst_quantifier1 :
150             { "*" => [ 44, \&_act__lst_prolog11 ],
151             "+" => [ 44, \&_act__lst_prolog11 ],
152             "<+" => [ 44, \&_act__lst_prolog11 ],
153             "?" => [ 44, \&_act__lst_prolog11 ],
154             __else__ => \&_act__lst_prolog11, },
155              
156             # [36] subrule : [subrule_name]
157             { "*" => [ 35, \&_act_subrule1 ], "+" => [ 35, \&_act_subrule1 ],
158             "<+" => [ 35, \&_act_subrule1 ], "?" => [ 35, \&_act_subrule1 ],
159             __else__ => [ 35, \&_act_subrule1 ], },
160              
161             # [37] subrule_name :
162             { "(" => 42, NAME => [ 51, \&_act_element1 ], },
163              
164             # [38] _lst_sentence4 :
165             { "|" => 39, },
166              
167             # [39] _lst_sentence4 : "|"
168             { "(" => [ 23, \&_act__lst_sentence21 ],
169             " [ 23, \&_act__lst_sentence21 ],
170             " [ 23, \&_act__lst_sentence21 ],
171             NAME => [ 23, \&_act__lst_sentence21 ],
172             TOKEN => [ 23, \&_act__lst_sentence21 ], },
173              
174             # [40] _lst_sentence3 :
175             { "(" => [ 23, 41 ], " [ 23, 41 ], " [ 23, 41 ],
176             NAME => [ 23, 41 ], TOKEN => [ 23, 41 ], },
177              
178             # [41] _lst_sentence3 : [sentence]
179             { __else__ => \&_act__lst_prolog11, "|" => [ 38, 41 ], },
180              
181             # [42] subrule_name : "("
182             { "(" => [ 40, 43 ], " [ 40, 43 ], " [ 40, 43 ],
183             NAME => [ 40, 43 ], TOKEN => [ 40, 43 ], },
184              
185             # [43] subrule_name : "(" [_lst_sentence3]
186             { ")" => \&_act_subrule_name1, },
187              
188             # [44] quantifier :
189             { "*" => \&_act_quantifier1, "+" => \&_act_quantifier1,
190             "<+" => \&_act_quantifier2, "?" => \&_act_quantifier1, },
191              
192             # [45] _lst_code1 :
193             { CODE => [ 53, \&_act__lst_prolog11 ],
194             __else__ => \&_act__lst_prolog11, },
195              
196             # [46] action :
197             { CODE => [ 45, \&_act_action1 ], __else__ => [ 45, \&_act_action1 ], },
198              
199             # [47] directive :
200             { " 48, },
201              
202             # [48] directive : "
203             { ":" => 49, },
204              
205             # [49] directive : "
206             { NAME => [ 51, 50 ], },
207              
208             # [50] directive : "
209             { ">" => \&_act_directive1, },
210              
211             # [51] name :
212             { NAME => \&_act_quantifier1, },
213              
214             # [52] token :
215             { TOKEN => \&_act_quantifier1, },
216              
217             # [53] code :
218             { CODE => \&_act_quantifier1, },
219              
220             );
221              
222             # _lst_prolog1 : [prolog]?
223             # _lst_statement1 : [statement] [statement]*
224             # _lst_epilog1 : [epilog]?
225             # _lst_sentence1 : [sentence] [_lst_sentence2]*
226             # _lst_element1 : [element] [element]*
227             # _lst_quantifier1 : [quantifier]?
228             # _lst_sentence3 : [sentence] [_lst_sentence4]*
229             # _lst_code1 : [code]?
230             sub _act__lst_prolog11 {
231 292     292   285 my($self, @item) = @_;
232             return \@item
233 292         422 }
234              
235             # _lst_sentence2 : "|" [sentence]
236             # _lst_sentence4 : "|" [sentence]
237             sub _act__lst_sentence21 {
238 6     6   8 my($self, @item) = @_;
239 6         11 return $item[1]
240             }
241              
242             # action : [_lst_code1]
243             sub _act_action1 {
244 59     59   61 my($self, @item) = @_;
245 59 100       42 if (@{$item[0]}) { # code block supplied
  59         83  
246 48         85 return $item[0][0];
247             }
248             else { # default action
249 11         16 return q{{
250             if (@item == 1) { # special case: one element
251             return $item[0]; # drop one array level
252             }
253             else {
254             return \@item;
255             }
256             }};
257             }
258             }
259              
260             # code_unbraced : [code]
261             sub _act_code_unbraced1 {
262 4     4   4 my($self, @item) = @_;
263 4         2 my $code = $item[0];
264 4         13 $code =~ s/\A\s*{//; # remove start ...
265 4         8 $code =~ s/}\s*\z//; # ... and end braces
266 4         7 return $code;
267             }
268              
269             # directive : ""
270             sub _act_directive1 {
271 4     4   7 my($self, @item) = @_;
272 4         4 my $name = $item[2];
273 4         15 $self->fsm->start_rule($name);
274 4         4 return;
275             }
276              
277             # element : [token]
278             # element : [subrule]
279             # subrule_name : [name]
280             sub _act_element1 {
281 124     124   121 my($self, @item) = @_;
282 124         174 return $item[0]
283             }
284              
285             # element : ""
286             sub _act_element2 {
287 3     3   5 my($self, @item) = @_;
288 3         5 return ""
289             }
290              
291             # element : ""
292             sub _act_element3 {
293 1     1   2 my($self, @item) = @_;
294 1         1 my $operand1 = $item[2];
295 1         2 my $operator = $item[3];
296 1         1 my $operand2 = $item[4];
297 1         2 my $name = "_anon".($uid++);
298 1         2 my $name_opt = "_anon".($uid++);
299            
300             # create rule for repetion of (operator operand2)
301 1         2 $self->fsm->add_rule($name_opt,
302             $operator, "[$operand2]",
303             '{return [$item[0][0], $item[1]]}');
304            
305             # create rule for : operand1 (opt_rule)*
306 1         2 $self->fsm->add_rule($name,
307             "[$operand1]", "[$name_opt]*",
308             q{{
309             my @ret = ($item[0]);
310             for (@{$item[1]}) {
311             push @ret, @$_;
312             }
313             return \@ret;
314             }});
315            
316             # return rule name
317 1         3 return "[$name]";
318             }
319              
320             # element : ""
321             sub _act_element4 {
322 1     1   2 my($self, @item) = @_;
323 1         1 my $operand1 = $item[2];
324 1         2 my $operator = $item[3];
325 1         1 my $operand2 = $item[4];
326 1         1 my $name = "_anon".($uid++);
327 1         2 my $name_opt = "_anon".($uid++);
328            
329             # create rule for repetion of (operator operand2)
330 1         2 $self->fsm->add_rule($name_opt,
331             "[$operator]", "[$operand2]",
332             '{return [$item[0], $item[1]]}');
333            
334             # create rule for : operand1 (opt_rule)*
335 1         2 $self->fsm->add_rule($name,
336             "[$operand1]", "[$name_opt]*",
337             q{{
338             my @ret = ($item[0]);
339             for (@{$item[1]}) {
340             push @ret, @$_;
341             }
342             return \@ret;
343             }});
344            
345             # return rule name
346 1         3 return "[$name]";
347             }
348              
349             # epilog : [code_unbraced]
350             sub _act_epilog1 {
351 2     2   3 my($self, @item) = @_;
352 2         2 my $code = $item[0];
353 2         3 $self->fsm->epilog($code);
354 2         2 return;
355             }
356              
357             # program : [_lst_prolog1] [_lst_statement1] [_lst_epilog1] ""
358             # statement : [rule]
359             # statement : [directive]
360       80     sub _act_program1 {
361             }
362              
363             # prolog : [code_unbraced]
364             sub _act_prolog1 {
365 2     2   2 my($self, @item) = @_;
366 2         2 my $code = $item[0];
367 2         3 $self->fsm->prolog($code);
368 2         3 return;
369             }
370              
371             # quantifier : "?"
372             # quantifier : "*"
373             # quantifier : "+"
374             # name : "NAME"
375             # token : "TOKEN"
376             # code : "CODE"
377             sub _act_quantifier1 {
378 217     217   240 my($self, @item) = @_;
379 217         357 return $item[0][1]
380             }
381              
382             # quantifier : "<+"
383             sub _act_quantifier2 {
384 2     2   4 my($self, @item) = @_;
385 2         7 return "<+$item[0][1]>"
386             }
387              
388             # rule : [name] ":" [_lst_sentence1] ";"
389             sub _act_rule1 {
390 49     49   65 my($self, @item) = @_;
391 49         45 my $name = $item[0];
392 49         34 my $sentences = $item[2];
393 49         61 for my $sentence (@$sentences) {
394 52         67 $self->fsm->add_rule($name, @$sentence);
395             }
396 49         93 return;
397             }
398              
399             # sentence : [_lst_element1] [action]
400             sub _act_sentence1 {
401 59     59   68 my($self, @item) = @_;
402 59         45 my $elements = $item[0];
403 59         34 my $action = $item[1];
404 59         116 return [@$elements, $action];
405             }
406              
407             # subrule : [subrule_name] [_lst_quantifier1]
408             sub _act_subrule1 {
409 27     27   31 my($self, @item) = @_;
410 27         25 my $name = $item[0];
411 27         24 my $quant = $item[1];
412 27         32 my $ret = "[$name]";
413 27 100       43 $ret .= $quant->[0] if @$quant;
414 27         41 return $ret;
415             }
416              
417             # subrule_name : "(" [_lst_sentence3] ")"
418             sub _act_subrule_name1 {
419 2     2   3 my($self, @item) = @_;
420 2         4 my $name = "_anon".($uid++);
421 2         2 my $sentences = $item[1];
422 2         3 for my $sentence (@$sentences) {
423 4         6 $self->fsm->add_rule($name, @$sentence);
424             }
425 2         4 return $name;
426             }
427              
428 0     0 0 0 sub parse_code { return shift->_parse(53) }
429 0     0 0 0 sub parse_program { return shift->_parse(2) }
430 0     0 0 0 sub parse_element { return shift->_parse(25) }
431 0     0 0 0 sub parse_subrule { return shift->_parse(34) }
432 0     0 0 0 sub parse_prolog { return shift->_parse(9) }
433 0     0 0 0 sub parse_statement { return shift->_parse(12) }
434 0     0 0 0 sub parse_subrule_name { return shift->_parse(37) }
435 0     0 0 0 sub parse_quantifier { return shift->_parse(44) }
436 0     0 0 0 sub parse_name { return shift->_parse(51) }
437 0     0 0 0 sub parse_rule { return shift->_parse(13) }
438 0     0 0 0 sub parse_sentence { return shift->_parse(23) }
439 0     0 0 0 sub parse_action { return shift->_parse(46) }
440 0     0 0 0 sub parse_code_unbraced { return shift->_parse(11) }
441 0     0 0 0 sub parse_directive { return shift->_parse(47) }
442 0     0 0 0 sub parse_token { return shift->_parse(52) }
443 0     0 0 0 sub parse_epilog { return shift->_parse(10) }
444              
445              
446             sub new {
447 38     38 1 55 my($class, %args) = @_;
448 38         118 return $class->SUPER::new(
449             _state_table => \@state_table,
450             _start_state => $start_state,
451             %args,
452             );
453             }
454              
455              
456             # access the FSM object
457 68     68 0 225 sub fsm { return shift->user->{fsm} }
458              
459             # read the given input string
460             sub from {
461 38     38 0 39 my($self, $line) = @_;
462            
463             $self->input(sub {
464 574     574   604 for ($line) {
465 574         1030 /\G(?:\s+|#.*)+/gc; # skip blanks and comments
466            
467 574 100       881 /\G([a-z]\w*)/gci and do {
468 94         248 return [NAME => $1];
469             };
470 480 100       779 /\G(?=["'])/gc and do {
471 70         63 my $start_pos = pos();
472 70         120 my($quoted_string, $rest) = extract_quotelike($_);
473 70 100       4167 if (defined $quoted_string) {
474 68         2690 my $token = eval($quoted_string); ## no critic
475 68 50       193 if (! $@) {
476 68         123 pos() = length() - length($rest);
477 68         204 return [TOKEN => $token];
478             }
479             }
480            
481             # could not parse quoted string, die
482 2         3 $rest = substr($_, $start_pos, 100);
483 2         4 die "Cannot parse quoted string at ", dump($rest), "\n";
484             };
485 410 100       591 /\G(?=[{])/gc and do {
486 54         51 my $start_pos = pos();
487 54         95 my($code_block, $rest) = extract_codeblock($_);
488 54 100       25850 if (defined $code_block) {
489 52         78 pos() = length() - length($rest);
490 52         131 return [CODE => $code_block];
491             }
492            
493             # could not parse quoted string, die
494 2         3 $rest = substr($_, $start_pos, 100);
495 2         4 die "Cannot parse code block at ", dump($rest), "\n";
496             };
497 356 50       422 /\G(%\w+)/gc and do { # directives
498 0         0 return [$1 => $1];
499             };
500 356 100       443 /\G(<\+)\s*([^>\s]+)\s*>/gc and do { # list quantifier
501 2         8 return [$1 => $2]; # ['<+' => ',']
502             };
503 354 100       389 /\G(<\w+)/gc and do { # directive
504 9         29 return [$1 => $1]; # [' '
505             };
506 345 100       464 /\G(.)/gc and do {
507 139         398 return [$1 => $1];
508             };
509 206         265 return; # end of input
510             }
511 38         169 });
512 38         57 return;
513             }
514              
515              
516              
517             1;