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   41 use strict;
  6         11  
  6         711  
3              
4             sub new {
5 192780     192780 0 267712 my $pkg = shift;
6             ## flatten alike operations, i.e, "a+(b+c)" into "a+b+c"
7 192780 100       313849 my @flat = map {UNIVERSAL::isa($_, $pkg) ? $_->members : $_} @_;
  234842         947509  
8              
9 192780         3226710 bless \@flat, $pkg;
10             }
11              
12             sub members {
13 1211     1211 0 1709 my $self = shift;
14 1211 100       5759 wantarray ? @$self[0 .. $#$self] : $self->[0];
15             }
16              
17             #################################
18             #### regex operators / components
19              
20             package FLAT::Regex::Op::atomic;
21 6     6   40 use parent 'FLAT::Regex::Op';
  6         11  
  6         38  
22              
23             sub as_string {
24 58     58   97 my $t = $_[0]->members;
25              
26 58 100       107 return "#" if not defined $t;
27 57 100       178 return $t =~ /^\w$/
28             ? $t
29             : "[$t]";
30             }
31              
32             sub as_perl_regex {
33 112     112   156 my $r = $_[0]->members;
34              
35 112 50       200 return "(?!)" if not defined $r;
36              
37 112         152 $r = quotemeta $r;
38 112 100       346 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   1878 FLAT::PFA->singleton($_[0]->members);
47             }
48              
49             sub from_parse {
50 166868     166868   86823875 my ($pkg, @item) = @_;
51 166868         233151 my $i = $item[1];
52              
53 166868 100       319936 return $pkg->new("") if $i eq "[]";
54 166800 100       251160 return $pkg->new(undef) if $i eq "#";
55              
56 166368         340074 $i =~ s/^\[|\]$//g;
57              
58 166368         325359 return $pkg->new($i);
59             }
60              
61             sub reverse {
62 22     22   50 $_[0];
63             }
64              
65             sub is_empty {
66 18     18   36 not defined $_[0]->members;
67             }
68              
69             sub has_nonempty_string {
70 9     9   15 my $self = shift;
71 9 100       19 defined $self->members and length $self->members;
72             }
73              
74             sub is_finite {
75 7     7   23 1
76             }
77              
78             ##############################
79             package FLAT::Regex::Op::star;
80 6     6   2258 use parent 'FLAT::Regex::Op';
  6         40  
  6         23  
81              
82 12     12   56 sub parse_spec {"%s '*'"}
83 50     50   137 sub precedence {30}
84              
85             sub as_string {
86 5     5   11 my ($self, $prec) = @_;
87 5         20 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   26 my ($self, $prec) = @_;
93 14         23 my $result = $self->members->as_perl_regex($self->precedence) . "*";
94 14 50       28 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 64     64   129 my $self = shift;
104 64         175 $self->members->as_pfa->kleene;
105             }
106              
107             sub from_parse {
108 4232     4232   1154834 my ($pkg, @item) = @_;
109 4232         14398 $pkg->new($item[1]);
110             }
111              
112             sub reverse {
113 4     4   5 my $self = shift;
114 4         9 my $op = $self->members->reverse;
115 4         11 __PACKAGE__->new($op);
116             }
117              
118             sub is_empty {
119 3     3   13 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   17 !$_[0]->members->has_nonempty_string;
128             }
129              
130             ################################
131             package FLAT::Regex::Op::concat;
132 6     6   2045 use parent 'FLAT::Regex::Op';
  6         17  
  6         29  
133              
134 12     12   43 sub parse_spec {"%s(2..)";}
135 174     174   479 sub precedence {20}
136              
137             sub as_string {
138 10     10   20 my ($self, $prec) = @_;
139 10         23 my $result = join "", map {$_->as_string($self->precedence)} $self->members;
  40         68  
140 10 50       26 return $prec > $self->precedence ? "($result)" : $result;
141             }
142              
143             sub as_perl_regex {
144 28     28   48 my ($self, $prec) = @_;
145 28         56 my $result = join "", map {$_->as_perl_regex($self->precedence)} $self->members;
  84         140  
146 28 50       61 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 156     156   296 my $self = shift;
157 156         541 my @parts = map {$_->as_pfa} $self->members;
  470         1483  
158 156         1194 $parts[0]->concat(@parts[1 .. $#parts]);
159             }
160              
161             sub from_parse {
162 20077     20077   14735412 my ($pkg, @item) = @_;
163 20077         35412 $pkg->new(@{$item[1]});
  20077         61616  
164             }
165              
166             ## note: "reverse" conflicts with perl builtin
167             sub reverse {
168 6     6   9 my $self = shift;
169 6         11 my @ops = CORE::reverse map {$_->reverse} $self->members;
  18         31  
170 6         12 __PACKAGE__->new(@ops);
171             }
172              
173             sub is_empty {
174 5     5   10 my $self = shift;
175 5         14 my @members = $self->members;
176 5         14 for (@members) {
177 10 100       23 return 1 if $_->is_empty;
178             }
179 4         18 return 0;
180             }
181              
182             sub has_nonempty_string {
183 1     1   3 my $self = shift;
184 1 50       5 return 0 if $self->is_empty;
185              
186 1         3 my @members = $self->members;
187 1         3 for (@members) {
188 2 50       5 return 1 if $_->has_nonempty_string;
189             }
190 1         4 return 0;
191             }
192              
193             sub is_finite {
194 2     2   5 my $self = shift;
195 2 50       5 return 1 if $self->is_empty;
196              
197 2         17 my @members = $self->members;
198 2         5 for (@members) {
199 3 100       8 return 0 if not $_->is_finite;
200             }
201 1         6 return 1;
202             }
203              
204             #############################
205             package FLAT::Regex::Op::alt;
206 6     6   3617 use parent 'FLAT::Regex::Op';
  6         35  
  6         31  
207              
208 12     12   67 sub parse_spec {"%s(2.. /[+|]/)"}
209 143     143   343 sub precedence {10}
210              
211             sub as_string {
212 7     7   18 my ($self, $prec) = @_;
213 7         14 my $result = join "+", map {$_->as_string($self->precedence)} $self->members;
  26         49  
214 7 100       19 return $prec > $self->precedence ? "($result)" : $result;
215             }
216              
217             sub as_perl_regex {
218 28     28   48 my ($self, $prec) = @_;
219 28         51 my $result = join "|", map {$_->as_perl_regex($self->precedence)} $self->members;
  70         118  
220 28 50       93 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 35     35   57 my $self = shift;
231 35         128 my @parts = map {$_->as_pfa} $self->members;
  78         315  
232 35         273 $parts[0]->union(@parts[1 .. $#parts]);
233             }
234              
235             sub from_parse {
236 229     229   55193 my ($pkg, @item) = @_;
237 229         511 $pkg->new(@{$item[1]});
  229         882  
238             }
239              
240             sub reverse {
241 4     4   7 my $self = shift;
242 4         9 my @ops = map {$_->reverse} $self->members;
  12         23  
243 4         9 __PACKAGE__->new(@ops);
244             }
245              
246             sub is_empty {
247 2     2   5 my $self = shift;
248 2         18 my @members = $self->members;
249 2         7 for (@members) {
250 4 100       9 return 0 if not $_->is_empty;
251             }
252 1         5 return 1;
253             }
254              
255             sub has_nonempty_string {
256 1     1   4 my $self = shift;
257 1         4 my @members = $self->members;
258 1         4 for (@members) {
259 2 50       21 return 1 if $_->has_nonempty_string;
260             }
261 1         7 return 0;
262             }
263              
264             sub is_finite {
265 2     2   5 my $self = shift;
266 2         6 my @members = $self->members;
267 2         5 for (@members) {
268 4 100       9 return 0 if not $_->is_finite;
269             }
270 1         5 return 1;
271             }
272             1;