File Coverage

blib/lib/ABNF/Generator.pm
Criterion Covered Total %
statement 145 203 71.4
branch 42 122 34.4
condition 13 38 34.2
subroutine 35 43 81.4
pod n/a
total 235 406 57.8


line stmt bran cond sub pod time code
1             package ABNF::Generator;
2              
3             =pod
4              
5             =head1 NAME
6              
7             B<ABNF::Generator> - abstract base class for ABNF-based generators
8              
9             =head1 INHERITANCE
10              
11             B<ABNF::Generator> is the root of the Honest and Liar generators
12              
13             =head1 DESCRIPTION
14              
15             B<ABNF::Generator> is the abstract base class for ABNF-based generators.
16              
17             Also it provides function B<asStrings> to stringified generated sequences
18              
19             =head1 METHODS
20              
21             =cut
22              
23 2     2   57 use 5.014;
  2         8  
  2         81  
24              
25 2     2   12 use strict;
  2         5  
  2         69  
26 2     2   10 use warnings;
  2         4  
  2         68  
27 2     2   10 no warnings "recursion";
  2         5  
  2         85  
28              
29 2     2   15 use Carp;
  2         3  
  2         141  
30 2     2   13 use Readonly;
  2         5  
  2         91  
31 2     2   11 use Method::Signatures;
  2         5  
  2         24  
32 2     2   882 use Data::Dumper;
  2         4  
  2         114  
33              
34 2     2   13 use Parse::ABNF;
  2         2  
  2         66  
35 2     2   16 use List::Util qw(shuffle);
  2         5  
  2         181  
36              
37 2     2   12 use ABNF::Grammar qw($BASIC_RULES splitRule);
  2         4  
  2         206  
38 2     2   12 use ABNF::Validator;
  2         4  
  2         98  
39              
40 2     2   12 use base qw(Exporter);
  2         4  
  2         471  
41             our @EXPORT_OK = qw($CONVERTERS $BASIC_RULES $RECURSION_LIMIT);
42              
43             Readonly our $CHOICE_LIMIT => 128;
44              
45             Readonly our $CONVERTERS => {
46             "hex" => sub { hex($_[0]) },
47             "bin" => sub { oct($_[0]) },
48             "decimal" => sub { int($_[0]) },
49             };
50              
51             =pod
52              
53             =head1 ABNF::Generator->C<new>($grammar, $validator?)
54              
55             Creates a new B<ABNF::Generator> object.
56              
57             $grammar isa B<ABNF::Grammar>.
58              
59             $validator isa B<ABNF::Validator>.
60              
61             Children classes can get acces for them by $self->{_grammar} and $self->{_validator}
62              
63             =cut
64              
65 2 50 33 2   8231 method new(ABNF::Grammar $grammar, ABNF::Validator $validator?) {
  2 50 33 2   6  
  2 50 33     9  
  2 50       23  
  2         3  
  2         45  
  2         6  
  2         11  
66 2   33     12 my $class = ref($self) || $self;
67              
68 2 50       11 croak "Cant create instance of abstract class" if $class eq 'ABNF::Generator';
69              
70 2   33     16 $self = {
71             _cache => {},
72             _grammar => $grammar,
73             _validator => $validator || ABNF::Validator->new($grammar)
74             };
75              
76 2         7 bless($self, $class);
77              
78 2         16 $self->_init();
79              
80 2         8 return $self;
81             }
82              
83 2 50   2   1770 method _init() {
  2     2   6  
  2         9  
84 2         115 $self->{handlers} = {
85             Range => $self->can("_range"),
86             String => $self->can("_string"),
87             Literal => $self->can("_literal"),
88             Repetition => $self->can("_repetition"),
89             ProseValue => $self->can("_proseValue"),
90             Reference => $self->can("_reference"),
91             Group => $self->can("_group"),
92             Choice => $self->can("_choice"),
93             Rule => $self->can("_rule"),
94             };
95             }
96              
97             =pod
98              
99             =head1 $generator->C<_range>($rule, $recursion)
100              
101             Generates chain for range element.
102              
103             Abstract method, most of all children must overload it.
104              
105             $recursion is a structure to controle recursion depth.
106              
107             =cut
108              
109 2 0   2   11574 method _range($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
110 0         0 croak "Range handler is undefined yet";
111             }
112              
113             =pod
114              
115             =head1 $generator->C<_string>($rule, $recursion)
116              
117             Generates chain for string element.
118              
119             Abstract method, most of all children must overload it
120              
121             $recursion is a structure to controle recursion depth.
122              
123             =cut
124              
125 2 0   2   5402 method _string($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
126 0         0 croak "String handler is undefined yet";
127             }
128              
129             =pod
130              
131             =head1 $generator->C<_literal>($rule, $recursion)
132              
133             Generates chain for literal element.
134              
135             Abstract method, most of all children must overload it
136              
137             $recursion is a structure to controle recursion depth.
138              
139             =cut
140              
141 2 0   2   5431 method _literal($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
142 0         0 croak "Literal handler is undefined yet";
143             }
144              
145             =pod
146              
147             =head1 $generator->C<_repetition>($rule, $recursion)
148              
149             Generates chain for repetition element.
150              
151             Abstract method, most of all children must overload it
152              
153             $recursion is a structure to controle recursion depth.
154              
155             =cut
156              
157 2 0   2   5732 method _repetition($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
158 0         0 croak "Repetition handler is undefined yet";
159             }
160              
161             =pod
162              
163             =head1 $generator->C<_reference>($rule, $recursion)
164              
165             Generates chain for reference element.
166              
167             Abstract method, most of all children must overload it
168              
169             $recursion is a structure to controle recursion depth.
170              
171             =cut
172              
173 2 0   2   5505 method _reference($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
174 0         0 croak "Reference handler is undefined yet";
175             }
176              
177             =pod
178              
179             =head1 $generator->C<_group>($rule, $recursion)
180              
181             Generates chain for group element.
182              
183             Abstract method, most of all children must overload it
184              
185             $recursion is a structure to controle recursion depth.
186              
187             =cut
188              
189 2 0   2   5724 method _group($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
190 0         0 croak "Group handler is undefined yet";
191             }
192              
193             =pod
194              
195             =head1 $generator->C<_choice>($rule, $recursion)
196              
197             Generates chain for choce element.
198              
199             Abstract method, most of all children must overload it
200              
201             $recursion is a structure to controle recursion depth.
202              
203             =cut
204              
205 2 0   2   5254 method _choice($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
206 0         0 croak "Choice handler is undefined yet";
207             }
208              
209             =pod
210              
211             =head1 $generator->C<_rule>($rule, $recursion)
212              
213             Generates chain for rule element, usually -- basic element in chain.
214              
215             Abstract method, most of all children must overload it
216              
217             $recursion is a structure to controle recursion depth.
218              
219             =cut
220              
221 2 0   2   5250 method _rule($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
222 0         0 croak "Rule handler is undefined yet";
223             }
224              
225             =pod
226              
227             =head1 $generator->C<_generateChain>($rule, $recursion)
228              
229             Generates one chain per different rule in $rule.
230              
231             $rule is structure that Return from B<ABNF::Grammar::rule> and like in B<Parse::ABNF>.
232              
233             $rule might be a command name.
234              
235             $recursion is a structure to controle recursion depth.
236              
237             at init it have only one key -- level == 0.
238              
239             You can create new object perl call or use one.
240              
241             See use example in ABNF::Generator::Honest in method _choice
242              
243             =cut
244              
245 2 50   2   5458 method _generateChain($rule, $recursion) {
  939108 50   939108   1218227  
  939108 50       2055321  
  939108         1204428  
  939108         1888356  
  939108         1048482  
  939108         1837046  
246              
247 939108         1180891 my @result = ();
248              
249 939108 100       2180090 if ( ref($rule) ) {
    100          
250 649723 50       1865573 croak "Bad rule " . Dumper($rule) unless UNIVERSAL::isa($rule, "HASH");
251             } elsif ( exists($BASIC_RULES->{$rule}) ) {
252 130987         905156 $rule = $BASIC_RULES->{$rule};
253             } else {
254 158398         1300285 $rule = $self->{_grammar}->rule($rule);
255             }
256              
257 939108 50       3639201 $self->{handlers}->{ $rule->{class} }
258             or die "Unknown class " . $rule->{class};
259              
260 939108         3168665 return $self->{handlers}->{ $rule->{class} }->($self, $rule, $recursion);
261             }
262              
263             =pod
264              
265             =head1 $generator->C<generate>($rule, $tail="")
266              
267             Generates one sequence string for command $rule.
268              
269             Using cache $self->{_cache}->{$rule} for this rule, that speeds up this call.
270              
271             $rule is a command name.
272              
273             $tail is a string added to result if it absent.
274              
275             dies if there is no command like $rule.
276              
277             =cut
278              
279 2 50 33 2   11109 method generate(Str $rule, Str $tail="") {
  42 50 0 42   108665  
  42 50 33     107  
  42 50       332  
  42 50       60  
  42         106  
  42         76  
  42         82  
280 42 100       206 croak "Unexisted command" unless $self->{_grammar}->hasCommand($rule);
281              
282 40   100     120 $self->{_cache}->{$rule} ||= [];
283 40 100       40 unless ( @{$self->{_cache}->{$rule}} ) {
  40         100  
284 21         83 $self->{_cache}->{$rule} = _asStrings( $self->_generateChain($rule, {level => 0}) );
285             }
286 40         164666 my $result = pop($self->{_cache}->{$rule});
287            
288 40         56 my $rx = eval { qr/$tail$/ };
  40         222  
289 40 50       86 croak "Bad tail" if $@;
290 40 50       300 return $result =~ $rx ? $result : $result . $tail;
291             }
292              
293             =pod
294              
295             =head1 $generator->C<withoutArguments>($name, $tail="")
296              
297             Return an strings starts like command $name and without arguments.
298              
299             $tail is a string added to a result.
300              
301             dies if there is no command like $rule.
302              
303             =cut
304              
305 2 50 33 2   12417 method withoutArguments(Str $name, Str $tail="") {
  6 50 33 6   8  
  6 50 33     15  
  6 50       41  
  6 50       21  
  6         61  
  6         25  
  6         16  
306 6 100       24 croak "Unexisted command" unless $self->{_grammar}->hasCommand($name);
307              
308 4         23 my ($prefix, $args) = splitRule( $self->{_grammar}->rule($name) );
309            
310 4         9 my $rx = eval { qr/$tail$/ };
  4         56  
311 4 50       15 croak "Bad tail" if $@;
312 4 50       35 return $prefix =~ $rx ? $prefix : $prefix . $tail;
313             }
314              
315             =pod
316              
317             =head1 $generator->C<hasCommand>($name)
318              
319             Return 1 if there is a $name is command, 0 otherwise
320              
321             =cut
322              
323 2 50 33 2   5987 method hasCommand(Str $name) {
  3 50   3   6  
  3 50       9  
  3         27  
  3         5  
  3         8  
324 3         18 $self->{_grammar}->hasCommand($name);
325             }
326              
327             =pod
328              
329             =head1 FUNCTIONS
330              
331             =head1 C<_asStrings>($generated)
332              
333             Return stringification of genereted sequences from C<_generateChain>.
334              
335             Uses in generate call to stringify chains.
336              
337             =cut
338              
339 2 50   2   4305 func _asStrings($generated) {
  360379 50   360379   695090  
  360379         361965  
  360379         634726  
340 360379         535698 given ( $generated->{class} ) {
341 360379         446978 when ( "Atom" ) { return [ $generated->{value} ] }
  169235         497078  
342              
343 191144         208842 when ( "Sequence" ) {
344 109225         131169 my $value = $generated->{value};
345 109225 50       214293 return [] unless @$value;
346              
347 109225         177401 my $begin = _asStrings($value->[0]);
348              
349 109225         275875 for ( my $pos = 1; $pos < @$value; $pos++ ) {
350 130986         153301 my @new_begin = ();
351 130986         230174 my $ends = _asStrings($value->[$pos]);
352 130986 50       268108 next unless @$ends;
353              
354 130986         665725 my @ibegin = splice([shuffle(@$begin)], 0, $CHOICE_LIMIT);
355 130986         4570734 my @iends = splice([shuffle(@$ends)], 0, $CHOICE_LIMIT);
356 130986         1635141 foreach my $end ( @iends ) {
357 629846         739663 foreach my $begin ( @ibegin ) {
358 12810582         19980241 push(@new_begin, $begin . $end);
359             }
360             }
361            
362 130986         2256775 $begin = \@new_begin;
363             }
364              
365 109225         911451 return $begin;
366             }
367              
368 81919         93601 when ( "Choice" ) {
369             return [
370 81919         81608 map { @{_asStrings($_)} } @{$generated->{value}}
  120147         109011  
  120147         181099  
  81919         161114  
371             ];
372             }
373              
374 0           default { die "Unknown class " . $generated->{class} . Dumper $generated }
  0            
375             }
376             }
377              
378             1;
379              
380             =pod
381              
382             =head1 AUTHOR / COPYRIGHT / LICENSE
383              
384             Copyright (c) 2013 Arseny Krasikov <nyaapa@cpan.org>.
385              
386             This module is licensed under the same terms as Perl itself.
387              
388             =cut