File Coverage

blib/lib/Parse/EBNF/Token.pm
Criterion Covered Total %
statement 96 99 96.9
branch 30 36 83.3
condition 6 6 100.0
subroutine 5 5 100.0
pod 0 5 0.0
total 137 151 90.7


line stmt bran cond sub pod time code
1             package Parse::EBNF::Token;
2            
3             sub new {
4 61     61 0 105 my ($class) = @_;
5 61         162 my $self = bless {}, $class;
6 61         120 $self->{error} = 0;
7 61         123 return $self;
8             }
9            
10             sub reduce_alternations {
11 51     51 0 54 my ($self) = @_;
12            
13 51 100       137 return 1 unless $self->{type} eq 'list';
14            
15            
16             #
17             # reduce our own children first
18             #
19            
20 21         18 for my $token(@{$self->{tokens}}){
  21         62  
21 31         65 $token->reduce_alternations();
22             }
23            
24            
25             #
26             # now check if we have any alts
27             #
28            
29 21         33 my $alts = 0;
30 21         20 for my $token(@{$self->{tokens}}){
  21         44  
31 31 100       76 $alts++ if $token->{type} eq 'alt';
32             }
33            
34 21 100       117 return 1 unless $alts;
35            
36            
37             #
38             # we have alts - change our base type and create new alt children
39             #
40            
41 2         3 my $our_tokens = $self->{tokens};
42 2         3 $self->{tokens} = [];
43 2         3 $self->{type} = 'alternation';
44            
45 2         5 my $current = Parse::EBNF::Token->new();
46 2         3 $current->{type} = 'list';
47 2         4 $current->{tokens} = [];
48            
49 2         3 for my $token(@{$our_tokens}){
  2         3  
50            
51 6 100       13 if ($token->{type} eq 'alt'){
52            
53 2         3 push @{$self->{tokens}}, $current;
  2         3  
54            
55 2         5 $current = Parse::EBNF::Token->new();
56 2         3 $current->{type} = 'list';
57 2         5 $current->{tokens} = [];
58            
59             }else{
60 4         4 push @{$current->{tokens}}, $token;
  4         8  
61             }
62             }
63            
64 2         4 push @{$self->{tokens}}, $current;
  2         3  
65            
66 2         9 return 1;
67             }
68            
69             sub reduce_repetition {
70 53     53 0 60 my ($self) = @_;
71            
72 53 100 100     211 return 1 unless (($self->{type} eq 'list') || ($self->{type} eq 'alternation'));
73            
74             #
75             # reduce our own children first
76             #
77            
78 25         24 for my $token(@{$self->{tokens}}){
  25         44  
79 33         61 $token->reduce_repetition();
80             }
81            
82            
83             #
84             # do it
85             #
86            
87 25         54 my $old_tokens = $self->{tokens};
88 25         38 $self->{tokens} = [];
89            
90 25         30 for my $token(@{$old_tokens}){
  25         33  
91            
92 33 100       71 if ($token->{type} =~ m!^rep (.*)$!){
93            
94 3         8 my $new = Parse::EBNF::Token->new();
95 3         9 $new->{type} = 'repeat '.$1;
96 3         6 $new->{tokens} = [];
97            
98 3         2 my $subject = pop @{$self->{tokens}};
  3         5  
99            
100 3 50       12 unless (defined $subject){
101 0         0 $self->{error} = "repetition operator without suject";
102 0         0 return 0;
103             }
104            
105 3         3 push @{$new->{tokens}}, $subject;
  3         36  
106            
107 3         4 push @{$self->{tokens}}, $new;
  3         8  
108             }else{
109            
110 30         31 push @{$self->{tokens}}, $token;
  30         67  
111             }
112             }
113            
114 25         82 return 1;
115             }
116            
117             sub reduce_empty {
118 53     53 0 66 my ($self) = @_;
119            
120            
121             #
122             # reduce our own children first
123             #
124            
125 53 100       116 if (defined($self->{tokens})){
126 28         658 for my $token(@{$self->{tokens}}){
  28         52  
127 33         57 $token->reduce_empty();
128             }
129             }
130            
131            
132             #
133             # reduce self?
134             #
135            
136 53 100       107 if ($self->{type} eq 'list'){
137 23 100       25 if (scalar(@{$self->{tokens}}) == 1){
  23         50  
138 21         31 my $child = $self->{tokens}->[0];
139            
140 21         19 for my $key(keys %{$self}){ delete $self->{$key}; }
  21         65  
  63         101  
141 21         35 for my $key(keys %{$child}){ $self->{$key} = $child->{$key}; }
  21         61  
  64         122  
142             }
143             }
144            
145 53         169 return 1;
146             }
147            
148             sub reduce_rx {
149 32     32 0 34 my ($self) = @_;
150            
151            
152             #
153             # reduce our own children first
154             #
155            
156 32 100       66 if (defined($self->{tokens})){
157 7         8 for my $token(@{$self->{tokens}}){
  7         12  
158 12         19 $token->reduce_rx();
159             }
160             }
161            
162 32 100 100     193 return 1 unless (($self->{type} eq 'alternation') || ($self->{type} eq 'list'));
163            
164            
165             #
166             # see if we're in a position to reduce self...
167             #
168            
169 4         6 for my $token(@{$self->{tokens}}){
  4         7  
170 5 100       32 next if $token->{type} eq 'literal';
171 3 50       10 next if $token->{type} eq 'rx';
172 3         11 return 1;
173             }
174            
175            
176             #
177             # we can reduce all of our children into a single rx
178             #
179            
180 1         2 my @rx;
181            
182 1         2 for my $token(@{$self->{tokens}}){
  1         3  
183            
184 2 50       5 if ($token->{type} eq 'literal'){
185 2         7 push @rx, '('.quotemeta($token->{content}).')';
186             }
187            
188 2 50       13 if ($token->{type} eq 'rx'){
189 0         0 push @rx, $token->{content};
190             }
191             }
192            
193 1         2 my $rx = '';
194 1 50       4 $rx = join('', @rx) if $self->{type} eq 'list';
195 1 50       5 $rx = join('|', @rx) if $self->{type} eq 'alternation';
196            
197 1         2 $self->{type} = 'rx';
198 1         2 $self->{content} = $rx;
199 1         2 $self->{tokens} = [];
200            
201 1         8 return 1;
202             }
203            
204             1;
205            
206             __END__