File Coverage

blib/lib/Babble/Grammar.pm
Criterion Covered Total %
statement 71 71 100.0
branch 11 14 78.5
condition 2 3 66.6
subroutine 18 18 100.0
pod 0 6 0.0
total 102 112 91.0


line stmt bran cond sub pod time code
1             package Babble::Grammar;
2              
3 12     12   12753 use PPR::X;
  12         541066  
  12         412  
4 12     12   5510 use Mu;
  12         67293  
  12         79  
5 12     12   13041 use strictures 2;
  12         63  
  12         425  
6              
7 12     12   6285 use Babble::Config;
  12         33  
  12         4943  
8              
9 76     76   933 lazy base_grammar_regexp => sub { $PPR::X::GRAMMAR };
10              
11             lazy base_rule_names => sub {
12 76     76   2239 my $g = $_[0]->base_grammar_regexp;
13 76         32327 +{ map +($_ => 1), $g =~ /\(\?<PerlStd(\w+)>/g };
14             };
15              
16             lazy rules => sub {
17 76     76   791 +{ map +($_ => [ undef ]), keys %{ $_[0]->base_rule_names } }
  76         1320  
18             };
19              
20             # global cache of compiled grammar regexps
21             my %COMPILE_CACHE;
22             lazy grammar_regexp => sub {
23 411     411   8831 my ($self) = @_;
24 411         645 my @parts;
25 411         656 foreach my $name (sort keys %{$self->rules}) {
  411         6162  
26 39059         73939 my @layers = @{$self->rules->{$name}};
  39059         577132  
27 39059         298706 foreach my $idx (0..$#layers) {
28 39767 100       96204 next unless defined(my $rule = $layers[$idx]);
29 1143         2401 my $layer_name = $self->_rule_name($name, $idx);
30 1143         3084 my $define = '(?<'.$layer_name.'>'.$rule.')';
31 1143 100       3190 $define = '(?<Perl'.$name.'>'.$define.')' if $idx == $#layers;
32 1143         3393 unshift @parts, $define;
33             }
34             }
35 411         10083 my $base_re = $self->base_grammar_regexp;
36 411 100       328876 return $base_re unless @parts;
37 402         1758 my $define_block = join "\n", '(?(DEFINE)', '', @parts, '', ')';
38             # This stringify is required for Perl v5.18 - v5.28
39             # (RT #126285, RT #144248).
40 402         18389 my $final_re = "${define_block} ${base_re}";
41 402         799 my $_re;
42             return Babble::Config::CACHE_RE ? $COMPILE_CACHE{$final_re} : $_re ||=
43 402   66     104845 do {
44 49         125 warn "Cache miss grammar_regexp: ${define_block}\n" if Babble::Config::CACHE_RE && Babble::Config::DEBUG_CACHE_MISS;
45 12     12   122 use re 'eval';
  12         22  
  12         1019  
46 49         1960689 my $re = qr{$final_re}x;
47 12     12   79 no re 'eval';
  12         23  
  12         7021  
48 49         7440 $re;
49             }
50             };
51              
52             sub _rule_name {
53 1741     1741   3827 my ($self, $name, $index) = @_;
54 1741 100       4695 return 'PerlStd'.$name unless $index;
55 712         3318 return 'PerlWrapper'.$name.'_'.sprintf("%03i", $index);
56             }
57              
58             sub add_rule {
59 294     294 0 2494 my ($self, $name, $rule) = @_;
60 294 50       5023 die "Rule ${name} already exists" if exists $self->rules->{$name};
61 294         6760 $self->rules->{$name} = [ $rule ];
62 294         2741 return $self;
63             }
64              
65             sub replace_rule {
66 10     10 0 36 my ($self, $name, $rule) = @_;
67 10 50       159 die "Rule ${name} does not exist" unless exists $self->rules->{$name};
68 10         266 $self->rules->{$name} = [ $rule ];
69 10         96 return $self;
70             }
71              
72             sub extend_rule {
73 598     598 0 32732 my ($self, $name, $cb) = @_;
74 598 50       9951 die "Rule ${name} does not exist" unless my $r = $self->rules->{$name};
75 598         4981 my $inner_name = $self->_rule_name($name, $#{$r});
  598         2020  
76 598         2190 $self->rules->{$name} = [ @$r, $cb->('(?&'.$inner_name.')') ];
77 598         9316 return $self;
78             }
79              
80             sub augment_rule {
81 281     281 0 689 my ($self, $name, $extra) = @_;
82 281     281   1593 $self->extend_rule($name, sub { join '|', $extra, $_[0] });
  281         5232  
83 281         1106 return $self;
84             }
85              
86             sub clone {
87 606     606 0 17853 my ($self) = @_;
88             return ref($self)->new(
89             base_grammar_regexp => $self->base_grammar_regexp,
90 606         10041 rules => { %{$self->rules} },
  606         12138  
91             );
92             }
93              
94             sub match {
95 7     7 0 4531 my ($self, $as, $text) = @_;
96 7         52 require Babble::Match;
97 7         144 Babble::Match->new(
98             top_rule => $as,
99             text => $text,
100             grammar => $self
101             );
102             }
103              
104             1;