File Coverage

blib/lib/Babble/Grammar.pm
Criterion Covered Total %
statement 68 68 100.0
branch 11 14 78.5
condition 2 3 66.6
subroutine 18 18 100.0
pod 0 6 0.0
total 99 109 90.8


line stmt bran cond sub pod time code
1             package Babble::Grammar;
2              
3 12     12   12375 use PPR::X;
  12         548456  
  12         447  
4 12     12   5982 use Mu;
  12         68660  
  12         76  
5 12     12   13234 use strictures 2;
  12         73  
  12         459  
6              
7 12     12   6390 use Babble::Config;
  12         40  
  12         5103  
8              
9 70     70   889 lazy base_grammar_regexp => sub { $PPR::X::GRAMMAR };
10              
11             lazy base_rule_names => sub {
12 70     70   1732 my $g = $_[0]->base_grammar_regexp;
13 70         30616 +{ map +($_ => 1), $g =~ /\(\?<PerlStd(\w+)>/g };
14             };
15              
16             lazy rules => sub {
17 70     70   795 +{ map +($_ => [ undef ]), keys %{ $_[0]->base_rule_names } }
  70         1291  
18             };
19              
20             # global cache of compiled grammar regexps
21             my %COMPILE_CACHE;
22             lazy grammar_regexp => sub {
23 369     369   8254 my ($self) = @_;
24 369         562 my @parts;
25 369         579 foreach my $name (sort keys %{$self->rules}) {
  369         5584  
26 35069         66262 my @layers = @{$self->rules->{$name}};
  35069         515134  
27 35069         263916 foreach my $idx (0..$#layers) {
28 35699 100       85069 next unless defined(my $rule = $layers[$idx]);
29 1023         2176 my $layer_name = $self->_rule_name($name, $idx);
30 1023         2905 my $define = '(?<'.$layer_name.'>'.$rule.')';
31 1023 100       2899 $define = '(?<Perl'.$name.'>'.$define.')' if $idx == $#layers;
32 1023         3251 unshift @parts, $define;
33             }
34             }
35 369         9137 my $base_re = $self->base_grammar_regexp;
36 369 100       329337 return $base_re unless @parts;
37 360         1679 my $define_block = join "\n", '(?(DEFINE)', '', @parts, '', ')';
38             # This stringify is required for Perl v5.18 - v5.28
39             # (RT #126285, RT #144248).
40 360         16071 my $final_re = "${define_block} ${base_re}";
41 360         719 my $_re;
42             return Babble::Config::CACHE_RE ? $COMPILE_CACHE{$final_re} : $_re = ( Babble::Config::CACHE_RE ? $COMPILE_CACHE{$final_re} : 0 )
43 360   66     156355 || do {
44             warn "Cache miss grammar_regexp: ${define_block}\n" if Babble::Config::CACHE_RE && Babble::Config::DEBUG_CACHE_MISS;
45 12     12   123 use re 'eval';
  12         28  
  12         1126  
46             my $re = qr{$final_re}x;
47 12     12   98 no re 'eval';
  12         31  
  12         7109  
48             $re;
49             }
50             };
51              
52             sub _rule_name {
53 1549     1549   3300 my ($self, $name, $index) = @_;
54 1549 100       4206 return 'PerlStd'.$name unless $index;
55 634         3217 return 'PerlWrapper'.$name.'_'.sprintf("%03i", $index);
56             }
57              
58             sub add_rule {
59 258     258 0 2324 my ($self, $name, $rule) = @_;
60 258 50       4565 die "Rule ${name} already exists" if exists $self->rules->{$name};
61 258         6052 $self->rules->{$name} = [ $rule ];
62 258         2415 return $self;
63             }
64              
65             sub replace_rule {
66 10     10 0 38 my ($self, $name, $rule) = @_;
67 10 50       192 die "Rule ${name} does not exist" unless exists $self->rules->{$name};
68 10         245 $self->rules->{$name} = [ $rule ];
69 10         85 return $self;
70             }
71              
72             sub extend_rule {
73 526     526 0 28945 my ($self, $name, $cb) = @_;
74 526 50       8690 die "Rule ${name} does not exist" unless my $r = $self->rules->{$name};
75 526         4507 my $inner_name = $self->_rule_name($name, $#{$r});
  526         1692  
76 526         1950 $self->rules->{$name} = [ @$r, $cb->('(?&'.$inner_name.')') ];
77 526         8234 return $self;
78             }
79              
80             sub augment_rule {
81 245     245 0 617 my ($self, $name, $extra) = @_;
82 245     245   1406 $self->extend_rule($name, sub { join '|', $extra, $_[0] });
  245         4490  
83 245         951 return $self;
84             }
85              
86             sub clone {
87 534     534 0 17450 my ($self) = @_;
88             return ref($self)->new(
89             base_grammar_regexp => $self->base_grammar_regexp,
90 534         9046 rules => { %{$self->rules} },
  534         10878  
91             );
92             }
93              
94             sub match {
95 7     7 0 5020 my ($self, $as, $text) = @_;
96 7         52 require Babble::Match;
97 7         145 Babble::Match->new(
98             top_rule => $as,
99             text => $text,
100             grammar => $self
101             );
102             }
103              
104             1;