File Coverage

blib/lib/Grammar/Formal.pm
Criterion Covered Total %
statement 158 190 83.1
branch 0 4 0.0
condition n/a
subroutine 53 65 81.5
pod 0 14 0.0
total 211 273 77.2


line stmt bran cond sub pod time code
1             #####################################################################
2             # Base package for operators
3             #####################################################################
4             package Grammar::Formal::Pattern;
5 2     2   119219 use Modern::Perl;
  2         18339  
  2         16  
6 2     2   1411 use Moose;
  2         855575  
  2         21  
7 2     2   14959 use MooseX::SetOnce;
  2         31113  
  2         443  
8              
9             has 'parent' => (
10             is => 'ro',
11             required => 0,
12             isa => 'Maybe[Grammar::Formal::Pattern]',
13             writer => '_set_parent',
14             traits => [qw/SetOnce/],
15             weak_ref => 1,
16             );
17              
18             has 'user_data' => (
19             is => 'rw',
20             required => 0,
21             );
22              
23             has 'position' => (
24             is => 'ro',
25             isa => 'Maybe[Int]',
26             required => 0,
27             );
28              
29             sub owner_grammar {
30 0     0 0 0 my ($self) = @_;
31              
32 0         0 for (my $p = $self->parent; $p; $p = $p->parent) {
33 0 0       0 next unless $p->isa('Grammar::Formal::Grammar');
34 0         0 return $p;
35             }
36              
37 0         0 die "Called owner_grammar on orphan pattern";
38             }
39              
40             #####################################################################
41             # Base package for unary operators
42             #####################################################################
43             package Grammar::Formal::Unary;
44 2     2   22 use Modern::Perl;
  2         5  
  2         20  
45 2     2   314 use Moose;
  2         4  
  2         14  
46              
47             extends 'Grammar::Formal::Pattern';
48              
49             has 'p' => (
50             is => 'ro',
51             required => 1,
52             isa => 'Grammar::Formal::Pattern'
53             );
54              
55             sub BUILD {
56 0     0 0 0 my $self = shift;
57 0         0 $self->p->_set_parent($self);
58             }
59              
60             #####################################################################
61             # Base package for binary operators
62             #####################################################################
63             package Grammar::Formal::Binary;
64 2     2   17361 use Modern::Perl;
  2         7  
  2         17  
65 2     2   348 use Moose;
  2         7  
  2         16  
66              
67             extends 'Grammar::Formal::Pattern';
68              
69             has 'p1' => (
70             is => 'ro',
71             required => 1,
72             isa => 'Grammar::Formal::Pattern'
73             );
74              
75             has 'p2' => (
76             is => 'ro',
77             required => 1,
78             isa => 'Grammar::Formal::Pattern'
79             );
80              
81             sub BUILD {
82 2     2 0 6916 my $self = shift;
83 2         103 $self->p1->_set_parent($self);
84 1         32 $self->p2->_set_parent($self);
85             }
86              
87             #####################################################################
88             # Group
89             #####################################################################
90             package Grammar::Formal::Group;
91 2     2   14506 use Modern::Perl;
  2         10  
  2         12  
92 2     2   230 use Moose;
  2         2  
  2         10  
93             extends 'Grammar::Formal::Binary';
94              
95             #####################################################################
96             # Choice
97             #####################################################################
98             package Grammar::Formal::Choice;
99 2     2   13417 use Modern::Perl;
  2         5  
  2         13  
100 2     2   278 use Moose;
  2         5  
  2         21  
101             extends 'Grammar::Formal::Binary';
102              
103             #####################################################################
104             # OrderedChoice
105             #####################################################################
106             package Grammar::Formal::OrderedChoice;
107 2     2   14070 use Modern::Perl;
  2         9  
  2         19  
108 2     2   263 use Moose;
  2         5  
  2         9  
109             extends 'Grammar::Formal::Binary';
110              
111             #####################################################################
112             # Conjunction
113             #####################################################################
114             package Grammar::Formal::Conjunction;
115 2     2   13335 use Modern::Perl;
  2         7  
  2         15  
116 2     2   222 use Moose;
  2         4  
  2         11  
117             extends 'Grammar::Formal::Binary';
118              
119             #####################################################################
120             # OrderedConjunction
121             #####################################################################
122             package Grammar::Formal::OrderedConjunction;
123 2     2   13484 use Modern::Perl;
  2         4  
  2         13  
124 2     2   233 use Moose;
  2         5  
  2         10  
125             extends 'Grammar::Formal::Binary';
126              
127             #####################################################################
128             # Subtraction
129             #####################################################################
130             package Grammar::Formal::Subtraction;
131 2     2   13198 use Modern::Perl;
  2         5  
  2         14  
132 2     2   243 use Moose;
  2         5  
  2         11  
133             extends 'Grammar::Formal::Binary';
134              
135             #####################################################################
136             # Empty
137             #####################################################################
138             package Grammar::Formal::Empty;
139 2     2   13485 use Modern::Perl;
  2         8  
  2         16  
140 2     2   230 use Moose;
  2         5  
  2         9  
141             extends 'Grammar::Formal::Pattern';
142              
143             #####################################################################
144             # NotAllowed
145             #####################################################################
146             package Grammar::Formal::NotAllowed;
147 2     2   13208 use Modern::Perl;
  2         5  
  2         31  
148 2     2   263 use Moose;
  2         4  
  2         9  
149             extends 'Grammar::Formal::Pattern';
150              
151             #####################################################################
152             # ZeroOrMore
153             #####################################################################
154             package Grammar::Formal::ZeroOrMore;
155 2     2   13184 use Modern::Perl;
  2         7  
  2         15  
156 2     2   211 use Moose;
  2         6  
  2         12  
157             extends 'Grammar::Formal::Unary';
158              
159             #####################################################################
160             # OneOrMore
161             #####################################################################
162             package Grammar::Formal::OneOrMore;
163 2     2   12763 use Modern::Perl;
  2         5  
  2         11  
164 2     2   215 use Moose;
  2         5  
  2         11  
165             extends 'Grammar::Formal::Unary';
166              
167             #####################################################################
168             # SomeOrMore
169             #####################################################################
170             package Grammar::Formal::SomeOrMore;
171 2     2   13393 use Modern::Perl;
  2         5  
  2         33  
172 2     2   202 use Moose;
  2         6  
  2         27  
173             extends 'Grammar::Formal::Unary';
174              
175             has 'min' => (
176             is => 'ro',
177             required => 1,
178             isa => 'Int'
179             );
180              
181             #####################################################################
182             # BoundedRepetition
183             #####################################################################
184             package Grammar::Formal::BoundedRepetition;
185 2     2   12319 use Modern::Perl;
  2         6  
  2         28  
186 2     2   194 use Moose;
  2         13  
  2         15  
187             extends 'Grammar::Formal::Unary';
188              
189             has 'min' => (
190             is => 'ro',
191             required => 1,
192             isa => 'Int'
193             );
194              
195             has 'max' => (
196             is => 'ro',
197             required => 1,
198             isa => 'Int'
199             );
200              
201             #####################################################################
202             # Reference
203             #####################################################################
204             package Grammar::Formal::Reference;
205 2     2   13463 use Modern::Perl;
  2         5  
  2         12  
206 2     2   244 use Moose;
  2         5  
  2         10  
207             extends 'Grammar::Formal::Pattern';
208              
209             has 'name' => (
210             is => 'ro',
211             required => 1,
212             isa => 'Str'
213             );
214              
215             sub expand {
216 0     0 0 0 my ($self) = @_;
217              
218 0         0 my $p = $self->owner_grammar;
219              
220             return $p->rules->{$self->name}
221 0 0       0 if $p->rules->{$self->name};
222              
223 0         0 warn "rule expansion for " . $self->name . " failed.";
224              
225 0         0 return;
226             }
227              
228             #####################################################################
229             # Rule
230             #####################################################################
231             package Grammar::Formal::Rule;
232 2     2   13917 use Modern::Perl;
  2         5  
  2         9  
233 2     2   171 use Moose;
  2         4  
  2         8  
234             extends 'Grammar::Formal::Unary';
235              
236             has 'name' => (
237             is => 'ro',
238             required => 1,
239             isa => 'Str'
240             );
241              
242             #####################################################################
243             # Grammar
244             #####################################################################
245             package Grammar::Formal::Grammar;
246 2     2   12741 use Modern::Perl;
  2         4  
  2         10  
247 2     2   173 use Moose;
  2         6  
  2         11  
248             extends 'Grammar::Formal::Pattern';
249              
250             has 'start' => (
251             is => 'ro',
252             required => 0,
253             isa => 'Maybe[Str]',
254             );
255              
256             has 'rules' => (
257             is => 'ro',
258             required => 1,
259             isa => 'HashRef[Grammar::Formal::Rule]',
260             default => sub { {} },
261             );
262              
263             # TODO: lock the rules hashref against external access?
264              
265             sub set_rule {
266 1     1 0 1403 my ($self, $name, $value) = @_;
267 1         69 $self->rules->{$name} = $value;
268 1         78 $value->_set_parent($self);
269             }
270              
271             # TODO: validate that rules include start symbol?
272              
273             #####################################################################
274             # Factory methods
275             #####################################################################
276              
277             # FIXME(bh): better alternative for this?
278              
279             sub NotAllowed {
280 0     0 0   my ($self, @o) = @_;
281 0           Grammar::Formal::NotAllowed->new(@o);
282             }
283              
284             sub Empty {
285 0     0 0   my ($self, @o) = @_;
286 0           Grammar::Formal::Empty->new(@o);
287             }
288              
289             sub Choice {
290 0     0 0   my ($self, $p1, $p2, @o) = @_;
291 0           Grammar::Formal::Choice->new(p1 => $p1, p2 => $p2, @o);
292             }
293              
294             sub Group {
295 0     0 0   my ($self, $p1, $p2, @o) = @_;
296 0           Grammar::Formal::Group->new(p1 => $p1, p2 => $p2, @o);
297             }
298              
299             sub Optional {
300 0     0 0   my ($self, $p, @o) = @_;
301 0           $self->Choice($self->Empty, $p, @o);
302             }
303              
304             sub OneOrMore {
305 0     0 0   my ($self, $p, @o) = @_;
306 0           Grammar::Formal::OneOrMore->new(p => $p, @o);
307             }
308              
309             sub ZeroOrMore {
310 0     0 0   my ($self, $p, @o) = @_;
311 0           Grammar::Formal::ZeroOrMore->new(p => $p, @o);
312             }
313              
314             #####################################################################
315             # CaseSensitiveString
316             #####################################################################
317             package Grammar::Formal::CaseSensitiveString;
318 2     2   12941 use Modern::Perl;
  2         5  
  2         10  
319 2     2   197 use Moose;
  2         5  
  2         8  
320             extends 'Grammar::Formal::Pattern';
321              
322             has 'value' => (
323             is => 'ro',
324             required => 1,
325             isa => 'Str'
326             );
327              
328             #####################################################################
329             # ASCII-Insensitive string
330             #####################################################################
331             package Grammar::Formal::AsciiInsensitiveString;
332 2     2   15845 use Modern::Perl;
  2         8  
  2         16  
333 2     2   395 use Moose;
  2         5  
  2         14  
334             extends 'Grammar::Formal::Pattern';
335              
336             has 'value' => (
337             is => 'ro',
338             required => 1,
339             isa => 'Str'
340             );
341              
342             #####################################################################
343             # prose values
344             #####################################################################
345             package Grammar::Formal::ProseValue;
346 2     2   17560 use Modern::Perl;
  2         7  
  2         15  
347 2     2   290 use Moose;
  2         5  
  2         13  
348             extends 'Grammar::Formal::Pattern';
349              
350             has 'value' => (
351             is => 'ro',
352             required => 1,
353             isa => 'Str'
354             );
355              
356             #####################################################################
357             # Range
358             #####################################################################
359             package Grammar::Formal::Range;
360 2     2   16371 use Modern::Perl;
  2         6  
  2         11  
361 2     2   200 use Moose;
  2         4  
  2         10  
362             extends 'Grammar::Formal::Pattern';
363              
364             has 'min' => (
365             is => 'ro',
366             required => 1,
367             isa => 'Int'
368             );
369              
370             has 'max' => (
371             is => 'ro',
372             required => 1,
373             isa => 'Int'
374             );
375              
376             # TODO: add check min <= max
377              
378             #####################################################################
379             # Character class
380             #####################################################################
381             package Grammar::Formal::CharClass;
382 2     2   18018 use Modern::Perl;
  2         7  
  2         16  
383 2     2   1799 use Set::IntSpan;
  2         20460  
  2         234  
384 2     2   77 use Moose;
  2         9  
  2         31  
385             extends 'Grammar::Formal::Pattern';
386              
387             has 'spans' => (
388             is => 'ro',
389             required => 1,
390             isa => 'Set::IntSpan'
391             );
392              
393             sub from_numbers {
394 0     0 0   my ($class, @numbers) = @_;
395 0           my $spans = Set::IntSpan->new([@numbers]);
396 0           return $class->new(spans => $spans);
397             }
398              
399             sub from_numbers_pos {
400 0     0 0   my ($class, $pos, @numbers) = @_;
401 0           my $spans = Set::IntSpan->new([@numbers]);
402 0           return $class->new(spans => $spans, position => $pos);
403             }
404              
405             #####################################################################
406             # Grammar::Formal
407             #####################################################################
408             package Grammar::Formal;
409 2     2   17535 use 5.012000;
  2         6  
410 2     2   12 use Modern::Perl;
  2         3  
  2         20  
411 2     2   451 use Moose;
  2         5  
  2         10  
412              
413             extends 'Grammar::Formal::Grammar';
414              
415             our $VERSION = '0.20';
416              
417             1;
418              
419              
420             __END__
421              
422             =head1 NAME
423              
424             Grammar::Formal - Object model to represent formal BNF-like grammars
425              
426             =head1 SYNOPSIS
427              
428             use Grammar::Formal;
429              
430             my $g = Grammar::Formal->new;
431              
432             my $s1 = Grammar::Formal::CaseSensitiveString->new(value => "a");
433             my $s2 = Grammar::Formal::CaseSensitiveString->new(value => "b");
434             my $choice = Grammar::Formal::Choice->new(p1 => $s1, p2 => $s2);
435              
436             $g->set_rule("a-or-b" => $choice);
437              
438             =head1 DESCRIPTION
439              
440             This module provides packages that can be used to model formal grammars
441             with production rules for non-terminals and terminals with arbitrary
442             operators and operands. The idea is to have a common baseline format to
443             avoid transformations between object models. Currently it has enough
444             features to model IETF ABNF grammars without loss of information (minor
445             details like certain syntax choices notwithstanding). All packages use
446             L<Moose>.
447              
448             =head1 API
449              
450             Grammar::Formal::Pattern
451             # Base package for all operators and operands
452             has rw user_data # Simple extension point
453             has ro parent # parent node if any
454              
455             + Grammar::Formal::Binary
456             # Base package for operators with 2 children
457              
458             has ro p1 # first child
459             has ro p2 # second child
460              
461             + Grammar::Formal::Group # concatenation
462             + Grammar::Formal::Choice # alternatives
463             + Grammar::Formal::OrderedChoice # ... with preference
464              
465             + Grammar::Formal::Unary
466             # Base package for operators with 1 child
467              
468             has ro p # the child pattern
469              
470             + Grammar::Formal::ZeroOrMore # zero or more
471             + Grammar::Formal::OneOrMore # one or more
472             + Grammar::Formal::SomeOrMore # min-bounded
473              
474             has ro min # minimum number of occurences
475              
476             + Grammar::Formal::BoundedRepetition
477             # bound repetition
478              
479             has ro min # minimum number of occurences
480             has ro max # maximum number of occurences
481              
482             + Grammar::Formal::Rule
483             # grammar production rule
484              
485             has ro name # name of the non-terminal symbol
486              
487             + Grammar::Formal::Reference
488             # Named reference to a non-terminal symbol
489              
490             has ro ref # name of the referenced non-terminal
491             can expand # returns the associated ::Rule or undef
492              
493             + Grammar::Formal::Grammar
494             # A grammar pattern with named rules
495              
496             has ro rules # Hash mapping rule names to ::Rules
497             has ro start # optional start symbol
498             can set_rule($name, $value) # set rule $name to ::Rule $rule
499              
500             + Grammar::Formal::CaseSensitiveString
501             # Case-sensitive sequence of characters
502              
503             has ro value # Text string this represents
504              
505             + Grammar::Formal::AsciiInsensitiveString
506             # Sequence of characters that treats [A-Z] like [a-z]
507              
508             has ro value # Text string
509              
510             + Grammar::Formal::ProseValue
511             # Free form text description, as in IETF ABNF grammars
512              
513             has ro value # Prose
514              
515             + Grammar::Formal::Range
516             # Range between two integers (inclusive)
517              
518             has ro min # first integer in range
519             has ro max # last integer in range
520              
521             + Grammar::Formal::CharClass
522             # Set of integers
523              
524             has ro spans # a Set::IntSpan object
525             can from_numbers(@ints) # static constructor
526              
527             =head1 EXPORTS
528              
529             None.
530              
531             =head1 TODO
532              
533             Surely there is a better way to automatically generate better POD?
534              
535             =head1 AUTHOR / COPYRIGHT / LICENSE
536              
537             Copyright (c) 2014 Bjoern Hoehrmann <bjoern@hoehrmann.de>.
538             This module is licensed under the same terms as Perl itself.
539              
540             =cut