File Coverage

blib/lib/MarpaX/Simple/Rules.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package MarpaX::Simple::Rules;
2 3     3   44246 use strict;
  3         6  
  3         132  
3              
4             our $VERSION='0.2.7';
5              
6 3     3   2485 use Marpa::XS;
  0            
  0            
7             use Data::Dumper;
8             use base 'Exporter';
9              
10             our @EXPORT_OK = qw/parse_rules/;
11              
12             sub Rules { my $m = shift; return { m => $m, rules => \@_ }; }
13             sub Rule { shift; return { @{$_[0]}, @{$_[2]}, @{$_[3]||[]} }; }
14             sub Rule2 { shift; return { @{$_[0]}, rhs => [], @{$_[2]||[]} }; }
15             sub Lhs { shift; return [lhs => $_[0]];}
16             sub Rhs { shift; return [rhs => $_[0]];}
17             sub Star { shift; return [rhs => [ $_[0] ], min => 0]; }
18             sub Plus { shift; return [rhs => [ $_[0] ], min => 1]; }
19             sub Names { shift; return [@_];}
20             sub Null { shift; return [rhs => []]; }
21             sub Action {
22             my (undef, $arrow, $name) = @_;
23             return [action => $name];
24             }
25              
26             sub parse_rules {
27             my ($string) = @_;
28              
29             my $grammar = Marpa::XS::Grammar->new({
30             start => 'Rules',
31             actions => __PACKAGE__,
32             rules => [
33             { lhs => 'Rules', rhs => [qw/Rule/], action => 'Rules', min => 1 },
34              
35             { lhs => 'Rule', rhs => [qw/Lhs DeclareOp Rhs Action/], action => 'Rule' },
36             { lhs => 'Rule', rhs => [qw/Lhs DeclareOp Action/], action => 'Rule2' },
37              
38             { lhs => 'Action', rhs => [], action => 'Action' },
39             { lhs => 'Action', rhs => [qw/ActionArrow ActionName/], action => 'Action' },
40             { lhs => 'Action', rhs => [qw/ActionArrow Name/], action => 'Action' },
41              
42             { lhs => 'Lhs', rhs => [qw/Name/], action => 'Lhs' },
43              
44             { lhs => 'Rhs', rhs => [qw/Names/], action => 'Rhs' },
45             { lhs => 'Rhs', rhs => [qw/Name Plus/], action => 'Plus' },
46             { lhs => 'Rhs', rhs => [qw/Name Star/], action => 'Star' },
47             { lhs => 'Rhs', rhs => [qw/Null/], action => 'Null' },
48              
49             { lhs => 'Names', rhs => [qw/Name/], action => 'Names', min => 1 },
50             ],
51             terminals => [qw/DeclareOp ActionArrow Name ActionName Plus Star Null/],
52             });
53             $grammar->precompute;
54              
55             my $rec = Marpa::XS::Recognizer->new({grammar => $grammar});
56              
57             my @lines = split /\n/, $string;
58             if (!@lines) {
59             return [];
60             }
61              
62             my @terminals = (
63             [ 'DeclareOp', '::=' ],
64             [ 'ActionName', qr/(::(whatever|undef))/ ],
65             [ 'Null', 'Null' ],
66             [ 'ActionArrow', '=>' ],
67             [ 'Plus', '\+' ],
68             [ 'Star', '\*' ],
69             [ 'Name', qr/\w+/, ],
70             );
71              
72             my $nr = 1;
73              
74             LINE: for my $line (@lines) {
75             my @tokens = split /\s+/, $line;
76              
77             TOKEN: for my $token (@tokens) {
78             next if $token =~ m/^\s*$/;
79              
80             for my $t (@terminals) {
81             if ($token =~ m/^($t->[1])/) {
82              
83             if (!$rec->read($t->[0], $2 // $1)) {
84             if ($t->[0] eq 'DeclareOp') {
85             die "Error: Parse exhausted, " . (join ", ", @{$rec->terminals_expected})
86             . " expected before '::=' at line $nr";
87             }
88             else {
89             die "Error: Parse exhausted, " . (join ", ", @{$rec->terminals_expected})
90             . " expected at line $nr";
91             }
92             }
93              
94             $token =~ s/$t->[1]//;
95              
96             if ($token) {
97             redo TOKEN;
98             }
99              
100             next TOKEN;
101             }
102             }
103              
104             die "Error: Found '$token', " . (join ", ", @{$rec->terminals_expected}) . " expected at line $nr";
105             }
106             }
107             continue {
108             $nr++;
109             }
110              
111             #if (grep {$_ eq 'DeclareOp'} @{$rec->terminals_expected}) {
112             #print Dumper($rec->terminals_expected);
113             #$nr--;
114             #die "Input incomplete DeclareOp expected at line $nr";
115             #}
116              
117             #$rec->end_input;
118              
119             my $parse_ref = $rec->value;
120              
121             if (!defined $parse_ref) {
122             return [];
123             }
124              
125             my $parse = $$parse_ref;
126              
127             # if (ref($parse->{m}{error}) eq 'ARRAY' && @{$parse->{m}{error}}) {
128             # die join ": ", @{$parse->{m}{error}};
129             # }
130             return $parse->{rules};
131             }
132              
133             1;
134              
135             __END__