File Coverage

blib/lib/Spp.pm
Criterion Covered Total %
statement 92 113 81.4
branch 13 20 65.0
condition n/a
subroutine 18 21 85.7
pod 0 10 0.0
total 123 164 75.0


line stmt bran cond sub pod time code
1             package Spp;
2              
3 2     2   46177 use 5.012;
  2         11  
4 2     2   9 no warnings "experimental";
  2         3  
  2         58  
5              
6 2     2   8 use Exporter;
  2         4  
  2         141  
7             our @ISA = qw(Exporter);
8             our @EXPORT =
9             qw(spp_to_ast ast_to_parser spp_to_parser
10             match_text spp_to_spp parse lint_ast see_ast);
11              
12             our $VERSION = '2.0';
13 2     2   484 use Spp::Builtin;
  2         5  
  2         237  
14 2     2   546 use Spp::Ast;
  2         4  
  2         59  
15 2     2   423 use Spp::Grammar qw(get_grammar);
  2         4  
  2         84  
16 2     2   426 use Spp::Cursor;
  2         5  
  2         56  
17 2     2   573 use Spp::Estr qw(to_estr from_estr flat atoms);
  2         3  
  2         125  
18 2     2   527 use Spp::MatchRule qw(match_rule);
  2         4  
  2         101  
19 2     2   530 use Spp::OptAst qw(opt_ast);
  2         6  
  2         126  
20 2     2   545 use Spp::ToSpp qw(ast_to_spp);
  2         5  
  2         1622  
21              
22             sub ast_to_parser {
23 6     6 0 13 my $ast = shift;
24 6         13 my $table = {};
25 6         14 for my $spec (@{$ast}) {
  6         17  
26 222         262 my ($name, $rule) = @{$spec};
  222         348  
27 222 50       401 if (exists $table->{$name}) {
28 0         0 say "repeated key: |$name|.";
29             }
30 222         463 $table->{$name} = $rule;
31             }
32 6         19 my $door = $ast->[0][0];
33 6         43 return [$door, $table];
34             }
35              
36             sub get_spp_parser {
37 3     3 0 13 my $json_ast = Spp::Ast::get_ast();
38 3         17 my $ast = from_json($json_ast);
39 3         18 lint_ast($ast);
40 3         49 return ast_to_parser($ast);
41             }
42              
43             sub spp_to_ast {
44 0     0 0 0 my $grammar = shift;
45 0         0 my $parser = get_spp_parser();
46 0         0 my $match = match_text($parser, $grammar);
47 0         0 my $ast = opt_ast($match);
48 0         0 lint_ast($ast);
49 0         0 return $ast;
50             }
51              
52             sub spp_to_parser {
53 0     0 0 0 my $grammar = shift;
54 0         0 my $ast = spp_to_ast($grammar);
55 0         0 $ast = clean_ast($ast);
56 0         0 lint_ast($ast);
57 0         0 return ast_to_parser($ast);
58             }
59              
60             sub match_text {
61 3     3 0 11 my ($parser, $text) = @_;
62 3         6 my ($door, $ns) = @{$parser};
  3         8  
63 3         8 my $rule = $ns->{$door};
64 3         30 my $cursor = Spp::Cursor->new($text, $ns);
65 3         21 my $match = match_rule($rule, $cursor);
66 3 50       13 if (is_false($match)) {
67 0         0 say $cursor->max_report;
68 0         0 exit();
69             }
70 3         29 return $match;
71             }
72              
73             sub spp_to_spp {
74 3     3 0 2005 my $str = shift;
75 3         15 my $parser = get_spp_parser();
76 3         12 my $match = match_text($parser, $str);
77 3         18 my $ast = opt_ast($match);
78 3         16 return ast_to_spp($ast);
79             }
80              
81             sub parse {
82 0     0 0 0 my ($grammar, $code) = @_;
83 0         0 my $parser = spp_to_parser($grammar);
84 0         0 my $match = match_text($parser, $code);
85 0 0       0 return $match if is_true($match);
86 0         0 return see_ast($match);
87             }
88              
89             sub lint_ast {
90 3     3 0 8 my $ast = shift;
91 3         13 my $parser = ast_to_parser($ast);
92 3         5 my ($door, $ns) = @{$parser};
  3         13  
93 3         13 check_token($door, $ns);
94 3         8 for my $name (keys %{$ns}) {
  3         37  
95 222 50       362 next if $name eq 'text';
96 222 100       340 next if $name eq $door;
97 219 100       357 next if start_with($name, '*');
98 108         183 my $cname = '*' . $name;
99 108 50       221 if (!exists $ns->{$cname}) {
100 0         0 say "warn! rule: <$name> not used!";
101             }
102             }
103             }
104              
105             sub check_token {
106 171     171 0 284 my ($name, $ns) = @_;
107 171 50       333 if (!exists($ns->{$name})) {
108 0         0 say "not exists token: <$name>";
109             }
110 171         246 my $rule = $ns->{$name};
111 171         282 my $cname = '*' . $name;
112 171 100       426 if (!exists($ns->{$cname})) {
113 111         249 $ns->{$cname} = 1;
114 111         197 check_rule($rule, $ns);
115             }
116             }
117              
118             sub check_rule {
119 561     561 0 863 my ($rule, $ns) = @_;
120 561 100       1007 if (is_str($rule)) { return 1 }
  66         145  
121 495         708 my ($name, $atoms) = @{$rule};
  495         993  
122 495         705 given ($name) {
123 495         1272 when ([qw(Ctoken Ntoken Rtoken)]) {
124 168         338 check_token($atoms, $ns)
125             }
126 327         777 when ([qw(Not Till)]) {
127 3         11 check_rule($atoms, $ns)
128             }
129 324         1152 when ([qw(Rept Look Rules Group Branch)]) {
130 159         209 for my $atom (@{$atoms}) {
  159         332  
131 447         782 check_rule($atom, $ns)
132             }
133             }
134             }
135             }
136              
137             1;