line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Algorithm::ConstructDFA::XS;
|
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
158247
|
use 5.012000;
|
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
148
|
|
4
|
4
|
|
|
4
|
|
24
|
use strict;
|
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
136
|
|
5
|
4
|
|
|
4
|
|
25
|
use warnings;
|
|
4
|
|
|
|
|
21
|
|
|
4
|
|
|
|
|
117
|
|
6
|
4
|
|
|
4
|
|
2388
|
use Data::AutoBimap;
|
|
4
|
|
|
|
|
1445
|
|
|
4
|
|
|
|
|
170
|
|
7
|
4
|
|
|
4
|
|
8751
|
use Storable;
|
|
4
|
|
|
|
|
11741
|
|
|
4
|
|
|
|
|
5764
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
require Exporter;
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our @ISA = qw(Exporter);
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw(
|
14
|
|
|
|
|
|
|
construct_dfa_xs
|
15
|
|
|
|
|
|
|
) ] );
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our @EXPORT = qw(
|
20
|
|
|
|
|
|
|
construct_dfa_xs
|
21
|
|
|
|
|
|
|
);
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our $VERSION = '0.23';
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
require XSLoader;
|
26
|
|
|
|
|
|
|
XSLoader::load('Algorithm::ConstructDFA::XS', $VERSION);
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub construct_dfa_xs {
|
29
|
90
|
|
|
90
|
1
|
12151272
|
my (%o) = @_;
|
30
|
|
|
|
|
|
|
|
31
|
90
|
50
|
|
|
|
668
|
die unless ref $o{is_nullable};
|
32
|
90
|
50
|
33
|
|
|
486
|
die unless ref $o{is_accepting} or exists $o{final};
|
33
|
90
|
50
|
66
|
|
|
542
|
die unless ref $o{successors} or ref $o{edges_from};
|
34
|
90
|
50
|
66
|
|
|
454
|
die unless ref $o{get_label} or ref $o{edges_from};
|
35
|
90
|
50
|
33
|
|
|
326
|
die unless exists $o{start} or exists $o{many_start};
|
36
|
90
|
50
|
33
|
|
|
637
|
die if ref $o{is_accepting} and exists $o{final};
|
37
|
90
|
50
|
66
|
|
|
500
|
die if ref $o{successors} and exists $o{edges_from};
|
38
|
90
|
50
|
66
|
|
|
421
|
die if ref $o{get_label} and ref $o{edges_from};
|
39
|
|
|
|
|
|
|
|
40
|
90
|
|
|
|
|
168
|
my $class = 'Algorithm::ConstructDFA::XS::Synth';
|
41
|
|
|
|
|
|
|
|
42
|
90
|
100
|
|
|
|
248
|
if (exists $o{edges_from}) {
|
43
|
|
|
|
|
|
|
|
44
|
30
|
|
|
|
|
71
|
my $old_accepting = $o{is_accepting};
|
45
|
|
|
|
|
|
|
$o{is_accepting} = sub {
|
46
|
234
|
|
|
234
|
|
1221
|
my @config = grep { ref $_ ne $class } @_;
|
|
5252
|
|
|
|
|
34548
|
|
47
|
234
|
|
|
|
|
641
|
return $old_accepting->(@config);
|
48
|
30
|
|
|
|
|
167
|
};
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
$o{get_label} = sub {
|
51
|
615
|
|
|
615
|
|
1364
|
my ($src) = @_;
|
52
|
615
|
100
|
|
|
|
1583
|
return unless ref $src eq $class;
|
53
|
398
|
|
|
|
|
858
|
return (Storable::thaw($$src))->[1];
|
54
|
30
|
|
|
|
|
141
|
};
|
55
|
|
|
|
|
|
|
|
56
|
30
|
|
|
|
|
57
|
my $old_nullable = $o{is_nullable};
|
57
|
|
|
|
|
|
|
$o{is_nullable} = sub {
|
58
|
615
|
|
|
615
|
|
1019
|
my ($src) = @_;
|
59
|
|
|
|
|
|
|
|
60
|
615
|
100
|
|
|
|
1922
|
if (ref $src eq $class) {
|
61
|
398
|
|
|
|
|
478
|
my $deref = $$src;
|
62
|
398
|
|
|
|
|
932
|
my $thawed = Storable::thaw $deref;
|
63
|
398
|
|
|
|
|
7750
|
return not defined $thawed->[1];
|
64
|
|
|
|
|
|
|
}
|
65
|
|
|
|
|
|
|
|
66
|
217
|
|
|
|
|
891
|
$old_nullable->($src);
|
67
|
30
|
|
|
|
|
145
|
};
|
68
|
|
|
|
|
|
|
|
69
|
30
|
|
|
|
|
61
|
my $old_edges_from = $o{edges_from};
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$o{successors} = sub {
|
72
|
615
|
|
|
615
|
|
1850
|
my ($src) = @_;
|
73
|
|
|
|
|
|
|
|
74
|
615
|
100
|
|
|
|
1586
|
if (ref $src eq $class) {
|
75
|
398
|
|
|
|
|
933
|
return (Storable::thaw $$src)->[2];
|
76
|
|
|
|
|
|
|
}
|
77
|
|
|
|
|
|
|
|
78
|
217
|
|
|
|
|
307
|
my @successors;
|
79
|
|
|
|
|
|
|
|
80
|
217
|
|
|
|
|
512
|
for my $edge ($old_edges_from->($src)) {
|
81
|
398
|
|
|
|
|
10255
|
my ($dst, $label) = @$edge;
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# TODO: theoretically there could be name clashes between the
|
84
|
|
|
|
|
|
|
# artificial vertex created here and vertices in the original
|
85
|
|
|
|
|
|
|
# unwrapped input which can interfere with the bimaps mapping
|
86
|
|
|
|
|
|
|
# stringified vertices to numbers.
|
87
|
398
|
|
|
|
|
1329
|
push @successors, bless \(Storable::freeze([$src, $label, $dst])),
|
88
|
|
|
|
|
|
|
$class;
|
89
|
|
|
|
|
|
|
}
|
90
|
|
|
|
|
|
|
|
91
|
217
|
|
|
|
|
8916
|
return @successors;
|
92
|
30
|
|
|
|
|
271
|
};
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
}
|
95
|
|
|
|
|
|
|
|
96
|
90
|
50
|
|
|
|
270
|
if (exists $o{final}) {
|
97
|
0
|
|
|
|
|
0
|
my %in_final = map { $_ => 1 } @{ $o{final} };
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
98
|
|
|
|
|
|
|
$o{is_accepting} = sub {
|
99
|
0
|
|
|
0
|
|
0
|
grep { $in_final{$_} } @_
|
|
0
|
|
|
|
|
0
|
|
100
|
0
|
|
|
|
|
0
|
};
|
101
|
|
|
|
|
|
|
}
|
102
|
|
|
|
|
|
|
|
103
|
90
|
|
50
|
|
|
514
|
$o{many_start} //= [$o{start}];
|
104
|
|
|
|
|
|
|
|
105
|
90
|
|
|
|
|
427
|
my $dfa = _construct_dfa_xs($o{many_start}, $o{get_label},
|
106
|
|
|
|
|
|
|
$o{is_nullable}, $o{successors}, $o{is_accepting});
|
107
|
|
|
|
|
|
|
|
108
|
90
|
100
|
|
|
|
489
|
if (exists $o{edges_from}) {
|
109
|
30
|
|
|
|
|
85
|
for (values %$dfa) {
|
110
|
5252
|
|
|
|
|
11801
|
$_->{Combines} = [ grep {
|
111
|
234
|
|
|
|
|
478
|
ref $_ ne $class;
|
112
|
234
|
|
|
|
|
276
|
} @{ $_->{Combines} } ];
|
113
|
|
|
|
|
|
|
}
|
114
|
|
|
|
|
|
|
}
|
115
|
|
|
|
|
|
|
|
116
|
90
|
|
|
|
|
1071
|
return $dfa;
|
117
|
|
|
|
|
|
|
}
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub _construct_dfa_xs {
|
120
|
90
|
|
|
90
|
|
176
|
my ($roots, $labelf, $nullablef, $successorsf, $acceptingf) = @_;
|
121
|
|
|
|
|
|
|
|
122
|
90
|
|
|
|
|
194
|
my @todo = map { @$_ } @$roots;
|
|
90
|
|
|
|
|
342
|
|
123
|
90
|
|
|
|
|
150
|
my %seen;
|
124
|
|
|
|
|
|
|
my @args;
|
125
|
90
|
|
|
|
|
543
|
my $sm = Data::AutoBimap->new;
|
126
|
90
|
|
|
|
|
1873
|
my $rm = Data::AutoBimap->new;
|
127
|
90
|
|
|
|
|
866
|
my %is_start;
|
128
|
|
|
|
|
|
|
|
129
|
90
|
|
|
|
|
305
|
for (my $ix = 0; $ix < @$roots; ++$ix) {
|
130
|
90
|
|
|
|
|
135
|
for my $v (@{ $roots->[$ix] }) {
|
|
90
|
|
|
|
|
250
|
|
131
|
113
|
|
|
|
|
159
|
push @{ $is_start{$v} }, $ix + 1;
|
|
113
|
|
|
|
|
650
|
|
132
|
|
|
|
|
|
|
}
|
133
|
|
|
|
|
|
|
}
|
134
|
|
|
|
|
|
|
|
135
|
90
|
|
|
|
|
232
|
while (@todo) {
|
136
|
2677
|
|
|
|
|
4257
|
my $c = pop @todo;
|
137
|
|
|
|
|
|
|
|
138
|
2677
|
100
|
|
|
|
8490
|
next if $seen{$c}++;
|
139
|
|
|
|
|
|
|
|
140
|
1456
|
|
|
|
|
3072
|
my $is_nullable = !!$nullablef->($c);
|
141
|
1456
|
|
|
|
|
81246
|
my $label = $labelf->($c);
|
142
|
1456
|
100
|
|
|
|
78655
|
my $label_x = defined $label ? $rm->s2n($label) : undef;
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# [vertex, label, nullable, start, successors...]
|
145
|
1456
|
|
100
|
|
|
10080
|
my @data = ($sm->s2n($c), $label_x, !!$is_nullable, $is_start{$c} // []);
|
146
|
|
|
|
|
|
|
|
147
|
1456
|
|
|
|
|
31707
|
for ($successorsf->($c)) {
|
148
|
2564
|
|
|
|
|
63805
|
push @data, $sm->s2n($_);
|
149
|
2564
|
|
|
|
|
29437
|
push @todo, $_;
|
150
|
|
|
|
|
|
|
}
|
151
|
|
|
|
|
|
|
|
152
|
1456
|
|
|
|
|
15454
|
push @args, \@data;
|
153
|
|
|
|
|
|
|
}
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
my %h = _internal_construct_dfa_xs(sub {
|
156
|
1115
|
|
|
1115
|
|
221989
|
!!$acceptingf->(map { $sm->n2s($_) } @_)
|
|
12511
|
|
|
|
|
83072
|
|
157
|
90
|
|
|
|
|
29186
|
}, \@args);
|
158
|
|
|
|
|
|
|
|
159
|
90
|
|
|
|
|
54509
|
for (values %h) {
|
160
|
1038
|
|
|
|
|
17501
|
$_->{Combines} = [ map { $sm->n2s($_) } @{ $_->{Combines} } ];
|
|
12402
|
|
|
|
|
74583
|
|
|
1038
|
|
|
|
|
2203
|
|
161
|
|
|
|
|
|
|
}
|
162
|
|
|
|
|
|
|
|
163
|
90
|
|
|
|
|
913
|
for my $v (values %h) {
|
164
|
1038
|
|
|
|
|
1584
|
my $over = {};
|
165
|
1038
|
|
|
|
|
1366
|
$over->{ $rm->n2s($_) } = $v->{NextOver}{$_} for keys %{ $v->{NextOver} };
|
|
1038
|
|
|
|
|
5202
|
|
166
|
1038
|
|
|
|
|
21482
|
$v->{NextOver} = $over;
|
167
|
|
|
|
|
|
|
}
|
168
|
|
|
|
|
|
|
|
169
|
90
|
|
|
|
|
2545
|
return \%h;
|
170
|
|
|
|
|
|
|
}
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
1;
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
__END__
|