File Coverage

blib/lib/Mylisp/Type.pm
Criterion Covered Total %
statement 29 267 10.8
branch 0 38 0.0
condition n/a
subroutine 10 41 24.3
pod 0 31 0.0
total 39 377 10.3


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