File Coverage

blib/lib/Mylisp/Type.pm
Criterion Covered Total %
statement 29 246 11.7
branch 0 38 0.0
condition n/a
subroutine 10 38 26.3
pod 0 28 0.0
total 39 350 11.1


line stmt bran cond sub pod time code
1             package Mylisp::Type;
2              
3 1     1   13 use 5.012;
  1         3  
4 1     1   4 no warnings 'experimental';
  1         2  
  1         23  
5              
6 1     1   4 use Exporter;
  1         1  
  1         62  
7             our @ISA = qw(Exporter);
8             our @EXPORT =
9             qw(new_lint get_type_parser get_type_cursor match_type pat_to_type_rule opt_pat_match match_type_rule match_type_rules match_type_branch match_type_token match_type_rept match_type_str match_type_end report type_grammar my_type_grammar opt_type_match map_opt_type_atom opt_type_atom opt_type_spec opt_type_atoms gather_type_branch opt_type_str is_branch type_rule_to_pat rules_to_pat branch_to_pat rept_to_pat);
10              
11 1     1   5 use Spp;
  1         4  
  1         50  
12 1     1   5 use Spp::MatchRule;
  1         1  
  1         112  
13 1     1   5 use Spp::Tools;
  1         1  
  1         90  
14 1     1   5 use Spp::Builtin;
  1         2  
  1         154  
15 1     1   5 use Spp::Cursor;
  1         2  
  1         46  
16 1     1   4 use Spp::OptAst;
  1         1  
  1         76  
17 1     1   5 use Spp::LintAst;
  1         2  
  1         1534  
18              
19             sub new_lint {
20 0     0 0   my $parser = get_type_parser();
21 0           my $cursor = get_type_cursor();
22             return {
23 0           'offline' => '',
24             'stack' => [],
25             'st' => {},
26             'ret' => '',
27             'parser' => $parser,
28             'cursor' => $cursor
29             };
30             }
31              
32             sub get_type_parser {
33 0     0 0   my $grammar = type_grammar();
34 0           my $ast = grammar_to_ast($grammar);
35 0           lint_spp_ast($ast);
36 0           my $parser = ast_to_table($ast);
37 0           return $parser;
38             }
39              
40             sub get_type_cursor {
41 0     0 0   my $parser = get_type_parser();
42 0           my $grammar = my_type_grammar();
43 0           my ($match, $ok) = match_text($parser, $grammar);
44 0 0         if ($ok) {
45 0           my $ast = opt_type_match($match);
46 0           lint_spp_ast($ast);
47 0           my $table = ast_to_table($ast);
48 0           my $cursor = new_cursor('text', $table);
49 0           return $cursor;
50             }
51 0           else { error($match) }
52             }
53              
54             sub match_type {
55 0     0 0   my ($t, $rule, $text) = @_;
56 0           my $cursor = $t->{'cursor'};
57 0           $cursor->{'text'} = add($text, End);
58 0           $cursor->{'off'} = 0;
59 0           return match_type_rule($cursor, $rule);
60             }
61              
62             sub pat_to_type_rule {
63 0     0 0   my ($t, $pat) = @_;
64 0           my $table = $t->{'parser'};
65 0           my $rule = $table->{'pat'};
66 0           my $cursor = new_cursor($pat, $table);
67 0           my $match = match_spp_rule($cursor, $rule);
68 0 0         if (is_false($match)) {
69 0           report($t, "pattern: |$pat| could not to rule!");
70             }
71 0           return opt_pat_match($match);
72             }
73              
74             sub opt_pat_match {
75 0     0 0   my $match = shift;
76 0           my $end = cons('End', 'End');
77 0 0         if (is_atom($match)) {
78 0           my $atom = opt_type_atom($match);
79 0           return cons('Rules', cons($atom, $end));
80             }
81 0           my $atoms = opt_type_atoms($match);
82 0 0         if (is_atom($atoms)) {
83 0           return cons('Rules', cons($atoms, $end));
84             }
85 0           return cons('Rules', epush($atoms, $end));
86             }
87              
88             sub match_type_rule {
89 0     0 0   my ($c, $rule) = @_;
90 0 0         if (elen($rule) < 2) {
91 0           say see_ast($rule);
92 0           croak('trace it...');
93             }
94 0           my ($name, $value) = flat($rule);
95 0           given ($name) {
96 0           when ('Rules') { return match_type_rules($c, $value) }
  0            
97 0           when ('Branch') { return match_type_branch($c, $value) }
  0            
98 0           when ('Rept') { return match_type_rept($c, $value) }
  0            
99 0           when ('Str') { return match_type_str($c, $value) }
  0            
100 0           when ('Token') { return match_type_token($c, $value) }
  0            
101 0           when ('End') { return match_type_end($c, $value) }
  0            
102 0           default {
103 0           error("unknown rule: $name to match!");
104 0           return False
105             }
106             }
107             }
108              
109             sub match_type_rules {
110 0     0 0   my ($c, $rules) = @_;
111 0           my $return = False;
112 0           for my $rule (@{ atoms($rules) }) {
  0            
113 0 0         if (is_hspace(get_char($c))) { $c->{'off'}++ }
  0            
114 0           my $match = match_type_rule($c, $rule);
115 0 0         if (is_false($match)) { return False }
  0            
116 0           $return = $match;
117             }
118 0           return $return;
119             }
120              
121             sub match_type_branch {
122 0     0 0   my ($c, $branch) = @_;
123 0           my $off = $c->{'off'};
124 0           for my $rule (@{ atoms($branch) }) {
  0            
125 0           my $match = match_type_rule($c, $rule);
126 0 0         if (not(is_false($match))) { return $match }
  0            
127 0           $c->{'off'} = $off;
128             }
129 0           return False;
130             }
131              
132             sub match_type_token {
133 0     0 0   my ($c, $name) = @_;
134 0           my $table = $c->{'ns'};
135 0           my $rule = $table->{$name};
136 0           return match_type_rule($c, $rule);
137             }
138              
139             sub match_type_rept {
140 0     0 0   my ($c, $rule) = @_;
141 0           my ($rept, $atom) = flat($rule);
142 0           my ($min, $max) = get_rept_time($rept);
143 0           my $time = 0;
144 0           while ($time != $max) {
145 0           my $off = $c->{'off'};
146 0 0         if (is_hspace(get_char($c))) { $c->{'off'}++ }
  0            
147 0           my $match = match_type_rule($c, $atom);
148 0 0         if (is_false($match)) {
149 0 0         if ($time < $min) { return False }
  0            
150 0           $c->{'off'} = $off;
151 0           return True;
152             }
153 0           $time++;
154             }
155 0           return True;
156             }
157              
158             sub match_type_str {
159 0     0 0   my ($c, $str) = @_;
160 0           for my $char (split '', $str) {
161 0 0         if ($char ne get_char($c)) { return False }
  0            
162 0           $c->{'off'}++;
163             }
164 0           return True;
165             }
166              
167             sub match_type_end {
168 0     0 0   my ($c, $end) = @_;
169 0 0         if (get_char($c) eq End) { return True }
  0            
170 0           return False;
171             }
172              
173             sub report {
174 0     0 0   my ($t, $message) = @_;
175 0           my $offline = $t->{'offline'};
176 0           my $line = value($offline);
177 0           error("error! line: $line $message");
178 0           return False;
179             }
180              
181             sub type_grammar {
182             return <<'EOF'
183              
184             door = |\s+ Spec|+ $ ;
185             Spec = Token \h+ '=' \h+ pat ;
186             pat = |\h Branch Token Str Rept|+ ;
187             Branch = '|' ;
188             Token = \a+ ;
189             Str = ':' \a+ ;
190             Rept = [+?] ;
191            
192             EOF
193 0     0 0   }
194              
195             sub my_type_grammar {
196             return <<'EOF'
197              
198             door = Bool|Int|StrOrArray|Ints|Map|Fn|Lint|Cursor
199             Bool = :Bool
200             Str = :Str|:String|:Lstr|:Char
201             Int = :Int
202             Array = :Array
203             Ints = :Ints
204             Hash = :Hash
205             Table = :Table
206             Cursor = :Cursor
207             Lint = :Lint
208             Fn = :Fn
209             StrOrArray = Str|Array
210             Map = Hash|Table
211            
212             EOF
213 0     0 0   }
214              
215             sub opt_type_match {
216 0     0 0   my $match = shift;
217 0 0         if (is_atom($match)) { return opt_type_atom($match) }
  0            
218 0           return map_opt_type_atom($match);
219             }
220              
221             sub map_opt_type_atom {
222 0     0 0   my $atoms = shift;
223             return estr(
224 0           [map { opt_type_atom($_) } @{ atoms($atoms) }]);
  0            
  0            
225             }
226              
227             sub opt_type_atom {
228 0     0 0   my $atom = shift;
229 0           my ($name, $value) = flat($atom);
230 0           given ($name) {
231 0           when ('Spec') { return opt_type_spec($value) }
  0            
232 0           when ('Str') { return opt_type_str($value) }
  0            
233 0           when ('Rept') { return cons('rept', $value) }
  0            
234 0           when ('Branch') { return cons('branch', $value) }
  0            
235 0           when ('Token') { return cons('Token', $value) }
  0            
236 0           default { say "unknown atom: |$name|" }
  0            
237             }
238             }
239              
240             sub opt_type_spec {
241 0     0 0   my $atoms = shift;
242 0           my ($token, $rules) = match($atoms);
243 0           my $name = value($token);
244 0           my $rule = opt_type_atoms($rules);
245 0           return cons($name, $rule);
246             }
247              
248             sub opt_type_atoms {
249 0     0 0   my $atoms = shift;
250 0           $atoms = map_opt_type_atom($atoms);
251 0           $atoms = gather_spp_rept($atoms);
252 0           $atoms = gather_type_branch($atoms);
253 0           return $atoms;
254             }
255              
256             sub gather_type_branch {
257 0     0 0   my $atoms = shift;
258 0           my $branches = [];
259 0           my $branch = [];
260 0           my $flag = 0;
261 0           my $count = 0;
262 0           for my $atom (@{ atoms($atoms) }) {
  0            
263 0 0         if (is_branch($atom)) {
264 0 0         if ($count > 1) {
265 0           push @{$branches}, cons('Rules', estr($branch));
  0            
266             }
267 0           else { push @{$branches}, $branch->[0]; }
  0            
268 0           $flag = 1;
269 0           $branch = [];
270 0           $count = 0;
271             }
272 0           else { push @{$branch}, $atom; $count++ }
  0            
  0            
273             }
274 0 0         if ($flag == 0) {
275 0 0         if ($count == 1) { return $branch->[0] }
  0            
276 0           else { return cons('Rules', estr($branch)) }
277             }
278 0 0         if ($count > 1) {
279 0           push @{$branches}, cons('Rules', estr($branch));
  0            
280             }
281 0           else { push @{$branches}, $branch->[0]; }
  0            
282 0           return cons('Branch', estr($branches));
283             }
284              
285             sub opt_type_str {
286 0     0 0   my $str = shift;
287 0           return cons('Str', rest_str($str));
288             }
289              
290             sub is_branch {
291 0     0 0   my $atom = shift;
292 0           return is_atom_name($atom, 'branch');
293             }
294              
295             sub type_rule_to_pat {
296 0     0 0   my $pat = shift;
297 0           my ($name, $value) = flat($pat);
298 0           given ($name) {
299 0           when ('Rules') { return rules_to_pat($value) }
  0            
300 0           when ('Branch') { return branch_to_pat($value) }
  0            
301 0           when ('Rept') { return rept_to_pat($value) }
  0            
302 0           when ('Str') { return ":$value" }
  0            
303 0           when ('Token') { return $value }
  0            
304 0           when ('End') { return '$' }
  0            
305 0           default { say "unknown pat name: |$name| to str" }
  0            
306             }
307             }
308              
309             sub rules_to_pat {
310 0     0 0   my $atoms = shift;
311             my $strs =
312 0           [map { type_rule_to_pat($_) } @{ atoms($atoms) }];
  0            
  0            
313 0           return join ' ', @{$strs};
  0            
314             }
315              
316             sub branch_to_pat {
317 0     0 0   my $atoms = shift;
318             my $strs =
319 0           [map { type_rule_to_pat($_) } @{ atoms($atoms) }];
  0            
  0            
320 0           return join '|', @{$strs};
  0            
321             }
322              
323             sub rept_to_pat {
324 0     0 0   my $rule = shift;
325 0           my ($rept, $atom) = flat($rule);
326 0           my $atom_str = type_rule_to_pat($atom);
327 0           return add($atom_str, $rept);
328             }
329             1;