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   95938 use strict;
  3         7  
  3         259  
3              
4             our $VERSION='0.2.6';
5              
6 3     3   11925 use Marpa::XS;
  0            
  0            
7             use base 'Exporter';
8              
9             our @EXPORT_OK = qw/parse_rules/;
10              
11             sub MissingRHS {my $m=shift;push @{$m->{error}}, 'Missing "::=" operator'; }
12             sub MissingLHS {my $m=shift;push @{$m->{error}}, 'Missing name left of "::=" operator'; }
13             sub Rules { my $m = shift; return { m => $m, rules => \@_ }; }
14             sub Rule { shift; return { @{$_[0]}, @{$_[2]}, @{$_[3]||[]} }; }
15             sub Rule2 { shift; return { @{$_[0]}, rhs => [], @{$_[2]||[]} }; }
16             sub Lhs { shift; return [lhs => $_[0]];}
17             sub Rhs { shift; return [rhs => $_[0]];}
18             sub Star { shift; return [rhs => [ $_[0] ], min => 0]; }
19             sub Plus { shift; return [rhs => [ $_[0] ], min => 1]; }
20             sub Names { shift; return [@_];}
21             sub Null { shift; return [rhs => []]; }
22             sub Action {
23             my (undef, $arrow, $name) = @_;
24             return [action => $name];
25             }
26              
27             sub parse_rules {
28             my ($string) = @_;
29              
30             my $grammar = Marpa::XS::Grammar->new({
31             start => 'Rules',
32             actions => __PACKAGE__,
33             rules => [
34             { lhs => 'Rules', rhs => [qw/Rule/], action => 'Rules', min => 1 },
35             { lhs => 'Rule', rhs => [qw/Lhs/], action => 'MissingRHS' },
36             { lhs => 'Rule', rhs => [qw/DeclareOp/], action => 'MissingLHS' },
37             { lhs => 'Rule', rhs => [qw/Lhs DeclareOp Rhs Action/], action => 'Rule' },
38             { lhs => 'Rule', rhs => [qw/Lhs DeclareOp Action/], action => 'Rule2' },
39              
40             { lhs => 'Action', rhs => [], action => 'Action' },
41             { lhs => 'Action', rhs => [qw/ActionArrow ActionName/], action => 'Action' },
42             { lhs => 'Action', rhs => [qw/ActionArrow Name/], action => 'Action' },
43              
44             { lhs => 'Lhs', rhs => [qw/Name/], action => 'Lhs' },
45              
46             { lhs => 'Rhs', rhs => [qw/Names/], action => 'Rhs' },
47             { lhs => 'Rhs', rhs => [qw/Name Plus/], action => 'Plus' },
48             { lhs => 'Rhs', rhs => [qw/Name Star/], action => 'Star' },
49             { lhs => 'Rhs', rhs => [qw/Null/], action => 'Null' },
50              
51             { lhs => 'Names', rhs => [qw/Name/], action => 'Names', min => 1 },
52             ],
53             terminals => [qw/DeclareOp ActionArrow Name ActionName Plus Star Null/],
54             });
55             $grammar->precompute;
56              
57             my $rec = Marpa::XS::Recognizer->new({grammar => $grammar});
58              
59             my @tokens = split /\s+/, $string;
60              
61             if (!@tokens) {
62             return [];
63             }
64              
65             my @terminals = (
66             [ 'DeclareOp', '::=' ],
67             [ 'ActionName', qr/(::(whatever|undef))/ ],
68             [ 'Null', 'Null' ],
69             [ 'ActionArrow', '=>' ],
70             [ 'Plus', '\+' ],
71             [ 'Star', '\*' ],
72             [ 'Name', qr/\w+/, ],
73             );
74              
75             TOKEN: for my $token (@tokens) {
76             next if $token =~ m/^\s*$/;
77              
78             for my $t (@terminals) {
79             if ($token =~ m/^($t->[1])/) {
80             $rec->read($t->[0], $2 // $1);
81             $token =~ s/$t->[1]//;
82             if ($token) {
83             redo TOKEN;
84             }
85             next TOKEN;
86             }
87             }
88             }
89              
90             $rec->end_input;
91              
92             my $parse_ref = $rec->value;
93              
94             if (!defined $parse_ref) {
95             die "Can't parse";
96             }
97             my $parse = $$parse_ref;
98              
99             if (ref($parse->{m}{error}) eq 'ARRAY' && @{$parse->{m}{error}}) {
100             die join ": ", @{$parse->{m}{error}};
101             }
102             return $parse->{rules};
103             }
104              
105             1;
106              
107             __END__