File Coverage

inc/Pegex/Compiler.pm
Criterion Covered Total %
statement 79 106 74.5
branch 22 34 64.7
condition 5 8 62.5
subroutine 14 17 82.3
pod 6 11 54.5
total 126 176 71.5


line stmt bran cond sub pod time code
1             package Pegex::Compiler;
2 3     3   17 use Pegex::Base;
  3         4  
  3         23  
3              
4 3     3   7098 use Pegex::Parser;
  3         7  
  3         73  
5 3     3   2635 use Pegex::Pegex::Grammar;
  3         22228  
  3         42  
6 3     3   2671 use Pegex::Pegex::AST;
  3         24618  
  3         97  
7 3     3   24 use Pegex::Grammar::Atoms;
  3         6  
  3         3010  
8              
9             has tree => ();
10              
11             sub compile {
12 26     26 1 272 my ($self, $grammar, @rules) = @_;
13              
14             # Global request to use the Pegex bootstrap compiler
15 26 50       89 if ($Pegex::Bootstrap) {
16 0         0 require Pegex::Bootstrap;
17 0         0 $self = Pegex::Bootstrap->new;
18             }
19              
20 26         69 @rules = map { s/-/_/g; $_ } @rules;
  0         0  
  0         0  
21              
22 26         86 $self->parse($grammar);
23 26         173 $self->combinate(@rules);
24 26         91 $self->native;
25              
26 26         215 return $self;
27             }
28              
29             sub parse {
30 26     26 1 49 my ($self, $input) = @_;
31              
32 26         155 my $parser = Pegex::Parser->new(
33             grammar => Pegex::Pegex::Grammar->new,
34             receiver => Pegex::Pegex::AST->new,
35             );
36              
37 26         5645 $self->{tree} = $parser->parse($input);
38              
39 26         1385120 return $self;
40             }
41              
42             #-----------------------------------------------------------------------------#
43             # Combination
44             #-----------------------------------------------------------------------------#
45             has _tree => ();
46              
47             sub combinate {
48 26     26 1 84 my ($self, @rule) = @_;
49 26 50       130 if (not @rule) {
50 26 50       144 if (my $rule = $self->{tree}->{'+toprule'}) {
51 26         79 @rule = ($rule);
52             }
53             else {
54 0         0 return $self;
55             }
56             }
57 78         287 $self->{_tree} = {
58 26         57 map {($_, $self->{tree}->{$_})} grep { /^\+/ } keys %{$self->{tree}}
  416         820  
  26         159  
59             };
60 26         110 for my $rule (@rule) {
61 26         109 $self->combinate_rule($rule);
62             }
63 26         78 $self->{tree} = $self->{_tree};
64 26         289 delete $self->{_tree};
65 26         73 return $self;
66             }
67              
68             sub combinate_rule {
69 468     468 0 640 my ($self, $rule) = @_;
70 468 100       1581 return if exists $self->{_tree}->{$rule};
71              
72 286         746 my $object = $self->{_tree}->{$rule} = $self->{tree}->{$rule};
73 286         631 $self->combinate_object($object);
74             }
75              
76             sub combinate_object {
77 1040     1040 0 1301 my ($self, $object) = @_;
78 1040 100       3195 if (exists $object->{'.rgx'}) {
    100          
    100          
    50          
    0          
79 338         725 $self->combinate_re($object);
80             }
81             elsif (exists $object->{'.ref'}) {
82 442         721 my $rule = $object->{'.ref'};
83 442 50       959 if (exists $self->{tree}{$rule}) {
84 442         991 $self->combinate_rule($rule);
85             }
86             else {
87 0 0       0 if (my $regex = (Pegex::Grammar::Atoms::atoms)->{$rule}) {
88 0         0 $self->{tree}{$rule} = { '.rgx' => $regex };
89 0         0 $self->combinate_rule($rule);
90             }
91             }
92             }
93             elsif (exists $object->{'.any'}) {
94 78         110 for my $elem (@{$object->{'.any'}}) {
  78         211  
95 234         482 $self->combinate_object($elem);
96             }
97             }
98             elsif (exists $object->{'.all' }) {
99 182         277 for my $elem (@{$object->{'.all'}}) {
  182         398  
100 520         1133 $self->combinate_object($elem);
101             }
102             }
103             elsif (exists $object->{'.err' }) {
104             }
105             else {
106 0         0 require YAML::XS;
107 0         0 die "Can't combinate:\n" . YAML::XS::Dump($object);
108             }
109             }
110              
111             sub combinate_re {
112 338     338 0 426 my ($self, $regexp) = @_;
113 338         1066 my $atoms = Pegex::Grammar::Atoms->atoms;
114 338         1078 my $re = $regexp->{'.rgx'};
115 338         394 while (1) {
116 5642         6992 $re =~ s[(?']ge;
  0         0  
117 5642         18808 $re =~ s[<([\w\-]+)>][
118 5304         9644 (my $key = $1) =~ s/-/_/g;
119 5304 50 50     35273 $self->{tree}->{$key} and (
      66        
      66        
120             $self->{tree}->{$key}{'.rgx'} or
121             die "'$key' not defined as a single RE"
122             )
123             or $atoms->{$key}
124             or die "'$key' not defined in the grammar"
125             ]e;
126 5642 100       14627 last if $re eq $regexp->{'.rgx'};
127 5304         7393 $regexp->{'.rgx'} = $re;
128             }
129             }
130              
131             #-----------------------------------------------------------------------------#
132             # Compile to native Perl regexes
133             #-----------------------------------------------------------------------------#
134             sub native {
135 26     26 0 60 my ($self) = @_;
136 26         119 $self->perl_regexes($self->{tree});
137 26         76 return $self;
138             }
139              
140             sub perl_regexes {
141 2028     2028 0 2728 my ($self, $node) = @_;
142 2028 100       6115 if (ref($node) eq 'HASH') {
    100          
143 1066 100       1940 if (exists $node->{'.rgx'}) {
144 338         588 my $re = $node->{'.rgx'};
145 338         9273 $node->{'.rgx'} = qr/\G$re/;
146             }
147             else {
148 728         1828 for (keys %$node) {
149 1248         2794 $self->perl_regexes($node->{$_});
150             }
151             }
152             }
153             elsif (ref($node) eq 'ARRAY') {
154 260         5667 $self->perl_regexes($_) for @$node;
155             }
156             }
157              
158             #-----------------------------------------------------------------------------#
159             # Serialization formatter methods
160             #-----------------------------------------------------------------------------#
161             sub to_yaml {
162 0     0 1   require YAML::XS;
163 0           my $self = shift;
164 0           return YAML::XS::Dump($self->tree);
165             }
166              
167             sub to_json {
168 0     0 1   require JSON::XS;
169 0           my $self = shift;
170 0           return JSON::XS->new->utf8->canonical->pretty->encode($self->tree);
171             }
172              
173             sub to_perl {
174 0     0 1   my $self = shift;
175 0           require Data::Dumper;
176 3     3   24 no warnings 'once';
  3         5  
  3         520  
177 0           $Data::Dumper::Terse = 1;
178 0           $Data::Dumper::Indent = 1;
179 0           $Data::Dumper::Sortkeys = 1;
180 0           my $perl = Data::Dumper::Dumper($self->tree);
181 0           $perl =~ s/\?\^:/?-xism:/g;
182 0           $perl =~ s!(\.rgx.*?qr/)\(\?-xism:(.*)\)(?=/)!$1$2!g;
183 0 0         die "to_perl failed with non compatible regex in:\n$perl"
184             if $perl =~ /\?\^/;
185 0           return $perl;
186             }
187              
188             1;