File Coverage

blib/lib/Grammar/Convert/ABNF/Pegex.pm
Criterion Covered Total %
statement 88 88 100.0
branch 8 16 50.0
condition 4 6 66.6
subroutine 14 14 100.0
pod n/a
total 114 124 91.9


line stmt bran cond sub pod time code
1             package Grammar::Convert::ABNF::Pegex;
2              
3             # ABSTRACT: convert an ABNF grammar to Pegex
4              
5 2     2   143184 use v5.20;
  2         24  
6              
7 2     2   12 use strict;
  2         3  
  2         75  
8 2     2   12 use warnings;
  2         5  
  2         71  
9              
10 2     2   1352 use Moo;
  2         21763  
  2         9  
11 2     2   3689 use Parse::ABNF;
  2         1014951  
  2         184  
12              
13 2     2   18 use feature qw(signatures);
  2         5  
  2         273  
14 2     2   12 no warnings qw(experimental::signatures);
  2         5  
  2         1512  
15              
16             our $VERSION = '0.02';
17              
18             has abnf => ( is => 'ro', required => 1 );
19             has pegex => ( is => 'ro', lazy => 1, default => sub ( $self ) {
20             $self->_abnf_to_pegex;
21             });
22             has parser => ( is => 'ro', lazy => 1, default => sub {
23             Parse::ABNF->new
24             });
25              
26 4     4   5 sub _abnf_to_pegex ($self) {
  4         7  
  4         7  
27 4         61 my $grammar = $self->parser->parse( $self->abnf );
28              
29 4         885620 my @rules;
30 4 50       11 for my $rule ( @{ $grammar || [] } ) {
  4         66  
31 9         29 push @rules, $self->_rule_to_pegex( $rule );
32             }
33              
34 4         13 my $pegex = join "\n\n", @rules;
35 4         63 return "$pegex\n";
36             }
37              
38 9     9   13 sub _rule_to_pegex ($self, $rule) {
  9         13  
  9         13  
  9         10  
39 9 50       39 return if !$rule->{class} eq 'Rule';
40              
41 9         22 my $name = $rule->{name};
42 9         17 my $body_type = $rule->{value}->{class};
43 9         50 my $sub = $self->can('_conv_' . lc $body_type );
44              
45 9 50       23 return if !$sub;
46              
47 9         27 my $rule_body = $self->$sub( $rule->{value} );
48 9         29 my $pegex_rule = sprintf "%s: %s", $name, $rule_body;
49              
50 9         20 return $pegex_rule;
51             }
52              
53 5     5   7 sub _conv_choice ($self, $choice ) {
  5         8  
  5         7  
  5         6  
54 5         8 my @elements;
55              
56 5 50       9 for my $element ( @{ $choice->{value} || [] } ) {
  5         15  
57 15         24 my $elem_type = $element->{class};
58 15         35 my $sub = $self->can('_conv_' . lc $elem_type );
59              
60 15 50       32 return if !$sub;
61              
62 15         25 push @elements, $self->$sub( $element );
63             }
64              
65 5         17 return join ' | ', @elements;
66             }
67              
68 12     12   27 sub _conv_group ( $self, $group ) {
  12         15  
  12         15  
  12         14  
69 12         18 my @elements;
70              
71 12 50       16 for my $element ( @{ $group->{value} || [] } ) {
  12         32  
72 32         47 my $elem_type = $element->{class};
73 32         75 my $sub = $self->can('_conv_' . lc $elem_type );
74              
75 32 50       54 return if !$sub;
76              
77 32         55 push @elements, $self->$sub( $element );
78             }
79              
80 12         51 return sprintf "(%s)", join ' ', @elements;
81             }
82              
83 6     6   7 sub _conv_repetition ( $self, $rep ) {
  6         8  
  6         8  
  6         8  
84 6         10 my $elem_type = $rep->{value}->{class};
85 6         15 my $sub = $self->can('_conv_' . lc $elem_type );
86              
87 6 50       15 return if !$sub;
88              
89 6         15 my $name = $self->$sub( $rep->{value} );
90              
91 6         19 my %rep_map = (
92             '0+' => '*',
93             '1+' => '+',
94             '01' => '?',
95             );
96              
97 6   50     26 my $rep_key = join '', ( $rep->{min} // 0, $rep->{max} // '+' );
      100        
98 6   50     11 my $repetition = $rep_map{$rep_key} // '';
99              
100 6         23 return sprintf "%s%s", $name, $repetition;
101             }
102              
103 30     30   51 sub _conv_reference ( $self, $element ) {
  30         36  
  30         34  
  30         34  
104 30         65 return $element->{name};
105             }
106              
107 9     9   10 sub _conv_literal ( $self, $element ) {
  9         12  
  9         10  
  9         9  
108 9         33 return sprintf "'%s'", $element->{value};
109             }
110              
111             1;
112              
113             __END__