File Coverage

blib/lib/Spp/MatchRule.pm
Criterion Covered Total %
statement 182 400 45.5
branch 43 88 48.8
condition 0 3 0.0
subroutine 23 40 57.5
pod 0 32 0.0
total 248 563 44.0


line stmt bran cond sub pod time code
1             package Spp::MatchRule;
2              
3 2     2   25 use 5.012;
  2         6  
4 2     2   7 no warnings 'experimental';
  2         4  
  2         46  
5              
6 2     2   8 use Exporter;
  2         3  
  2         124  
7             our @ISA = qw(Exporter);
8             our @EXPORT =
9             qw(match_spp_rule match_spp_any match_spp_assert match_spp_rules match_spp_branch match_spp_ntoken match_spp_ctoken match_spp_rtoken match_spp_not match_spp_till match_spp_rept match_spp_look match_spp_str match_spp_char match_spp_chclass match_spp_nclass match_spp_catom match_spp_cclass is_match_spp_cclass match_spp_range match_spp_sym get_spp_sym_value match_spp_value match_spp_call get_spp_call_value eval_spp_my eval_spp_push get_spp_atom_value get_spp_array_value get_spp_atoms_value name_spp_match gather_spp_match);
10              
11 2     2   10 use Spp::Builtin;
  2         3  
  2         366  
12 2     2   12 use Spp::Tools;
  2         2  
  2         191  
13 2     2   34 use Spp::Cursor;
  2         6  
  2         95  
14 2     2   473 use Spp::ToSpp;
  2         4  
  2         5009  
15              
16             sub _match_spp_rule {
17 0     0   0 my ($c, $rule) = @_;
18 0         0 if (1) {
19 0         0 my $off = $c->{'off'};
20 0         0 my $char = get_char($c);
21 0         0 my $indent = ' ' x $c->{'depth'};
22 0         0 my $spp = to_spp($rule);
23 0         0 say "$off| $char |$indent -> $spp";
24 0         0 $c->{'depth'}++;
25 0         0 my $match = _match_spp_rule($c, $rule);
26 0         0 $c->{'depth'}--;
27 0         0 $off = $c->{'off'};
28 0         0 $char = get_char($c);
29 0         0 $indent = ' ' x $c->{'depth'};
30 0         0 my $flag = 'ok';
31 0 0       0 if (is_false($match)) { $flag = "<-" }
  0         0  
32 0         0 say "$off| $char |$indent $flag $spp";
33 0         0 return $match;
34             }
35             else { return _match_spp_rule($c, $rule) }
36             }
37              
38             sub match_spp_rule {
39 682     682 0 996 my ($c, $rule) = @_;
40 682         1020 my ($name, $value) = flat($rule);
41 682         999 given ($name) {
42 682         1016 when ('Rules') { return match_spp_rules($c, $value) }
  119         227  
43 563         664 when ('Group') { return match_spp_rules($c, $value) }
  0         0  
44 563         640 when ('Branch') { return match_spp_branch($c, $value) }
  69         150  
45 494         613 when ('Rept') { return match_spp_rept($c, $value) }
  77         172  
46 417         511 when ('Look') { return match_spp_look($c, $value) }
  0         0  
47 417         481 when ('Cclass') { return match_spp_cclass($c, $value) }
  40         89  
48 377         418 when ('Chclass') {
49 46         125 return match_spp_chclass($c, $value)
50             }
51 331         397 when ('Nclass') { return match_spp_nclass($c, $value) }
  0         0  
52 331         384 when ('Str') { return match_spp_str($c, $value) }
  42         95  
53 289         362 when ('Char') { return match_spp_char($c, $value) }
  98         200  
54 191         225 when ('Assert') { return match_spp_assert($c, $value) }
  6         18  
55 185         216 when ('Not') { return match_spp_not($c, $value) }
  0         0  
56 185         271 when ('Till') { return match_spp_till($c, $value) }
  0         0  
57 185         225 when ('Rtoken') { return match_spp_rtoken($c, $value) }
  44         94  
58 141         169 when ('Ctoken') { return match_spp_ctoken($c, $value) }
  10         33  
59 131         176 when ('Ntoken') { return match_spp_ntoken($c, $value) }
  131         220  
60 0         0 when ('Any') { return match_spp_any($c, $value) }
  0         0  
61 0         0 when ('Call') { return match_spp_call($c, $value) }
  0         0  
62 0         0 when ('Sym') { return match_spp_sym($c, $value) }
  0         0  
63 0         0 default { say "unknown rule: $name to match!" }
  0         0  
64             }
65             }
66              
67             sub match_spp_any {
68 0     0 0 0 my ($c, $any) = @_;
69 0         0 my $char = get_char($c);
70 0 0       0 if ($char eq End) { return False }
  0         0  
71 0         0 to_next($c);
72 0         0 return $char;
73             }
74              
75             sub match_spp_assert {
76 6     6 0 17 my ($c, $assert) = @_;
77 6         10 given ($assert) {
78 6         16 when ('$') {
79 6 50       14 if (get_char($c) eq End) { return True }
  6         16  
80 0         0 return False
81             }
82 0         0 when ('^') {
83 0 0       0 if (pre_char($c) eq "\n") { return True }
  0         0  
84 0 0       0 if ($c->{'off'} == 0) { return True }
  0         0  
85 0         0 return False
86             }
87 0         0 when ('$$') {
88 0 0       0 if (get_char($c) eq "\n") { return True }
  0         0  
89 0 0       0 if (get_char($c) eq End) { return True }
  0         0  
90 0         0 return False
91             }
92 0         0 default { say "unknown assert: $assert" }
  0         0  
93             }
94             }
95              
96             sub match_spp_rules {
97 119     119 0 186 my ($c, $rules) = @_;
98 119         161 my $gather = True;
99 119         130 for my $rule (@{ atoms($rules) }) {
  119         200  
100 138         248 my $match = match_spp_rule($c, $rule);
101 138 100       273 if (is_false($match)) { return False }
  110         300  
102 28         73 $gather = gather_spp_match($gather, $match);
103             }
104 9         46 return $gather;
105             }
106              
107             sub match_spp_branch {
108 69     69 0 117 my ($c, $branch) = @_;
109 69         134 my $cache = cache($c);
110 69         90 for my $rule (@{ atoms($branch) }) {
  69         116  
111 231         390 my $match = match_spp_rule($c, $rule);
112 231 100       422 if (not(is_false($match))) { return $match }
  34         122  
113 197         419 reset_cache($c, $cache);
114             }
115 35         111 return False;
116             }
117              
118             sub match_spp_ntoken {
119 131     131 0 206 my ($c, $name) = @_;
120 131         191 my $table = $c->{'ns'};
121 131         240 my $rule = $table->{$name};
122 131         260 my $cache = cache($c);
123 131         225 my $match = match_spp_rule($c, $rule);
124 131 100       279 if (is_bool($match)) { return $match }
  117         269  
125 14 100       35 if (is_str($match)) {
126 10         32 my $ref_name = add('@', $name);
127 10         18 my $ns = $c->{'ns'};
128 10         31 $ns->{$ref_name} = $match;
129             }
130 14         51 return name_spp_match($name, $match, $cache);
131             }
132              
133             sub match_spp_ctoken {
134 10     10 0 23 my ($c, $name) = @_;
135 10         19 my $table = $c->{'ns'};
136 10         23 my $rule = $table->{$name};
137 10         24 my $match = match_spp_rule($c, $rule);
138 10 50       36 if (is_str($match)) {
139 0         0 my $ref_name = add('@', $name);
140 0         0 my $ns = $c->{'ns'};
141 0         0 $ns->{$ref_name} = $match;
142             }
143 10         37 return $match;
144             }
145              
146             sub match_spp_rtoken {
147 44     44 0 82 my ($c, $name) = @_;
148 44         68 my $table = $c->{'ns'};
149 44         80 my $rule = $table->{$name};
150 44         84 my $match = match_spp_rule($c, $rule);
151 44 100       86 if (is_false($match)) { return False }
  38         85  
152 6         16 return True;
153             }
154              
155             sub match_spp_not {
156 0     0 0 0 my ($c, $rule) = @_;
157 0         0 my $cache = cache($c);
158 0         0 my $match = match_spp_rule($c, $rule);
159 0 0       0 if (is_false($match)) {
160 0         0 reset_cache($c, $cache);
161 0         0 return True;
162             }
163 0         0 return False;
164             }
165              
166             sub match_spp_till {
167 0     0 0 0 my ($c, $rule) = @_;
168 0         0 my $buf = [];
169 0         0 while ($c->{'off'} < $c->{'length'}) {
170 0         0 my $char = get_char($c);
171 0         0 my $cache = cache($c);
172 0         0 my $match = match_spp_rule($c, $rule);
173 0 0       0 if (not(is_false($match))) {
174 0         0 my $gather_str = string($buf);
175 0         0 return gather_spp_match($gather_str, $match);
176             }
177 0         0 push @{$buf}, $char;
  0         0  
178 0         0 reset_cache($c, $cache);
179 0         0 to_next($c);
180             }
181 0         0 return False;
182             }
183              
184             sub match_spp_rept {
185 77     77 0 168 my ($c, $rule) = @_;
186 77         102 my $gather = True;
187 77         110 my $time = 0;
188 77         128 my ($rept, $atom) = flat($rule);
189 77         206 my ($min, $max) = get_rept_time($rept);
190 77         157 while ($time != $max) {
191 125         276 my $cache = cache($c);
192 125         233 my $match = match_spp_rule($c, $atom);
193 125 100       238 if (is_false($match)) {
194 77 100       142 if ($time < $min) { return False }
  50         136  
195 27         64 reset_cache($c, $cache);
196 27         82 return $gather;
197             }
198 48         71 $time++;
199 48         89 $gather = gather_spp_match($gather, $match);
200             }
201 0         0 return $gather;
202             }
203              
204             sub match_spp_look {
205 0     0 0 0 my ($c, $rule) = @_;
206 0         0 my ($rept, $atom_look) = flat($rule);
207 0         0 my ($atom, $look) = flat($atom_look);
208 0         0 my ($min, $max) = get_rept_time($rept);
209 0         0 my $gather = True;
210 0         0 my $time = 0;
211 0         0 while ($time != $max) {
212 0         0 my $cache = cache($c);
213 0         0 my $match = match_spp_rule($c, $atom);
214 0 0       0 if (is_false($match)) {
215 0 0       0 if ($time > $min) { return False }
  0         0  
216 0         0 reset_cache($c, $cache);
217 0         0 $match = match_spp_rule($c, $look);
218 0 0       0 if (is_false($match)) { return False }
  0         0  
219 0         0 return gather_spp_match($gather, $match);
220             }
221 0         0 $time++;
222 0         0 $gather = gather_spp_match($gather, $match);
223 0 0       0 if ($time >= $min) {
224 0         0 $cache = cache($c);
225 0         0 $match = match_spp_rule($c, $look);
226 0 0       0 if (not(is_false($match))) {
227 0         0 return gather_spp_match($gather, $match);
228             }
229 0         0 reset_cache($c, $cache);
230             }
231             }
232 0         0 return False;
233             }
234              
235             sub match_spp_str {
236 42     42 0 95 my ($c, $str) = @_;
237 42         129 for my $char (split '', $str) {
238 44 100       118 if ($char ne get_char($c)) { return False }
  42         139  
239 2         11 to_next($c);
240             }
241 0         0 return $str;
242             }
243              
244             sub match_spp_char {
245 98     98 0 146 my ($c, $char) = @_;
246 98 100       218 if ($char ne get_char($c)) { return False }
  91         216  
247 7         27 to_next($c);
248 7         20 return $char;
249             }
250              
251             sub match_spp_chclass {
252 46     46 0 89 my ($c, $atoms) = @_;
253 46         98 my $char = get_char($c);
254 46         80 for my $atom (@{ atoms($atoms) }) {
  46         89  
255 88 100       191 if (match_spp_catom($atom, $char)) {
256 21         72 to_next($c);
257 21         61 return $char;
258             }
259             }
260 25         72 return False;
261             }
262              
263             sub match_spp_nclass {
264 0     0 0 0 my ($c, $atoms) = @_;
265 0         0 my $char = get_char($c);
266 0 0       0 if ($char eq End) { return False }
  0         0  
267 0         0 for my $atom (@{ atoms($atoms) }) {
  0         0  
268 0 0       0 if (match_spp_catom($atom, $char)) { return False }
  0         0  
269             }
270 0         0 to_next($c);
271 0         0 return $char;
272             }
273              
274             sub match_spp_catom {
275 88     88 0 138 my ($atom, $char) = @_;
276 88         147 my ($name, $value) = flat($atom);
277 88         128 given ($name) {
278 88         145 when ('Range') { return match_spp_range($value, $char) }
  0         0  
279 88         118 when ('Cclass') {
280 34         72 return is_match_spp_cclass($value, $char)
281             }
282 54         86 default { return $value eq $char }
  54         151  
283             }
284             }
285              
286             sub match_spp_cclass {
287 40     40 0 81 my ($c, $cclass) = @_;
288 40         81 my $char = get_char($c);
289 40 100       88 if ($char eq End) { return False }
  6         16  
290 34 100       67 if (is_match_spp_cclass($cclass, $char)) {
291 9         28 to_next($c);
292 9         20 return $char;
293             }
294 25         59 return False;
295             }
296              
297             sub is_match_spp_cclass {
298 68     68 0 124 my ($cchar, $char) = @_;
299 68         90 given ($cchar) {
300 68         97 when ('a') { return is_alpha($char) }
  34         82  
301 34         48 when ('A') { return not(is_alpha($char)) }
  0         0  
302 34         37 when ('d') { return is_digit($char) }
  0         0  
303 34         42 when ('D') { return not(is_digit($char)) }
  0         0  
304 34         53 when ('h') { return is_hspace($char) }
  0         0  
305 34         41 when ('H') { return not(is_hspace($char)) }
  0         0  
306 34         59 when ('l') { return is_lower($char) }
  0         0  
307 34         42 when ('L') { return not(is_lower($char)) }
  0         0  
308 34         53 when ('s') { return is_space($char) }
  34         80  
309 0         0 when ('S') { return not(is_space($char)) }
  0         0  
310 0         0 when ('u') { return is_upper($char) }
  0         0  
311 0         0 when ('U') { return not(is_upper($char)) }
  0         0  
312 0         0 when ('v') { return is_vspace($char) }
  0         0  
313 0         0 when ('V') { return not(is_vspace($char)) }
  0         0  
314 0         0 when ('w') { return is_words($char) }
  0         0  
315 0         0 when ('W') { return not(is_words($char)) }
  0         0  
316 0         0 when ('x') { return is_xdigit($char) }
  0         0  
317 0         0 when ('X') { return not(is_xdigit($char)) }
  0         0  
318 0         0 default { say "unknown cclass: $cchar" }
  0         0  
319             }
320             }
321              
322             sub match_spp_range {
323 0     0 0 0 my ($range, $char) = @_;
324 0         0 my ($from, $to) = flat($range);
325 0   0     0 return $from le $char && $char le $to;
326             }
327              
328             sub match_spp_sym {
329 0     0 0 0 my ($c, $name) = @_;
330 0         0 my $value = get_spp_sym_value($c, $name);
331 0         0 return match_spp_value($c, $value);
332             }
333              
334             sub get_spp_sym_value {
335 0     0 0 0 my ($c, $name) = @_;
336 0         0 my $ns = $c->{'ns'};
337 0 0       0 if (exists $ns->{$name}) { return $ns->{$name} }
  0         0  
338 0         0 error("variable not define: <$name>.");
339             }
340              
341             sub match_spp_value {
342 0     0 0 0 my ($c, $atom) = @_;
343 0         0 my ($name, $value) = flat($atom);
344 0         0 given ($name) {
345 0         0 when ('Array') {
346 0 0       0 if (is_blank($value)) { return False }
  0         0  
347 0         0 return match_spp_branch($c, $value)
348             }
349 0         0 when ('Str') { return match_spp_str($c, $value) }
  0         0  
350             }
351             }
352              
353             sub match_spp_call {
354 0     0 0 0 my ($c, $call) = @_;
355 0         0 my $value = get_spp_call_value($c, $call);
356 0         0 return match_spp_value($c, $value);
357             }
358              
359             sub get_spp_call_value {
360 0     0 0 0 my ($c, $call) = @_;
361 0         0 my ($name, $args) = match($call);
362 0         0 given ($name) {
363 0         0 when ('my') { return eval_spp_my($c, $args) }
  0         0  
364 0         0 when ('push') { return eval_spp_push($c, $args) }
  0         0  
365 0         0 default { error("not implement: ($name..)") }
  0         0  
366             }
367             }
368              
369             sub eval_spp_my {
370 0     0 0 0 my ($c, $atoms) = @_;
371 0         0 my ($sym, $value) = flat($atoms);
372 0 0       0 if (is_sym($sym)) {
373 0         0 my $name = value($sym);
374 0         0 my $ns = $c->{'ns'};
375 0         0 $ns->{$name} = $value;
376 0         0 return True;
377             }
378 0         0 error("only assign symbol!");
379             }
380              
381             sub eval_spp_push {
382 0     0 0 0 my ($c, $atoms) = @_;
383 0         0 my $sym = name($atoms);
384 0 0       0 if (is_sym($sym)) {
385 0         0 my $name = value($sym);
386 0         0 my $atoms_value = get_spp_atoms_value($c, $atoms);
387 0         0 my ($array, $elem) = flat($atoms_value);
388 0         0 $array = value($array);
389 0         0 $array = epush($array, $elem);
390 0         0 my $ns = $c->{'ns'};
391 0         0 $ns->{$name} = cons('Array', $array);
392 0         0 return True;
393             }
394 0         0 error('push only accept array symbol!');
395             }
396              
397             sub get_spp_atom_value {
398 0     0 0 0 my ($c, $atom) = @_;
399 0         0 my ($name, $value) = flat($atom);
400 0         0 given ($name) {
401 0         0 when ('Array') {
402 0         0 return get_spp_array_value($c, $value)
403             }
404 0         0 when ('Sym') { return get_spp_sym_value($c, $value) }
  0         0  
405 0         0 when ('Str') { return $atom }
  0         0  
406             }
407             }
408              
409             sub get_spp_array_value {
410 0     0 0 0 my ($c, $array) = @_;
411 0 0       0 if (is_blank($array)) { return cons('Array', $array) }
  0         0  
412 0         0 my $atoms = get_spp_atoms_value($c, $array);
413 0         0 return cons('Array', $atoms);
414             }
415              
416             sub get_spp_atoms_value {
417 0     0 0 0 my ($c, $atoms) = @_;
418 0         0 my $atoms_value = [];
419 0         0 for my $atom (@{ atoms($atoms) }) {
  0         0  
420 0         0 push @{$atoms_value}, get_spp_atom_value($c, $atom);
  0         0  
421             }
422 0         0 return estr($atoms_value);
423             }
424              
425             sub name_spp_match {
426 14     14 0 43 my ($name, $match, $pos) = @_;
427 14 50       30 if (is_true($match)) { return $match }
  0         0  
428 14         51 my $pos_str = estr_ints($pos);
429 14 100       55 if (is_atom($match)) {
430 1         5 return cons($name, cons($match), $pos_str);
431             }
432 13         58 return cons($name, $match, $pos_str);
433             }
434              
435             sub gather_spp_match {
436 76     76 0 142 my ($gather, $match) = @_;
437 76 100       137 if (is_true($match)) { return $gather }
  13         37  
438 63 100       110 if (is_true($gather)) { return $match }
  36         98  
439 27 100       61 if (is_str($match)) {
440 20 100       35 if (is_str($gather)) { return add($gather, $match) }
  14         36  
441 6         15 return $gather;
442             }
443 7 50       23 if (is_str($gather)) { return $match }
  0         0  
444 7 100       22 if (is_atom($gather)) {
445 6 100       13 if (is_atom($match)) { return cons($gather, $match) }
  3         10  
446 3         17 return eunshift($gather, $match);
447             }
448 1 50       6 if (is_atom($match)) { return epush($gather, $match) }
  1         5  
449 0           return eappend($gather, $match);
450             }
451             1;