File Coverage

blib/lib/Mylisp/LintAst.pm
Criterion Covered Total %
statement 17 520 3.2
branch 0 52 0.0
condition n/a
subroutine 6 48 12.5
pod 0 42 0.0
total 23 662 3.4


line stmt bran cond sub pod time code
1             package Mylisp::LintAst;
2              
3 1     1   899 use 5.012;
  1         4  
4 1     1   4 no warnings 'experimental';
  1         2  
  1         26  
5              
6 1     1   5 use Exporter;
  1         1  
  1         66  
7             our @ISA = qw(Exporter);
8             our @EXPORT =
9             qw(lint_my_ast init_my_lint use_package load_package load_ast regist_func get_my_atoms_value regist_const lint_my_atoms lint_my_atom lint_my_exprs lint_my_block lint_my_func get_return_type_str arg_type_to_return lint_my_return get_args_type_str lint_my_my lint_my_our lint_my_call lint_my_for lint_my_set lint_my_sym_list lint_my_sym is_define get_atom_type get_sym_type get_call_type get_array_type get_arange_type get_iter_type lint_my_aindex get_aindex_type get_index_type update_pos ns in_package in_ns out_block out_ns set_name_value get_name_value);
10              
11 1     1   5 use Spp::Builtin;
  1         1  
  1         164  
12 1     1   6 use Spp::Tools;
  1         4  
  1         95  
13 1     1   242 use Mylisp::Type;
  1         2  
  1         3149  
14              
15             sub lint_my_ast {
16 0     0 0   my $ast = shift;
17 0           my $t = new_lint();
18 0           print 'load package .. ';
19 0           init_my_lint($t, $ast);
20 0           print "load ok!\n";
21 0           lint_my_atoms($t, $ast);
22 0           return True;
23             }
24              
25             sub init_my_lint {
26 0     0 0   my ($t, $ast) = @_;
27 0           for my $expr (@{ atoms($ast) }) {
  0            
28 0           my ($name, $args) = flat($expr);
29 0           update_pos($t, $expr);
30 0           given ($name) {
31 0           when ('package') { in_package($t, $args) }
  0            
32 0           when ('use') { use_package($t, $args) }
  0            
33 0           when ('const') { regist_const($t, $args) }
  0            
34 0           when ('func') { regist_func($t, $args) }
  0            
35             }
36             }
37 0           return True;
38             }
39              
40             sub use_package {
41 0     0 0   my ($t, $args) = @_;
42 0           load_package($t, $args);
43 0           my $table = $t->{'st'}{$args};
44 0           for my $name (keys %{$table}) {
  0            
45 0 0         next if start_with($name, '_');
46 0           my $value = $table->{$name};
47 0           set_name_value($t, $name, $value);
48             }
49 0           return True;
50             }
51              
52             sub load_package {
53 0     0 0   my ($t, $package) = @_;
54 0           my $dirs = [split '::', $package];
55 0           my $path = join '/', @{$dirs};
  0            
56 0           my $ast_file = add($path, ".spp.estr");
57 0           my $ast = read_file($ast_file);
58 0           load_ast($t, $ast);
59 0           return True;
60             }
61              
62             sub load_ast {
63 0     0 0   my ($t, $ast) = @_;
64 0           for my $expr (@{ atoms($ast) }) {
  0            
65 0           my ($name, $args) = flat($expr);
66 0           update_pos($t, $expr);
67 0           given ($name) {
68 0           when ('package') { in_package($t, $args) }
  0            
69 0           when ('func') { regist_func($t, $args) }
  0            
70 0           when ('const') { regist_const($t, $args) }
  0            
71 0           when ('end') { out_ns($t) }
  0            
72             }
73             }
74 0           return True;
75             }
76              
77             sub regist_func {
78 0     0 0   my ($t, $atoms) = @_;
79 0           my ($name_args, $return) = flat($atoms);
80 0           my $return_type = get_my_atoms_value(value($return));
81 0           my ($name, $args) = flat($name_args);
82 0 0         if (is_blank($args)) {
83 0           set_name_value($t, $name, $return_type);
84             }
85             else {
86 0           my $args_type = get_my_atoms_value($args);
87 0           my $value = cons($args_type, $return_type);
88 0           set_name_value($t, $name, $value);
89             }
90 0           return True;
91             }
92              
93             sub get_my_atoms_value {
94 0     0 0   my $atoms = shift;
95 0           my $names = [map { value($_) } @{ atoms($atoms) }];
  0            
  0            
96 0           return join ' ', @{$names};
  0            
97             }
98              
99             sub regist_const {
100 0     0 0   my ($t, $args) = @_;
101 0           my ($sym, $value) = flat($args);
102 0           my $name = value($sym);
103 0           my $value_type = get_atom_type($t, $value);
104 0           set_name_value($t, $name, $value_type);
105 0           return True;
106             }
107              
108             sub lint_my_atoms {
109 0     0 0   my ($t, $atoms) = @_;
110 0           for my $atom (@{ atoms($atoms) }) {
  0            
111 0           lint_my_atom($t, $atom);
112             }
113 0           return True;
114             }
115              
116             sub lint_my_atom {
117 0     0 0   my ($t, $atom) = @_;
118 0           my ($name, $args) = flat($atom);
119 0           update_pos($t, $atom);
120 0           given ($name) {
121 0           when ('func') { lint_my_func($t, $args) }
  0            
122 0           when ('return') { lint_my_return($t, $args) }
  0            
123 0           when ('my') { lint_my_my($t, $args) }
  0            
124 0           when ('our') { lint_my_our($t, $args) }
  0            
125 0           when ('=') { lint_my_set($t, $args) }
  0            
126 0           when ('Sym') { lint_my_sym($t, $args) }
  0            
127 0           when ('Aindex') { lint_my_aindex($t, $args) }
  0            
128 0           when ('for') { lint_my_for($t, $args) }
  0            
129 0           when ('while') { lint_my_exprs($t, $args) }
  0            
130 0           when ('given') { lint_my_exprs($t, $args) }
  0            
131 0           when ('when') { lint_my_exprs($t, $args) }
  0            
132 0           when ('if') { lint_my_exprs($t, $args) }
  0            
133 0           when ('elif') { lint_my_exprs($t, $args) }
  0            
134 0           when ('then') { lint_my_block($t, $args) }
  0            
135 0           when ('else') { lint_my_block($t, $args) }
  0            
136 0           when ('String') { lint_my_atoms($t, $args) }
  0            
137 0           when ('Array') { lint_my_atoms($t, $args) }
  0            
138 0           when ('Hash') { lint_my_atoms($t, $args) }
  0            
139 0           when ('Pair') { lint_my_atoms($t, $args) }
  0            
140 0           when ('end') { out_ns($t) }
  0            
141 0           when ('package') { return True }
  0            
142 0           when ('const') { return True }
  0            
143 0           when ('Str') { return True }
  0            
144 0           when ('Lstr') { return True }
  0            
145 0           when ('Int') { return True }
  0            
146 0           when ('Char') { return True }
  0            
147 0           when ('Bool') { return True }
  0            
148 0           when ('Type') { return True }
  0            
149 0           when ('Lint') { return True }
  0            
150 0           when ('Cursor') { return True }
  0            
151 0           when ('use') { return True }
  0            
152 0           when ('->') { return True }
  0            
153 0           default { lint_my_call($t, $name, $args) }
  0            
154             }
155             }
156              
157             sub lint_my_exprs {
158 0     0 0   my ($t, $atoms) = @_;
159 0           my ($cond_atom, $exprs) = match($atoms);
160 0           lint_my_atom($t, $cond_atom);
161 0           lint_my_block($t, $exprs);
162 0           return True;
163             }
164              
165             sub lint_my_block {
166 0     0 0   my ($t, $exprs) = @_;
167 0           my $uuid = uuid();
168 0           in_ns($t, $uuid);
169 0           lint_my_atoms($t, $exprs);
170 0           out_block($t, $uuid);
171 0           return True;
172             }
173              
174             sub lint_my_func {
175 0     0 0   my ($t, $args) = @_;
176 0           my ($name_args, $rest) = match($args);
177 0           my ($return, $atoms) = match($rest);
178 0           my $return_type_str = get_return_type_str($return);
179 0           $t->{'ret'} = $return_type_str;
180 0           my ($call, $func_args) = flat($name_args);
181 0           in_ns($t, $call);
182 0           for my $arg (@{ atoms($func_args) }) {
  0            
183 0           my ($name, $type) = flat($arg);
184 0           set_name_value($t, $name, $type);
185             }
186 0           lint_my_atoms($t, $atoms);
187 0           out_ns($t);
188 0           return True;
189             }
190              
191             sub get_return_type_str {
192 0     0 0   my $expr = shift;
193 0           my $args = value($expr);
194 0           my $names = [map { value($_) } @{ atoms($args) }];
  0            
  0            
195 0           my $types = [map { arg_type_to_return($_) } @{$names}];
  0            
  0            
196 0           return join ' ', @{$types};
  0            
197             }
198              
199             sub arg_type_to_return {
200 0     0 0   my $type = shift;
201 0           given ($type) {
202 0           when ('Str+') { return 'Array' }
  0            
203 0           when ('Int+') { return 'Ints' }
  0            
204 0           default { return $type }
  0            
205             }
206             }
207              
208             sub lint_my_return {
209 0     0 0   my ($t, $args) = @_;
210 0           my $call = ns($t);
211 0           my $return_type = $t->{'ret'};
212 0           my $args_type_str = get_args_type_str($t, $args);
213 0           my $args_pat = pat_to_type_rule($t, $args_type_str);
214 0           my $match = match_type($t, $args_pat, $return_type);
215 0           lint_my_atoms($t, $args);
216 0 0         if (is_false($match)) {
217 0           say "return type is not same with call declare";
218 0           say "|$args_type_str| != |$return_type|";
219             }
220 0           return True;
221             }
222              
223             sub get_args_type_str {
224 0     0 0   my ($t, $atoms) = @_;
225 0           my $types = [];
226 0           for my $atom (@{ atoms($atoms) }) {
  0            
227 0           push @{$types}, get_atom_type($t, $atom);
  0            
228             }
229 0           return join ' ', @{$types};
  0            
230             }
231              
232             sub lint_my_my {
233 0     0 0   my ($t, $args) = @_;
234 0           my ($sym, $value) = flat($args);
235 0           lint_my_atom($t, $value);
236 0           my $type = get_atom_type($t, $value);
237 0           my $name = value($sym);
238 0 0         if (is_str($type)) { set_name_value($t, $name, $type) }
  0            
239 0           else { report($t, "one sym accept more assign") }
240 0           return True;
241             }
242              
243             sub lint_my_our {
244 0     0 0   my ($t, $args) = @_;
245 0           my ($array, $value) = flat($args);
246 0           lint_my_atom($t, $value);
247 0           my $type = get_atom_type($t, $value);
248 0           my $types = [split ' ', $type];
249 0           my $syms = value($array);
250 0           lint_my_sym_list($t, $syms);
251 0           my ($a, $b) = flat($syms);
252              
253 0 0         if (len($types) != 2) {
254 0           report($t, "return value not two");
255             }
256 0           my $a_name = value($a);
257 0           my $b_name = value($b);
258 0           my $a_type = $types->[0];
259 0           my $b_type = $types->[1];
260 0           set_name_value($t, $a_name, $a_type);
261 0           set_name_value($t, $b_name, $b_type);
262 0           return True;
263             }
264              
265             sub lint_my_call {
266 0     0 0   my ($t, $name, $args) = @_;
267 0           my $value = get_name_value($t, $name);
268 0 0         if (is_blank($args)) {
269 0 0         if (is_estr($value)) {
270 0           report($t, "call |$name| less argument");
271             }
272 0           return True;
273             }
274 0 0         if (is_str($value)) {
275 0           report($t, "call |$name| more argument");
276             }
277 0           my $call_type_str = name($value);
278 0           lint_my_atoms($t, $args);
279 0           my $args_type_str = get_args_type_str($t, $args);
280 0           my $call_rule = pat_to_type_rule($t, $call_type_str);
281             # say see_ast($call_rule);
282 0           my $match = match_type($t, $call_rule, $args_type_str);
283 0 0         if (is_false($match)) {
284 0           say "|$call_type_str| != |$args_type_str|";
285 0           report($t, "call |$name| args type not same!");
286             }
287 0           return True;
288             }
289              
290             sub lint_my_for {
291 0     0 0   my ($t, $args) = @_;
292 0           my ($iter_expr, $exprs) = match($args);
293 0           my ($name, $iter_atom) = flat($iter_expr);
294 0           my $type = get_iter_type($t, $iter_atom);
295 0           set_name_value($t, $name, $type);
296 0           lint_my_block($t, $exprs);
297             }
298              
299             sub lint_my_set {
300 0     0 0   my ($t, $args) = @_;
301 0           my ($sym, $value) = flat($args);
302 0           my $sym_type = get_atom_type($t, $sym);
303 0           my $value_type = get_atom_type($t, $value);
304 0 0         if ($sym_type ne $value_type) {
305 0           say "|$sym_type| != |$value_type|";
306 0           report($t, "assign type not same with define!");
307             }
308             }
309              
310             sub lint_my_sym_list {
311 0     0 0   my ($t, $list) = @_;
312 0           for my $sym (@{ atoms($list) }) {
  0            
313 0 0         next if is_sym($sym);
314 0           report($t, "Symbol List have no variable!");
315             }
316             }
317              
318             sub lint_my_sym {
319 0     0 0   my ($t, $name) = @_;
320 0 0         if (not(is_define($t, $name))) {
321 0           report($t, "not defined symbol: |$name|");
322             }
323             }
324              
325             sub is_define {
326 0     0 0   my ($t, $name) = @_;
327 0           my $stack = $t->{'stack'};
328 0           for my $ns (@{$stack}) {
  0            
329 0           my $stable = $t->{'st'};
330 0 0         if (exists $stable->{$ns}{$name}) { return 1 }
  0            
331             }
332 0           return 0;
333             }
334              
335             sub get_atom_type {
336 0     0 0   my ($t, $atom) = @_;
337 0           my ($name, $value) = flat($atom);
338 0           update_pos($t, $atom);
339 0           given ($name) {
340 0           when ('Type') { return $value }
  0            
341 0           when ('Int') { return $name }
  0            
342 0           when ('Str') { return $name }
  0            
343 0           when ('Bool') { return $name }
  0            
344 0           when ('Hash') { return $name }
  0            
345 0           when ('Char') { return 'Str' }
  0            
346 0           when ('Lstr') { return 'Str' }
  0            
347 0           when ('String') { return 'Str' }
  0            
348 0           when ('Cursor') { return 'Cursor' }
  0            
349 0           when ('Lint') { return 'Lint' }
  0            
350 0           when ('Array') { return get_array_type($t, $value) }
  0            
351 0           when ('Aindex') { return get_aindex_type($t, $value) }
  0            
352 0           when ('Sym') { return get_sym_type($t, $value) }
  0            
353 0           when ('if') { report($t, "$name as argument") }
  0            
354 0           when ('elif') { report($t, "$name as argument") }
  0            
355 0           when ('else') { report($t, "$name as argument") }
  0            
356 0           when ('given') { report($t, "$name as argument") }
  0            
357 0           when ('when') { report($t, "$name as argument") }
  0            
358 0           when ('then') { report($t, "$name as argument") }
  0            
359 0           when ('func') { report($t, "$name as argument") }
  0            
360 0           when ('my') { report($t, "$name as argument") }
  0            
361 0           when ('our') { report($t, "$name as argument") }
  0            
362 0           when ('use') { report($t, "$name as argument") }
  0            
363 0           when ('import') { report($t, "$name as argument") }
  0            
364 0           when ('package') { report($t, "$name as argument") }
  0            
365 0           when ('const') { report($t, "$name as argument") }
  0            
366 0           when ('for') { report($t, "$name as argument") }
  0            
367 0           when ('while') { report($t, "$name as argument") }
  0            
368 0           when ('return') { report($t, "$name as argument") }
  0            
369 0           default { return get_call_type($t, $name, $value) }
  0            
370             }
371             }
372              
373             sub get_sym_type {
374 0     0 0   my ($t, $name) = @_;
375 0           my $value = get_name_value($t, $name);
376 0 0         if (is_str($value)) { return $value }
  0            
377 0           return 'Fn';
378             }
379              
380             sub get_call_type {
381 0     0 0   my ($t, $name, $args) = @_;
382 0           my $value = get_name_value($t, $name);
383 0 0         if (is_str($value)) { return $value }
  0            
384 0           return value($value);
385             }
386              
387             sub get_array_type {
388 0     0 0   my ($t, $args) = @_;
389 0 0         if (is_blank($args)) { return 'Array' }
  0            
390 0           my $sub_type = get_atom_type($t, name($args));
391 0 0         if ($sub_type eq 'Int') { return 'Ints' }
  0            
392 0           return 'Array';
393             }
394              
395             sub get_arange_type {
396 0     0 0   my ($t, $args) = @_;
397 0           my $sym = name($args);
398 0           my $type = get_atom_type($t, $sym);
399 0 0         if ($type eq 'Array') { return $type }
  0            
400 0           report($t, "Not Array arange");
401             }
402              
403             sub get_iter_type {
404 0     0 0   my ($t, $atom) = @_;
405 0           my $type = get_atom_type($t, $atom);
406 0           given ($type) {
407 0           when ('Array') { return 'Str' }
  0            
408 0           when ('Hash') { return 'Str' }
  0            
409 0           when ('Str') { return 'Str' }
  0            
410 0           when ('Ints') { return 'Int' }
  0            
411 0           when ('Int+') { return 'Int' }
  0            
412 0           when ('Str+') { return 'Str' }
  0            
413 0           default { report($t, "|$type| could not index") }
  0            
414             }
415 0           return True;
416             }
417              
418             sub lint_my_aindex {
419 0     0 0   my ($t, $args) = @_;
420 0           lint_my_atoms($t, $args);
421 0           return True;
422             }
423              
424             sub get_aindex_type {
425 0     0 0   my ($t, $args) = @_;
426 0           my ($sym, $indexs) = match($args);
427 0           my $value = get_atom_type($t, $sym);
428 0           for my $index (@{ atoms($indexs) }) {
  0            
429 0           my $type = get_atom_type($t, $index);
430 0           my $name = value($index);
431 0           $value = get_index_type($t, $value, $type, $name);
432             }
433 0           return $value;
434             }
435              
436             sub get_index_type {
437 0     0 0   my ($t, $value, $type, $name) = @_;
438 0           given ($value) {
439 0           when ('Array') {
440 0 0         if ($type eq 'Int') { return 'Str' }
  0            
441 0           report($t, "Array index is: $type")
442             }
443 0           when ('Ints') {
444 0 0         if ($type eq 'Int') { return 'Int' }
  0            
445 0           report($t, "Ints index is $type")
446             }
447 0           when ('Hash') {
448 0 0         if ($type eq 'Str') { return 'Str' }
  0            
449 0           report($t, "Hash index is: |$type|")
450             }
451 0           when ('Table') {
452 0 0         if ($type eq 'Str') { return 'Hash' }
  0            
453 0           report($t, "Table index is: |$type|")
454             }
455 0           when ('Cursor') {
456 0 0         if ($type eq 'Str') {
457 0           given ($name) {
458 0           when ('text') { return 'Str' }
  0            
459 0           when ('ns') { return 'Hash' }
  0            
460 0           when ('off') { return 'Int' }
  0            
461 0           when ('depth') { return 'Int' }
  0            
462 0           when ('len') { return 'Int' }
  0            
463 0           when ('line') { return 'Int' }
  0            
464 0           when ('maxline') { return 'Int' }
  0            
465 0           when ('maxoff') { return 'Int' }
  0            
466 0           default { report($t, "Cursor !exists $name") }
  0            
467             }
468             }
469 0           report($t, "Cursor index is: |$type|")
470             }
471 0           when ('Lint') {
472 0 0         if ($type eq 'Str') {
473 0           given ($name) {
474 0           when ('offline') { return 'Str' }
  0            
475 0           when ('st') { return 'Table' }
  0            
476 0           when ('stack') { return 'Array' }
  0            
477 0           when ('ret') { return 'Str' }
  0            
478 0           when ('parser') { return 'Hash' }
  0            
479 0           when ('cursor') { return 'Cursor' }
  0            
480 0           default { report($t, "Lint !exists $name") }
  0            
481             }
482             }
483 0           report($t, "Lint index is: |$type|")
484             }
485 0           default { report($t, "Could not index: $value") }
  0            
486             }
487 0           return True;
488             }
489              
490             sub update_pos {
491 0     0 0   my ($t, $atom) = @_;
492 0           $t->{'offline'} = offline($atom);
493 0           return True;
494             }
495              
496             sub ns {
497 0     0 0   my $t = shift;
498 0           my $stack = $t->{'stack'};
499 0           return $stack->[0];
500             }
501              
502             sub in_package {
503 0     0 0   my ($t, $ns) = @_;
504 0           in_ns($t, $ns);
505 0           set_name_value($t, $ns, 'package');
506 0           return True;
507             }
508              
509             sub in_ns {
510 0     0 0   my ($t, $ns) = @_;
511 0           $t->{'st'}{$ns} = {};
512 0           unshift @{ $t->{'stack'} }, $ns;
  0            
513 0           return True;
514             }
515              
516             sub out_block {
517 0     0 0   my ($t, $ns) = @_;
518 0           out_ns($t);
519 0           my $table = $t->{'st'};
520 0           delete $table->{$ns};
521 0           return True;
522             }
523              
524             sub out_ns {
525 0     0 0   my $t = shift;
526 0           shift @{ $t->{'stack'} };
  0            
527 0           return True;
528             }
529              
530             sub set_name_value {
531 0     0 0   my ($t, $name, $value) = @_;
532 0           my $ns = ns($t);
533 0           my $stable = $t->{'st'};
534 0 0         if (exists $stable->{$ns}{$name}) {
535 0           report($t, "exists symbol define |$name|.");
536             }
537 0           $t->{'st'}{$ns}{$name} = $value;
538 0           return True;
539             }
540              
541             sub get_name_value {
542 0     0 0   my ($t, $name) = @_;
543 0           my $stack = $t->{'stack'};
544 0           for my $ns (@{$stack}) {
  0            
545 0           my $stable = $t->{'st'};
546 0 0         if (exists $stable->{$ns}{$name}) {
547 0           return $t->{'st'}{$ns}{$name};
548             }
549             }
550 0           report($t, "symbol <$name> not define!");
551 0           return False;
552             }
553             1;