File Coverage

blib/lib/Spp/OptAst.pm
Criterion Covered Total %
statement 125 257 48.6
branch 23 58 39.6
condition n/a
subroutine 18 36 50.0
pod 0 31 0.0
total 166 382 43.4


line stmt bran cond sub pod time code
1             package Spp::OptAst;
2              
3 2     2   36 use 5.012;
  2         6  
4 2     2   10 no warnings "experimental";
  2         2  
  2         53  
5              
6 2     2   8 use Exporter;
  2         2  
  2         104  
7             our @ISA = qw(Exporter);
8             our @EXPORT = qw(opt_ast);
9              
10 2     2   10 use Spp::Builtin;
  2         6  
  2         322  
11 2     2   15 use Spp::Core qw(is_tillnot is_look is_rept is_sym);
  2         4  
  2         4618  
12              
13             sub opt_ast {
14 3     3 0 7 my $ast = shift;
15 3 50       9 return [ opt_atom($ast) ] if is_atom($ast);
16 0         0 return map_opt_atom($ast);
17             }
18              
19             sub map_opt_atom {
20 3     3 0 6 my $atoms = shift;
21 3         7 return [ map { opt_atom($_) } @{$atoms} ];
  7         22  
  3         9  
22             }
23              
24             sub opt_atom {
25 10     10 0 17 my $atom = shift;
26 10         18 my ($name, $value) = @{$atom};
  10         25  
27 10         17 given ($name) {
28 10         23 when ('Group') { return opt_group($value) }
  0         0  
29 10         18 when ('Branch') { return opt_branch($value) }
  0         0  
30 10         22 when ('Spec') { return opt_spec($value) }
  3         11  
31 7         13 when ('Cclass') { return opt_cclass($value) }
  2         8  
32 5         10 when ('Char') { return opt_char($value) }
  0         0  
33 5         10 when ('Str') { return opt_str($value) }
  0         0  
34 5         11 when ('String') { return opt_str($value) }
  0         0  
35 5         10 when ('Kstr') { return opt_kstr($value) }
  0         0  
36 5         17 when ('Point') { return opt_point($value) }
  0         0  
37 5         12 when ('Chclass') { return opt_chclass($value)}
  0         0  
38 5         12 when ('Look') { return opt_look($value) }
  1         5  
39 4         8 when ('Token') { return opt_token($value) }
  2         14  
40 2         6 when ('Expr') { return opt_expr($value) }
  0         0  
41 2         5 when ('Sym') { return opt_sym($value) }
  0         0  
42 2         4 when ('Sub') { return opt_sym($value) }
  0         0  
43 2         4 when ('Array') { return opt_array($value) }
  0         0  
44 2         5 when ('In') { return opt_in($value) }
  0         0  
45 2         4 when ('Out') { return opt_out($value) }
  0         0  
46 2         5 when ('Qstr') { return opt_qstr($value) }
  0         0  
47 2         5 when ('Qint') { return opt_qint($value) }
  0         0  
48 2         3 when ('Int') { return opt_int($value) }
  0         0  
49 2         5 default { return $atom }
  2         12  
50             }
51             }
52              
53             sub opt_spec {
54 3     3 0 4 my $atoms = shift;
55 3         8 my $token = $atoms->[0];
56 3         7 my $name = $token->[1];
57 3         12 my $rules = rest($atoms);
58 3         13 return [$name, opt_rules($rules)];
59             }
60              
61             sub opt_rules {
62 3     3 0 7 my $atoms = shift;
63 3         12 return opt_sets('Rules', $atoms);
64             }
65              
66             sub opt_group {
67 0     0 0 0 my $atoms = shift;
68 0         0 return opt_sets('Group', $atoms);
69             }
70              
71             sub opt_branch {
72 0     0 0 0 my $atoms = shift;
73 0         0 return opt_sets('Branch', $atoms);
74             }
75              
76             sub opt_sets {
77 3     3 0 10 my ($name, $atoms) = @_;
78 3         11 my $opt_atoms = opt_atoms($atoms);
79 3 100       12 return $opt_atoms->[0] if len($opt_atoms) == 1;
80 2         14 return [$name, $opt_atoms];
81             }
82              
83             sub opt_atoms {
84 3     3 0 7 my $atoms = shift;
85 3         11 my $opt_atoms = map_opt_atom($atoms);
86 3         16 $opt_atoms = gather_tillnot($opt_atoms);
87 3         11 $opt_atoms = gather_look($opt_atoms);
88 3         10 $opt_atoms = gather_rept($opt_atoms);
89 3         9 return $opt_atoms;
90             }
91              
92             sub opt_point {
93 0     0 0 0 my $point = shift;
94 0         0 return ['Char', chr(hex($point))];
95             }
96              
97             sub opt_kstr {
98 0     0 0 0 my $kstr = shift;
99 0         0 my $str = substr($kstr, 1);
100 0 0       0 return ['Char', $str] if len($str) == 1;
101 0         0 return ['Str', $str];
102             }
103              
104             sub opt_cclass {
105 2     2 0 3 my $cclass = shift;
106 2         5 return ['Cclass', tail($cclass)];
107             }
108              
109             sub opt_char {
110 0     0 0 0 my $char = shift;
111 0         0 return ['Char', opt_escape_char($char)];
112             }
113              
114             sub opt_escape_char {
115 0     0 0 0 my $str = shift;
116 0         0 my $char = tail($str);
117 0         0 given ($char) {
118 0         0 when ('b') { return ' ' }
  0         0  
119 0         0 when ('f') { return "\f" }
  0         0  
120 0         0 when ('n') { return "\n" }
  0         0  
121 0         0 when ('r') { return "\r" }
  0         0  
122 0         0 when ('t') { return "\t" }
  0         0  
123 0         0 default { return $char }
  0         0  
124             }
125             }
126              
127             sub opt_str {
128 0     0 0 0 my $atoms = shift;
129 0         0 my $opt_atoms = [];
130 0         0 for my $atom (@{$atoms}) {
  0         0  
131 0         0 my ($name, $value) = @{$atom};
  0         0  
132 0         0 given ($name) {
133 0         0 when ('Char') {
134 0         0 my $char = opt_escape_char($value);
135 0         0 push @{$opt_atoms}, $char;
  0         0  
136             }
137 0         0 default {
138 0         0 push @{$opt_atoms}, $value;
  0         0  
139             }
140             }
141             }
142 0         0 my $str = join('', @{$opt_atoms});
  0         0  
143 0 0       0 return ['Char', $str] if len($str) == 1;
144 0         0 return ['Str', $str];
145             }
146              
147             sub opt_chclass {
148 0     0 0 0 my $nodes = shift;
149 0         0 my $atoms = [];
150 0         0 my $flip = 0;
151 0         0 for my $node (@{$nodes}) {
  0         0  
152 0         0 my ($name, $value) = @{$node};
  0         0  
153 0 0       0 if ($name eq 'Flip') { $flip = 1; }
  0         0  
154             else {
155 0         0 my $atom = opt_catom($name, $value);
156 0         0 push @{$atoms}, $atom;
  0         0  
157             }
158             }
159 0 0       0 if ($flip == 0) { return ['Chclass', $atoms]; }
  0         0  
160 0         0 return ['Nchclass', $atoms];
161             }
162              
163             sub opt_catom {
164 0     0 0 0 my ($name, $value) = @_;
165 0         0 given ($name) {
166 0         0 when ('Cclass') {
167 0         0 return opt_cclass($value)
168             }
169 0         0 when ('Range') {
170 0         0 return opt_range($value)
171             }
172 0         0 when ('Char') {
173 0         0 return opt_char($value)
174             }
175 0         0 default { return ['Char', $value] }
  0         0  
176             }
177             }
178              
179             sub opt_range {
180 0     0 0 0 my $range = shift;
181 0         0 return ['Range', [split('-', $range)]];
182             }
183              
184             sub opt_look {
185 1     1 0 3 my $atoms = shift;
186 1         3 my $rept = $atoms->[0][1];
187 1 50       3 return ['_rept', $rept] if len($atoms) == 1;
188 0         0 return ['_look', $rept];
189             }
190              
191             sub gather_tillnot {
192 3     3 0 6 my $atoms = shift;
193 3         7 my @opt_atoms = ();
194 3         6 my $flag = 0;
195 3         7 my $cache = '';
196 3         6 for my $atom (@{$atoms}) {
  3         8  
197 7 50       20 if ($flag == 0) {
198 7 50       20 if (is_tillnot($atom)) {
199 0         0 $flag = 1;
200 0         0 $cache = $atom;
201             } else {
202 7         17 push @opt_atoms, $atom;
203             }
204             }
205             else {
206 0 0       0 if (!is_tillnot($atom)) {
207 0         0 my $name = $cache->[0];
208 0         0 $cache = [$name, $atom];
209 0         0 push @opt_atoms, $cache;
210 0         0 $flag = 0;
211             } else {
212 0         0 die('Till/Not duplicate');
213             }
214             }
215             }
216 3 50       11 if ($flag > 0) { die("Till/Not without token!") }
  0         0  
217 3         10 return [@opt_atoms];
218             }
219              
220             sub gather_look {
221 3     3 0 5 my $atoms = shift;
222 3         7 my @opt_atoms = ();
223 3         5 my $flag = 0;
224 3         6 my $cache = '';
225 3         6 my $look = '';
226 3         4 for my $atom (@{$atoms}) {
  3         6  
227 7 100       23 if ($flag == 0) {
    50          
228 3 50       13 if (is_look($atom)) {
229 0         0 die("Look token less prefix atom: $atom");
230             } else {
231 3         11 $cache = $atom;
232 3         8 $flag = 1;
233             }
234             } elsif ($flag == 1) {
235 4 50       16 if (is_look($atom)) {
236 0         0 $look = $atom->[1];
237 0         0 $flag = 2;
238             } else {
239 4         10 push @opt_atoms, $cache;
240 4         11 $cache = $atom;
241             }
242             } else {
243 0 0       0 if (!is_look($atom)) {
244 0         0 $cache = ['Look', [$look, $cache, $atom]];
245 0         0 push @opt_atoms, $cache;
246 0         0 $flag = 0;
247             } else {
248 0         0 die("Look token repeat");
249             }
250             }
251             }
252 3 50       11 if ($flag > 1) { die('Look without atom!') }
  0         0  
253 3 50       11 push @opt_atoms, $cache if $flag == 1;
254 3         11 return [@opt_atoms];
255             }
256              
257             sub gather_rept {
258 3     3 0 6 my $atoms = shift;
259 3         5 my @opt_atoms;
260 3         5 my $flag = 0;
261 3         5 my $cache = '';
262 3         13 for my $atom (@{$atoms}) {
  3         7  
263 7 100       18 if ($flag == 0) {
264 3 50       12 if (is_rept($atom)) {
265 0         0 die("rept without token");
266             }
267             else {
268 3         6 $cache = $atom;
269 3         8 $flag = 1;
270             }
271             }
272             else {
273 4 100       13 if (is_rept($atom)) {
274 1         3 my $rept = $atom->[1];
275 1         2 push @opt_atoms, ['Rept', [$rept, $cache]];
276 1         3 $flag = 0;
277             }
278             else {
279 3         9 push @opt_atoms, $cache;
280 3         8 $cache = $atom;
281             }
282             }
283             }
284 3 100       21 if ($flag == 1) { push @opt_atoms, $cache; }
  2         5  
285 3         9 return [@opt_atoms];
286             }
287              
288             sub opt_token {
289 2     2 0 8 my $name = shift;
290 2         10 my $char = first($name);
291 2 50       8 return ['Rtoken', $name] if $char eq '_';
292 2 50       9 return ['Ntoken', $name] if is_upper($char);
293 2         10 return ['Ctoken', $name];
294             }
295              
296             sub opt_expr {
297 0     0 0   my $atoms = shift;
298 0           my $opt_atoms = map_opt_atom($atoms);
299 0           my $action = $opt_atoms->[0];
300 0 0         if (is_sym($action)) {
301 0           $opt_atoms->[0] = $action->[1];
302 0           return ['Expr', $opt_atoms];
303             }
304 0           die "Expr not action: {$action->[1]}";
305             }
306              
307             sub opt_sym {
308 0     0 0   my $name = shift;
309 0 0         return ['false'] if $name eq 'false';
310 0 0         return ['true'] if $name eq 'true';
311 0           return ['Sym', $name];
312             }
313              
314             sub opt_array {
315 0     0 0   my $atoms = shift;
316 0 0         return ['Array', []] if is_str($atoms);
317 0           my $opt_atoms = map_opt_atom($atoms);
318 0           return ['Array', $opt_atoms];
319             }
320              
321 0     0 0   sub opt_in { return ['Char', In] }
322              
323 0     0 0   sub opt_out { return ['Char', Out] }
324              
325 0     0 0   sub opt_qstr { return ['Char', Qstr] }
326              
327 0     0 0   sub opt_qint { return ['Char', Qint] }
328              
329             sub opt_int {
330 0     0 0   my $int = shift;
331 0 0         return ['Char', $int] if len($int) == 1;
332 0           return ['Str', $int];
333             }
334              
335             1;