File Coverage

blib/lib/Parse/RecDescent/Deparse.pm
Criterion Covered Total %
statement 44 99 44.4
branch 2 26 7.6
condition 0 21 0.0
subroutine 15 17 88.2
pod 0 3 0.0
total 61 166 36.7


line stmt bran cond sub pod time code
1             package Parse::RecDescent::Deparse;
2 1     1   16768 use Parse::RecDescent;
  1         55804  
  1         10  
3              
4 1     1   67 use 5.006;
  1         8  
  1         32  
5 1     1   6 use strict;
  1         7  
  1         30  
6 1     1   5 use warnings;
  1         2  
  1         819  
7              
8             $Parse::RecDescent::Deparse::VERSION = '1.00';
9              
10             # This is not a Parse::RecDescent optimizer.
11              
12             # Given a grammar
13             #
14             # a : b
15             # b : 'foo' c 'baz'
16             # c : 'bar'
17             #
18             # repeated calls to ->hoist will produce
19             #
20             # a : 'foo' c 'baz'
21             # b : 'foo' 'bar' 'baz'
22             # c : 'bar'
23             #
24             # and
25             #
26             # a : 'foo' 'bar' 'baz'
27             # b : 'foo' 'bar' 'baz'
28             # c : 'bar'
29              
30             sub Parse::RecDescent::hoist {
31 0     0 0 0 my $self = shift;
32 0         0 RULE: for (values %{$self->{rules}}) {
  0         0  
33 0         0 my @directly_calls =
34 0         0 map { $_->{subrule} }
35 0         0 grep { ref $_ eq "Parse::RecDescent::Subrule" }
36 0         0 map { @{$_->{items}} }
  0         0  
37 0         0 @{$_->{prods}};
38 0         0 for my $subrule (@directly_calls) {
39 0         0 $subrule = $self->{rules}->{$subrule};
40 0 0 0     0 next if @{$subrule->{prods}} > 1 or !@{$subrule->{prods}};
  0         0  
  0         0  
41             #print "Hoisting $subrule->{name} into $_->{name}\n";
42 0         0 for my $prod (@{$_->{prods}}) {
  0         0  
43 0         0 for my $i (0..$#{$prod->{items}}) {
  0         0  
44 0 0 0     0 if (ref $prod->{items}[$i] eq
45             "Parse::RecDescent::Subrule" and
46             $prod->{items}[$i]{subrule} eq $subrule->{name}) {
47 0         0 splice (@{$prod->{items}}, $i, 1, map {bless{ %$_ }, ref$_} @{$subrule->{prods}[0]->{items}}); # Ugly hack
  0         0  
  0         0  
  0         0  
48 0         0 return;
49             }
50             }
51             }
52             }
53             }
54             }
55              
56             # Given a grammar
57             #
58             # a : 'b' /c/ "d"
59             #
60             # ->merge_literals will produce
61             #
62             # a : 'bcd'
63              
64             sub Parse::RecDescent::merge_literals {
65 0     0 0 0 my $self = shift;
66 0         0 for (values %{$self->{rules}}) {
  0         0  
67 0         0 for (@{$_->{prods}}) {
  0         0  
68 0         0 for (@{$_->{items}}) {
  0         0  
69 0 0 0     0 if (ref $_ eq "Parse::RecDescent::Token" and
      0        
70             $_->{pattern} !~ /[\(\[\]\)\+\*\?\\\^]/ and
71             $_->{pattern} !~ /\$$/) {
72 0         0 bless $_, "Parse::RecDescent::InterpLit";
73             }
74 0 0 0     0 if (ref $_ eq "Parse::RecDescent::InterpLit" and
75             $_->{pattern} !~ /(^|[^\\])[\$\@]/) {
76 0         0 bless $_, "Parse::RecDescent::Literal";
77             }
78             }
79 0 0       0 next unless @{$_->{items}} > 1;
  0         0  
80 0         0 RETRY: for my $i (1..$#{$_->{items}}) {
  0         0  
81 0 0 0     0 if (ref $_->{items}[$i] eq "Parse::RecDescent::Literal"
      0        
82             and (ref $_->{items}[$i-1] eq "Parse::RecDescent::Literal"
83             or ref $_->{items}[$i-1] eq "Parse::RecDescent::InterpLit")
84             ) {
85 0 0       0 if (ref $_->{items}[$i-1] eq "Parse::RecDescent::InterpLit") {
86 0         0 $_->{items}[$i-1]{pattern} =~ s/([\@\$])::(\w+)$/$1::{$2}/;
87             }
88 0         0 $_->{items}[$i-1]->{pattern} .= (splice @{$_->{items}}, $i, 1)->{pattern};
  0         0  
89             # XXX Swizzle item numbers here.
90 0         0 goto RETRY;
91             }
92             }
93             }
94             }
95             }
96              
97             sub Parse::RecDescent::deparse {
98 2     2 0 171008 my $self = shift;
99 40         96 return join "", map {" $_ : ".$self->{rules}->{$_}->deparse."\n"}
  130         251  
100             sort {
101 2         32 $self->{rules}->{$a}->{line}
102             <=>
103             $self->{rules}->{$b}->{line}
104             }
105 2         8 keys %{$self->{rules}};
106             }
107              
108             sub Parse::RecDescent::Rule::deparse {
109 40     40   40 my $self = shift;
110 40         39 return join " | ", map { $_->deparse } @{$self->{prods}};
  96         167  
  40         76  
111             }
112              
113             sub Parse::RecDescent::Production::deparse {
114 96     96   91 my $self = shift;
115 96         77 return join " ", map {$_->deparse} @{$self->{items}};
  142         237  
  96         170  
116             }
117              
118             sub Parse::RecDescent::InterpLit::deparse {
119 4     4   10 my $dq = (shift)->{pattern};
120 4 50       24 return qq{"$dq"} if $dq !~ /"/;
121 0 0       0 return "qq{$dq}" if $dq !~ /[\{\}]/;
122 1     1   5 no warnings; # Sheesh
  1         2  
  1         212  
123 0 0       0 for (qw(/ # !)) { return "qq$_$dq$_" if $dq !~ /$_/; }
  0         0  
124             # Sodding hell.
125 0         0 $dq =~ s/"/\\"/g;
126 0         0 return qq{"$dq"};
127             }
128              
129             sub Parse::RecDescent::Subrule::deparse {
130 38     38   34 my $self = shift;
131 38         127 return $self->{subrule};
132             }
133              
134             sub Parse::RecDescent::Literal::deparse {
135 50     50   48 my $self = shift;
136 50         84 my $q = $self->{pattern};
137 50 50       214 return qq{'$q'} if $q !~ /'/;
138 0 0       0 return "q{$q}" if $q !~ /[\{\}]/;
139 1     1   5 no warnings;
  1         2  
  1         218  
140 0 0       0 for (qw(/ # !)) { return "q$_$q$_" if $q !~ /$_/; }
  0         0  
141             # Sodding hell.
142 0         0 $q =~ s/'/\\'/g;
143 0         0 return qq{'$q'};
144             }
145              
146             sub Parse::RecDescent::Token::deparse {
147 18     18   17 my $self = shift;
148 18         107 return "m".$self->{ldelim}.$self->{pattern}.$self->{rdelim};
149             }
150              
151             sub Parse::RecDescent::Action::deparse {
152 14     14   10 my $self = shift;
153 14         84 return $self->{code};
154             }
155              
156             sub Parse::RecDescent::Repetition::deparse {
157 18     18   15 my $self = shift;
158 18         90 return $self->{subrule}."($self->{repspec})";
159             }
160              
161             =head1 NAME
162              
163             Parse::RecDescent::Deparse - Turn a Parse::RecDescent object back into its grammar
164              
165             =head1 SYNOPSIS
166              
167             use Parse::RecDescent::Deparse;
168              
169             my $foo = new Parse::RecDescent($grammar);
170             print $foo->deparse;
171              
172             =head1 DESCRIPTION
173              
174             This module adds the C method to the C
175             class, which returns a textual description of the grammar.
176              
177             Why? There are at least two equally unlikely reasons why this could be
178             useful:
179              
180             =over 3
181              
182             =item *
183              
184             You're working on something which grovels around in the
185             C object data structure and want to view the effects
186             of your changes. For instance, a C optimizer. (This
187             package does not contain a functional C optimizer.)
188              
189             =item *
190              
191             You want to understand how C does what it does, and
192             fancy the source of this package is a bit more of a gentle introduction
193             than the source of C itself.
194              
195             =back
196              
197             =head2 BUGS
198              
199             C can correctly deparse the metagrammar for
200             C input, so that's a good thing. There are no bugs in
201             the C optimizer as it clearly does not exist.
202              
203              
204             =head1 AUTHOR
205              
206             Simon Cozens, C
207              
208             =head1 SEE ALSO
209              
210             L.
211              
212             =cut