File Coverage

blib/lib/Pugs/Emitter/Rule/Perl5/Regex.pm
Criterion Covered Total %
statement 17 125 13.6
branch 0 58 0.0
condition 0 7 0.0
subroutine 6 32 18.7
pod 0 26 0.0
total 23 248 9.2


line stmt bran cond sub pod time code
1             package Pugs::Emitter::Rule::Perl5::Regex;
2              
3             # p6-rule perl5 emitter for emitting perl5 regexes
4              
5             =for TODO
6              
7             plug into the :ratchet emitter
8              
9             @ (non-)interpolation (test)
10             aliased, named captures
11             nested captures
12             quantified captures
13             ranges
14              
15             die() on captures that would have wrong numbering
16            
17             BUGS:
18             - nested captures are not detected
19             - set operations on character classes are not detected
20            
21             =cut
22              
23 1     1   820 use strict;
  1         2  
  1         40  
24 1     1   6 use warnings;
  1         2  
  1         31  
25 1     1   6 use Data::Dumper;
  1         3  
  1         261  
26             $Data::Dumper::Indent = 1;
27              
28             our $capture_count;
29             our $capture_to_array;
30              
31             sub emit {
32 0     0 0   my ($grammar, $ast, $param) = @_;
33 0           my $sigspace = $param->{sigspace};
34 0           local $capture_count = -1;
35 0           local $capture_to_array = 0;
36             #print "rule: ", Dumper( $ast );
37 0 0         die "sigspace not supported in P5 mode (can't call subrule)"
38             if $sigspace;
39 0           my $p5regex = '(?m)' . emit_rule( $ast );
40             # print ":P5/$p5regex/ \n";
41 0           return $p5regex;
42             }
43              
44             sub emit_rule {
45 0     0 0   my $n = $_[0];
46 0 0         die "unknown node: ", Dumper( $n )
47             unless ref( $n ) eq 'HASH';
48             #print "NODE ", Dumper($n);
49 0           my ($k) = keys %$n;
50 0           my $v = $$n{$k};
51             # XXX - use real references
52 1     1   8 no strict 'refs';
  1         3  
  1         1254  
53             #print "NODE ", Dumper($k), ", ", Dumper($v);
54 0           my $code = &$k( $v, '' );
55 0           return $code;
56             }
57              
58             #rule nodes
59              
60             sub non_capturing_group {
61 0     0 0   return "(?:" . emit_rule( $_[0] ) . ")";
62             }
63             sub quant {
64 0     0 0   my $term = $_[0]->{'term'};
65 0   0       my $quantifier = $_[0]->{quant} || '';
66 0   0       my $greedy = $_[0]->{greedy} || ''; # + ?
67 0 0         $greedy = '' if $greedy eq '+';
68             #print "QUANT: ",Dumper($_[0]);
69             # TODO: fix grammar to not emit empty quantifier
70 0 0         die "ranges not implemented"
71             if ref( $quantifier );
72 0           my $rul;
73             {
74             #print "Term: ", Dumper($term), "\n";
75 0           my $cap = $capture_to_array;
  0            
76 0   0       local $capture_to_array = $cap || ( $quantifier ne '' );
77 0           $rul = emit_rule( $term );
78             }
79 0           my $quant = $quantifier . $greedy;
80 0 0         return "(?:$rul)$quant" if $quant;
81 0           return $rul;
82             }
83             sub alt {
84 0     0 0   my @s;
85 0           my $count = $capture_count;
86 0           my $max = -1;
87 0           for ( @{$_[0]} ) {
  0            
88 0           $capture_count = $count;
89 0           my $tmp = emit_rule( $_ );
90             # print ' ',$capture_count;
91 0 0         $max = $capture_count
92             if $capture_count > $max;
93 0           push @s, $tmp; # if $tmp;
94             }
95 0           $capture_count = $max;
96             # print " max = $capture_count\n";
97             return
98 0           "(?:" . join( "|", @s ) . ")";
99             }
100 0     0 0   sub alt1 { &alt }
101             sub concat {
102 0           return join( "",
103 0     0 0   map { emit_rule( $_ ) } @{$_[0]}
  0            
104             );
105             }
106             sub code {
107 0     0 0   die "code not implemented";
108             }
109             sub dot {
110 0     0 0   '(?:\n\r?|\r\n?|.)'
111             }
112              
113             sub variable {
114 0     0 0   die "variable interpolation not implemented";
115             }
116             sub special_char {
117 0     0 0   my $char = substr($_[0],1);
118 0 0         return '(?:\n\r?|\r\n?)'
119             if $char eq 'n';
120 0 0         return '(?!\n\r?|\r\n?).'
121             if $char eq 'N';
122 0           for ( qw( r t e f w d s ) ) {
123 0 0         return "\\$_" if $char eq $_;
124 0 0         return "[^\\$_]" if $char eq uc($_);
125             }
126 0           return '\\' . $char;
127             }
128             sub match_variable {
129 0     0 0   die "no match variables yet";
130             }
131             sub closure {
132 0     0 0   die "no closures";
133             }
134             sub capturing_group {
135 0     0 0   my $program = $_[0];
136 0 0         die "capture to array not implemented"
137             if $capture_to_array;
138 0           $capture_count++;
139             {
140 0           local $capture_count = -1;
  0            
141 0           local $capture_to_array = 0;
142 0 0         $program = emit_rule( $program )
143             if ref( $program );
144             }
145 0           return "(" . $program . ")"
146             }
147             sub capture_as_result {
148 0     0 0   die "return objects not implemented";
149             }
150             sub named_capture {
151 0     0 0   die "no named captures";
152             }
153             sub negate {
154 0     0 0   die "no negate";
155             }
156             sub before {
157 0     0 0   my $program = $_[0]{rule};
158 0 0         $program = emit_rule( $program )
159             if ref( $program );
160 0           return "(?=" . $program . ")";
161             }
162             sub not_before {
163 0     0 0   my $program = $_[0]{rule};
164 0 0         $program = emit_rule( $program )
165             if ref( $program );
166 0           return "(?!" . $program . ")";
167             }
168             sub after {
169 0     0 0   my $program = $_[0]{rule};
170 0 0         $program = emit_rule( $program )
171             if ref( $program );
172 0           return "(?<=" . $program . ")";
173             }
174             sub not_after {
175 0     0 0   my $program = $_[0]{rule};
176 0 0         $program = emit_rule( $program )
177             if ref( $program );
178 0           return "(?
179             }
180             sub colon {
181 0     0 0   my $str = $_[0];
182 0 0         return '\z'
183             if $str eq '$';
184 0 0         return '\A'
185             if $str eq '^';
186 0 0         return '$'
187             if $str eq '$$';
188 0 0         return '^'
189             if $str eq '^^';
190 0           die "'$str' not implemented";
191             }
192             sub modifier {
193 0     0 0   my $str = $_[0];
194 0           die "modifier '$str' not implemented";
195             }
196             sub constant {
197 0 0   0 0   return ""
198             unless length($_[0]);
199 0 0         return '\\/' if $_[0] eq '/';
200 0           return $_[0];
201             }
202              
203 1     1   10 use vars qw( %char_class );
  1         2  
  1         87  
204             BEGIN {
205 1     1   3 %char_class = map { $_ => 1 } qw(
  14         385  
206             alpha alnum ascii blank
207             cntrl digit graph lower
208             print punct space upper
209             word xdigit
210             );
211             }
212              
213             sub char_class {
214 0     0 0   my $cmd = Pugs::Emitter::Rule::Perl5::CharClass::emit( $_[0] );
215 0           return $cmd;
216             }
217              
218             sub metasyntax {
219             #
220 0     0 0   my $cmd = $_[0];
221 0           my $prefix = substr( $cmd, 0, 1 );
222 0 0         if ( $prefix eq q(') ) { # single quoted literal '
223 0           $cmd = substr( $cmd, 1, -1 );
224 0           $cmd =~ s/([\$\@\%\[\]\+\*\(\)\?\/])/\\$1/g;
225 0           return $cmd;
226             }
227 0 0         if ( $prefix eq '.' ) { # non_capturing_subrule / code assertion
228 0           $cmd = substr( $cmd, 1 );
229 0 0         if ( exists $char_class{$cmd} ) {
230             # XXX - inlined char classes are not inheritable, but this should be ok
231 0           return "[[:$cmd:]]";
232             }
233             }
234 0 0         if ( $prefix eq '?' ) { # non_capturing_subrule / code assertion
235             # XXX FIXME
236 0           $cmd = substr( $cmd, 1 );
237 0 0         if ( exists $char_class{$cmd} ) {
238             # XXX - inlined char classes are not inheritable, but this should be ok
239 0           return "[[:$cmd:]]";
240             }
241             }
242 0 0         if ( $prefix =~ /[_[:alnum:]]/ ) {
243 0 0         if ( $cmd eq 'null' ) {
244 0           return ""
245             }
246             }
247 0           die "<$cmd> not implemented";
248             }
249              
250             1;