File Coverage

blib/lib/Spp/MatchRule.pm
Criterion Covered Total %
statement 182 401 45.3
branch 43 88 48.8
condition 0 3 0.0
subroutine 23 40 57.5
pod 0 32 0.0
total 248 564 43.9


line stmt bran cond sub pod time code
1             package Spp::MatchRule;
2              
3 2     2   27 use 5.012;
  2         6  
4 2     2   9 no warnings 'experimental';
  2         3  
  2         49  
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         2  
  2         330  
12 2     2   10 use Spp::Tools;
  2         3  
  2         192  
13 2     2   11 use Spp::Cursor;
  2         2  
  2         80  
14 2     2   482 use Spp::ToSpp;
  2         4  
  2         5217  
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 953 my ($c, $rule) = @_;
40 682         1091 my ($name, $value) = flat($rule);
41 682         886 given ($name) {
42 682         981 when ('Rules') { return match_spp_rules($c, $value) }
  119         219  
43 563         631 when ('Group') { return match_spp_rules($c, $value) }
  0         0  
44 563         669 when ('Branch') { return match_spp_branch($c, $value) }
  69         133  
45 494         574 when ('Rept') { return match_spp_rept($c, $value) }
  77         158  
46 417         478 when ('Look') { return match_spp_look($c, $value) }
  0         0  
47 417         455 when ('Cclass') { return match_spp_cclass($c, $value) }
  40         93  
48 377         453 when ('Chclass') {
49 46         101 return match_spp_chclass($c, $value)
50             }
51 331         402 when ('Nclass') { return match_spp_nclass($c, $value) }
  0         0  
52 331         365 when ('Str') { return match_spp_str($c, $value) }
  42         97  
53 289         320 when ('Char') { return match_spp_char($c, $value) }
  98         203  
54 191         266 when ('Assert') { return match_spp_assert($c, $value) }
  6         16  
55 185         208 when ('Not') { return match_spp_not($c, $value) }
  0         0  
56 185         197 when ('Till') { return match_spp_till($c, $value) }
  0         0  
57 185         209 when ('Rtoken') { return match_spp_rtoken($c, $value) }
  44         167  
58 141         168 when ('Ctoken') { return match_spp_ctoken($c, $value) }
  10         24  
59 131         149 when ('Ntoken') { return match_spp_ntoken($c, $value) }
  131         217  
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 12 my ($c, $assert) = @_;
77 6         10 given ($assert) {
78 6         12 when ('$') {
79 6 50       13 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 188 my ($c, $rules) = @_;
98 119         169 my $gather = True;
99 119         138 for my $rule (@{ atoms($rules) }) {
  119         195  
100 138         273 my $match = match_spp_rule($c, $rule);
101 138 100       260 if (is_false($match)) { return False }
  110         298  
102 28         56 $gather = gather_spp_match($gather, $match);
103             }
104 9         36 return $gather;
105             }
106              
107             sub match_spp_branch {
108 69     69 0 130 my ($c, $branch) = @_;
109 69         150 my $cache = cache($c);
110 69         87 for my $rule (@{ atoms($branch) }) {
  69         114  
111 231         399 my $match = match_spp_rule($c, $rule);
112 231 100       375 if (not(is_false($match))) { return $match }
  34         133  
113 197         396 reset_cache($c, $cache);
114             }
115 35         96 return False;
116             }
117              
118             sub match_spp_ntoken {
119 131     131 0 187 my ($c, $name) = @_;
120 131         213 my $table = $c->{'ns'};
121 131         236 my $rule = $table->{$name};
122 131         254 my $cache = cache($c);
123 131         227 my $match = match_spp_rule($c, $rule);
124 131 100       255 if (is_bool($match)) { return $match }
  117         304  
125 14 100       34 if (is_str($match)) {
126 10         36 my $ref_name = add('@', $name);
127 10         20 my $ns = $c->{'ns'};
128 10         28 $ns->{$ref_name} = $match;
129             }
130 14         39 return name_spp_match($name, $match, $cache);
131             }
132              
133             sub match_spp_ctoken {
134 10     10 0 24 my ($c, $name) = @_;
135 10         22 my $table = $c->{'ns'};
136 10         17 my $rule = $table->{$name};
137 10         22 my $match = match_spp_rule($c, $rule);
138 10 50       30 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 89 my ($c, $name) = @_;
148 44         74 my $table = $c->{'ns'};
149 44         84 my $rule = $table->{$name};
150 44         82 my $match = match_spp_rule($c, $rule);
151 44 100       75 if (is_false($match)) { return False }
  38         83  
152 6         20 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->{'len'}) {
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 = join '', @{$buf};
  0         0  
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 126 my ($c, $rule) = @_;
186 77         104 my $gather = True;
187 77         99 my $time = 0;
188 77         133 my ($rept, $atom) = flat($rule);
189 77         183 my ($min, $max) = get_rept_time($rept);
190 77         177 while ($time != $max) {
191 125         252 my $cache = cache($c);
192 125         231 my $match = match_spp_rule($c, $atom);
193 125 100       219 if (is_false($match)) {
194 77 100       372 if ($time < $min) { return False }
  50         127  
195 27         68 reset_cache($c, $cache);
196 27         88 return $gather;
197             }
198 48         70 $time++;
199 48         88 $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 86 my ($c, $str) = @_;
237 42         104 for my $char (split '', $str) {
238 44 100       94 if ($char ne get_char($c)) { return False }
  42         118  
239 2         7 to_next($c);
240             }
241 0         0 return $str;
242             }
243              
244             sub match_spp_char {
245 98     98 0 142 my ($c, $char) = @_;
246 98 100       218 if ($char ne get_char($c)) { return False }
  91         235  
247 7         22 to_next($c);
248 7         13 return $char;
249             }
250              
251             sub match_spp_chclass {
252 46     46 0 83 my ($c, $atoms) = @_;
253 46         92 my $char = get_char($c);
254 46         63 for my $atom (@{ atoms($atoms) }) {
  46         77  
255 88 100       170 if (match_spp_catom($atom, $char)) {
256 21         63 to_next($c);
257 21         60 return $char;
258             }
259             }
260 25         66 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 151 my ($atom, $char) = @_;
276 88         150 my ($name, $value) = flat($atom);
277 88         134 given ($name) {
278 88         138 when ('Range') { return match_spp_range($value, $char) }
  0         0  
279 88         114 when ('Cclass') {
280 34         68 return is_match_spp_cclass($value, $char)
281             }
282 54         71 default { return $value eq $char }
  54         152  
283             }
284             }
285              
286             sub match_spp_cclass {
287 40     40 0 77 my ($c, $cclass) = @_;
288 40         80 my $char = get_char($c);
289 40 100       91 if ($char eq End) { return False }
  6         16  
290 34 100       59 if (is_match_spp_cclass($cclass, $char)) {
291 9         20 to_next($c);
292 9         17 return $char;
293             }
294 25         54 return False;
295             }
296              
297             sub is_match_spp_cclass {
298 68     68 0 126 my ($cchar, $char) = @_;
299 68         78 given ($cchar) {
300 68         83 when ('a') { return is_alpha($char) }
  34         106  
301 34         44 when ('A') { return not(is_alpha($char)) }
  0         0  
302 34         40 when ('d') { return is_digit($char) }
  0         0  
303 34         39 when ('D') { return not(is_digit($char)) }
  0         0  
304 34         46 when ('h') { return is_hspace($char) }
  0         0  
305 34         40 when ('H') { return not(is_hspace($char)) }
  0         0  
306 34         42 when ('l') { return is_lower($char) }
  0         0  
307 34         41 when ('L') { return not(is_lower($char)) }
  0         0  
308 34         42 when ('s') { return is_space($char) }
  34         79  
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 34 my ($name, $match, $pos) = @_;
427 14 50       32 if (is_true($match)) { return $match }
  0         0  
428 14         46 my $pos_str = estr_ints($pos);
429 14 100       45 if (is_atom($match)) {
430 1         8 return cons($name, cons($match), $pos_str);
431             }
432 13         62 return cons($name, $match, $pos_str);
433             }
434              
435             sub gather_spp_match {
436 76     76 0 134 my ($gather, $match) = @_;
437 76 100       131 if (is_true($match)) { return $gather }
  13         40  
438 63 100       103 if (is_true($gather)) { return $match }
  36         94  
439 27 100       51 if (is_str($match)) {
440 20 100       37 if (is_str($gather)) { return add($gather, $match) }
  14         35  
441 6         14 return $gather;
442             }
443 7 50       21 if (is_str($gather)) { return $match }
  0         0  
444 7 100       18 if (is_atom($gather)) {
445 6 100       13 if (is_atom($match)) { return cons($gather, $match) }
  3         9  
446 3         17 return eunshift($gather, $match);
447             }
448 1 50       5 if (is_atom($match)) { return epush($gather, $match) }
  1         5  
449 0           return eappend($gather, $match);
450             }
451             1;