File Coverage

blib/lib/FLAT/Regex/Op.pm
Criterion Covered Total %
statement 131 143 91.6
branch 36 46 78.2
condition n/a
subroutine 44 49 89.8
pod 0 2 0.0
total 211 240 87.9


line stmt bran cond sub pod time code
1             package FLAT::Regex::Op;
2 6     6   102 use strict;
  6         15  
  6         781  
3              
4             sub new {
5 192843     192843 0 272310 my $pkg = shift;
6             ## flatten alike operations, i.e, "a+(b+c)" into "a+b+c"
7 192843 100       360597 my @flat = map {UNIVERSAL::isa($_, $pkg) ? $_->members : $_} @_;
  234781         1048476  
8              
9 192843         3532099 bless \@flat, $pkg;
10             }
11              
12             sub members {
13 1192     1192 0 1715 my $self = shift;
14 1192 100       6177 wantarray ? @$self[0 .. $#$self] : $self->[0];
15             }
16              
17             #################################
18             #### regex operators / components
19              
20             package FLAT::Regex::Op::atomic;
21 6     6   48 use parent 'FLAT::Regex::Op';
  6         12  
  6         44  
22              
23             sub as_string {
24 58     58   104 my $t = $_[0]->members;
25              
26 58 100       123 return "#" if not defined $t;
27 57 100       206 return $t =~ /^\w$/
28             ? $t
29             : "[$t]";
30             }
31              
32             sub as_perl_regex {
33 112     112   169 my $r = $_[0]->members;
34              
35 112 50       200 return "(?!)" if not defined $r;
36              
37 112         147 $r = quotemeta $r;
38 112 100       365 return $r =~ /^\w$/ ? $r : "(?:$r)";
39             }
40              
41             sub as_nfa {
42 0     0   0 FLAT::NFA->singleton($_[0]->members);
43             }
44              
45             sub as_pfa {
46 546     546   1827 FLAT::PFA->singleton($_[0]->members);
47             }
48              
49             sub from_parse {
50 166979     166979   95143976 my ($pkg, @item) = @_;
51 166979         269117 my $i = $item[1];
52              
53 166979 100       348197 return $pkg->new("") if $i eq "[]";
54 166911 100       287685 return $pkg->new(undef) if $i eq "#";
55              
56 166535         388057 $i =~ s/^\[|\]$//g;
57              
58 166535         361385 return $pkg->new($i);
59             }
60              
61             sub reverse {
62 22     22   35 $_[0];
63             }
64              
65             sub is_empty {
66 18     18   61 not defined $_[0]->members;
67             }
68              
69             sub has_nonempty_string {
70 9     9   21 my $self = shift;
71 9 100       26 defined $self->members and length $self->members;
72             }
73              
74             sub is_finite {
75 7     7   37 1
76             }
77              
78             ##############################
79             package FLAT::Regex::Op::star;
80 6     6   2661 use parent 'FLAT::Regex::Op';
  6         13  
  6         26  
81              
82 12     12   69 sub parse_spec {"%s '*'"}
83 50     50   144 sub precedence {30}
84              
85             sub as_string {
86 5     5   12 my ($self, $prec) = @_;
87 5         25 my $result = $self->members->as_string($self->precedence) . "*";
88 5 50       14 return $prec > $self->precedence ? "($result)" : $result;
89             }
90              
91             sub as_perl_regex {
92 14     14   25 my ($self, $prec) = @_;
93 14         27 my $result = $self->members->as_perl_regex($self->precedence) . "*";
94 14 50       30 return $prec > $self->precedence ? "(?:$result)" : $result;
95             }
96              
97             sub as_nfa {
98 0     0   0 my $self = shift;
99 0         0 $self->members->as_nfa->kleene;
100             }
101              
102             sub as_pfa {
103 55     55   116 my $self = shift;
104 55         176 $self->members->as_pfa->kleene;
105             }
106              
107             sub from_parse {
108 4213     4213   1286315 my ($pkg, @item) = @_;
109 4213         16174 $pkg->new($item[1]);
110             }
111              
112             sub reverse {
113 4     4   6 my $self = shift;
114 4         9 my $op = $self->members->reverse;
115 4         9 __PACKAGE__->new($op);
116             }
117              
118             sub is_empty {
119 3     3   20 0
120             }
121              
122             sub has_nonempty_string {
123 0     0   0 $_[0]->members->has_nonempty_string;
124             }
125              
126             sub is_finite {
127 7     7   36 !$_[0]->members->has_nonempty_string;
128             }
129              
130             ################################
131             package FLAT::Regex::Op::concat;
132 6     6   2253 use parent 'FLAT::Regex::Op';
  6         13  
  6         45  
133              
134 12     12   47 sub parse_spec {"%s(2..)";}
135 174     174   516 sub precedence {20}
136              
137             sub as_string {
138 10     10   23 my ($self, $prec) = @_;
139 10         28 my $result = join "", map {$_->as_string($self->precedence)} $self->members;
  40         74  
140 10 50       32 return $prec > $self->precedence ? "($result)" : $result;
141             }
142              
143             sub as_perl_regex {
144 28     28   49 my ($self, $prec) = @_;
145 28         56 my $result = join "", map {$_->as_perl_regex($self->precedence)} $self->members;
  84         137  
146 28 50       59 return $prec > $self->precedence ? "(?:$result)" : $result;
147             }
148              
149             sub as_nfa {
150 0     0   0 my $self = shift;
151 0         0 my @parts = map {$_->as_nfa} $self->members;
  0         0  
152 0         0 $parts[0]->concat(@parts[1 .. $#parts]);
153             }
154              
155             sub as_pfa {
156 155     155   408 my $self = shift;
157 155         582 my @parts = map {$_->as_pfa} $self->members;
  479         1536  
158 155         1228 $parts[0]->concat(@parts[1 .. $#parts]);
159             }
160              
161             sub from_parse {
162 20062     20062   16650957 my ($pkg, @item) = @_;
163 20062         42395 $pkg->new(@{$item[1]});
  20062         61785  
164             }
165              
166             ## note: "reverse" conflicts with perl builtin
167             sub reverse {
168 6     6   8 my $self = shift;
169 6         13 my @ops = CORE::reverse map {$_->reverse} $self->members;
  18         31  
170 6         14 __PACKAGE__->new(@ops);
171             }
172              
173             sub is_empty {
174 5     5   14 my $self = shift;
175 5         26 my @members = $self->members;
176 5         17 for (@members) {
177 10 100       34 return 1 if $_->is_empty;
178             }
179 4         20 return 0;
180             }
181              
182             sub has_nonempty_string {
183 1     1   2 my $self = shift;
184 1 50       5 return 0 if $self->is_empty;
185              
186 1         5 my @members = $self->members;
187 1         4 for (@members) {
188 2 50       6 return 1 if $_->has_nonempty_string;
189             }
190 1         3 return 0;
191             }
192              
193             sub is_finite {
194 2     2   5 my $self = shift;
195 2 50       8 return 1 if $self->is_empty;
196              
197 2         7 my @members = $self->members;
198 2         5 for (@members) {
199 3 100       9 return 0 if not $_->is_finite;
200             }
201 1         9 return 1;
202             }
203              
204             #############################
205             package FLAT::Regex::Op::alt;
206 6     6   3860 use parent 'FLAT::Regex::Op';
  6         22  
  6         54  
207              
208 12     12   80 sub parse_spec {"%s(2.. /[+|]/)"}
209 143     143   392 sub precedence {10}
210              
211             sub as_string {
212 7     7   19 my ($self, $prec) = @_;
213 7         22 my $result = join "+", map {$_->as_string($self->precedence)} $self->members;
  26         47  
214 7 100       18 return $prec > $self->precedence ? "($result)" : $result;
215             }
216              
217             sub as_perl_regex {
218 28     28   42 my ($self, $prec) = @_;
219 28         52 my $result = join "|", map {$_->as_perl_regex($self->precedence)} $self->members;
  70         117  
220 28 50       102 return $prec > $self->precedence ? "(?:$result)" : $result;
221             }
222              
223             sub as_nfa {
224 0     0   0 my $self = shift;
225 0         0 my @parts = map {$_->as_nfa} $self->members;
  0         0  
226 0         0 $parts[0]->union(@parts[1 .. $#parts]);
227             }
228              
229             sub as_pfa {
230 33     33   66 my $self = shift;
231 33         145 my @parts = map {$_->as_pfa} $self->members;
  73         296  
232 33         239 $parts[0]->union(@parts[1 .. $#parts]);
233             }
234              
235             sub from_parse {
236 227     227   58504 my ($pkg, @item) = @_;
237 227         472 $pkg->new(@{$item[1]});
  227         893  
238             }
239              
240             sub reverse {
241 4     4   6 my $self = shift;
242 4         9 my @ops = map {$_->reverse} $self->members;
  12         25  
243 4         10 __PACKAGE__->new(@ops);
244             }
245              
246             sub is_empty {
247 2     2   5 my $self = shift;
248 2         11 my @members = $self->members;
249 2         8 for (@members) {
250 4 100       15 return 0 if not $_->is_empty;
251             }
252 1         11 return 1;
253             }
254              
255             sub has_nonempty_string {
256 1     1   2 my $self = shift;
257 1         5 my @members = $self->members;
258 1         5 for (@members) {
259 2 50       13 return 1 if $_->has_nonempty_string;
260             }
261 1         49 return 0;
262             }
263              
264             sub is_finite {
265 2     2   5 my $self = shift;
266 2         11 my @members = $self->members;
267 2         7 for (@members) {
268 4 100       15 return 0 if not $_->is_finite;
269             }
270 1         9 return 1;
271             }
272             1;