| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Filter::Syntactic; |
|
2
|
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
784865
|
use 5.022; |
|
|
5
|
|
|
|
|
22
|
|
|
4
|
5
|
|
|
5
|
|
46
|
use warnings; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
554
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.000002'; |
|
7
|
|
|
|
|
|
|
|
|
8
|
5
|
|
|
5
|
|
3120
|
use Filter::Simple; |
|
|
5
|
|
|
|
|
104305
|
|
|
|
5
|
|
|
|
|
33
|
|
|
9
|
5
|
|
|
5
|
|
5653
|
use PPR::X; |
|
|
5
|
|
|
|
|
424321
|
|
|
|
5
|
|
|
|
|
340
|
|
|
10
|
5
|
|
|
5
|
|
3190
|
use experimental 'signatures'; |
|
|
5
|
|
|
|
|
18812
|
|
|
|
5
|
|
|
|
|
32
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
15
|
|
|
15
|
|
30
|
sub _expected ($what = q{}) { |
|
|
15
|
|
|
|
|
78
|
|
|
|
15
|
|
|
|
|
30
|
|
|
13
|
15
|
|
|
|
|
20
|
state ($expected, $unexpected); |
|
14
|
15
|
100
|
|
|
|
41
|
if ($what) { |
|
15
|
12
|
|
|
|
|
27
|
$expected = $what; |
|
16
|
12
|
50
|
|
|
|
19
|
$unexpected = do { substr($_,pos()) =~ m{ \A \s* (\S \N*) } ? $1 : substr($_,pos(),20) }; |
|
|
12
|
|
|
|
|
1336
|
|
|
17
|
|
|
|
|
|
|
} |
|
18
|
|
|
|
|
|
|
else { |
|
19
|
3
|
|
|
|
|
11
|
my $expectation = qq{Expected $expected but found "$unexpected"}; |
|
20
|
3
|
|
|
|
|
10
|
$expected = $unexpected = q{}; |
|
21
|
3
|
|
|
|
|
9
|
return $expectation; |
|
22
|
|
|
|
|
|
|
} |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Extract context information... |
|
26
|
13
|
|
|
13
|
|
28
|
sub _line_comment ($str, $pos, $line_offset) { |
|
|
13
|
|
|
|
|
26
|
|
|
|
13
|
|
|
|
|
25
|
|
|
|
13
|
|
|
|
|
20
|
|
|
|
13
|
|
|
|
|
24
|
|
|
27
|
13
|
|
100
|
|
|
50
|
$pos //= 0; |
|
28
|
13
|
|
|
|
|
53
|
return "\n#" . _line_loc($str, $pos, $line_offset) . "\n"; |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
|
|
31
|
23
|
|
|
23
|
|
249000
|
sub _line_loc ($str, $pos, $line_offset) { |
|
|
23
|
|
|
|
|
48
|
|
|
|
23
|
|
|
|
|
39
|
|
|
|
23
|
|
|
|
|
35
|
|
|
|
23
|
|
|
|
|
33
|
|
|
32
|
23
|
|
50
|
|
|
57
|
$pos //= 0; |
|
33
|
23
|
|
|
|
|
198
|
my $line_num = $line_offset + (substr($str,0,$pos) =~ tr/\n//); |
|
34
|
23
|
|
|
|
|
268
|
return "line $line_num"; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub import { |
|
38
|
|
|
|
|
|
|
# Generated filters use subroutine signatures (which were experimental until 5.36)... |
|
39
|
|
|
|
|
|
|
if ($] < 5.36) { |
|
40
|
|
|
|
|
|
|
experimental->import('signatures'); |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
} |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
FILTER { |
|
45
|
|
|
|
|
|
|
return if m{ \A __(DATA|END)__ \n }xms; |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# Remember where we parked... |
|
48
|
|
|
|
|
|
|
my ($filename, $start_line) = (caller 1)[1,2]; |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# What filter blocks look like... |
|
51
|
|
|
|
|
|
|
my @filters; |
|
52
|
|
|
|
|
|
|
my $PERL_WITH_FILTER_BLOCKS = qr{ |
|
53
|
|
|
|
|
|
|
\A (?&PerlEntireDocument) \z |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
(?(DEFINE) |
|
56
|
|
|
|
|
|
|
(? (?> |
|
57
|
|
|
|
|
|
|
filter \b |
|
58
|
|
|
|
|
|
|
(?> |
|
59
|
|
|
|
|
|
|
(?<_> (?>(?&PerlNWS)) |
|
60
|
|
|
|
|
|
|
(?{ _expected('PPR rule name') }) |
|
61
|
|
|
|
|
|
|
(?(? [A-Za-z_]++ )) (?>(?&PerlOWS)) |
|
62
|
|
|
|
|
|
|
(?{ _expected('mode, rule, or code block') }) |
|
63
|
|
|
|
|
|
|
(? :extend | ) (?>(?&PerlOWS)) |
|
64
|
|
|
|
|
|
|
(?{ _expected('rule or code block') }) |
|
65
|
|
|
|
|
|
|
(? \( (?>(?&PPR_X_balanced_parens)) \) )?+ (?>(?&PerlOWS)) |
|
66
|
|
|
|
|
|
|
(?{ _expected('code block') }) |
|
67
|
|
|
|
|
|
|
(? (?>(?&PerlBlock)) ) |
|
68
|
|
|
|
|
|
|
) |
|
69
|
|
|
|
|
|
|
(?{ _expected(); |
|
70
|
|
|
|
|
|
|
my $len = length($+{_}) + 6; |
|
71
|
|
|
|
|
|
|
push @filters, { POS => pos() - $len, LEN => $len, END => pos(), |
|
72
|
|
|
|
|
|
|
BLOCKPOS => pos() - length($+{BLOCK}), %+ }; |
|
73
|
|
|
|
|
|
|
}) |
|
74
|
|
|
|
|
|
|
| |
|
75
|
|
|
|
|
|
|
(?{ push @filters, { POS => pos() - 6, EXPECTED => _expected(), INVALID => 1 } }) |
|
76
|
|
|
|
|
|
|
) |
|
77
|
|
|
|
|
|
|
| |
|
78
|
|
|
|
|
|
|
(?>(?&PerlStdControlBlock)) |
|
79
|
|
|
|
|
|
|
)) |
|
80
|
|
|
|
|
|
|
) |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
$PPR::X::GRAMMAR |
|
83
|
|
|
|
|
|
|
}xms; |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Did we find any??? |
|
86
|
|
|
|
|
|
|
if (/$PERL_WITH_FILTER_BLOCKS/) { |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Delete all the filters, reporting bad filters, but leaving the line numbers unchanged... |
|
89
|
|
|
|
|
|
|
my $invalid; |
|
90
|
|
|
|
|
|
|
for my $filter (reverse @filters) { |
|
91
|
|
|
|
|
|
|
if ($filter->{INVALID}) { |
|
92
|
|
|
|
|
|
|
substr($_, $filter->{POS}, 0) |
|
93
|
|
|
|
|
|
|
= qq{BEGIN { die "Invalid filter specification. \Q$filter->{EXPECTED}\E" } }; |
|
94
|
|
|
|
|
|
|
$invalid = 1; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
else { |
|
97
|
|
|
|
|
|
|
substr($_, $filter->{POS}, $filter->{LEN}) =~ tr/\n/ /c; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
return if $invalid; |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Normalize filters... |
|
103
|
|
|
|
|
|
|
for my $filter (@filters) { |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
$filter->{RULENAME} =~ s{ \A (?:Perl)?+ (.*) \z }{Perl$1}xms; |
|
106
|
|
|
|
|
|
|
$filter->{STDNAME} = $filter->{RULENAME} =~ s{ \A Perl }{PerlStd}xmsr; |
|
107
|
|
|
|
|
|
|
$filter->{REGEX} //= "(?&$filter->{STDNAME})"; |
|
108
|
|
|
|
|
|
|
my $active_regex = $filter->{REGEX} |
|
109
|
|
|
|
|
|
|
=~ s{ \(\?\(DEFINE\) (?>(?&PPR_X_balanced_parens)) \) |
|
110
|
|
|
|
|
|
|
$PPR::X::GRAMMAR }{}gxmsr; |
|
111
|
|
|
|
|
|
|
my @captures = _uniq($active_regex =~ m{ \(\?< \K [^>]++ }gxms); |
|
112
|
|
|
|
|
|
|
$filter->{CAPTURES} = \@captures; |
|
113
|
|
|
|
|
|
|
$filter->{UNPACK} = @captures > 1 ? '[@+{'. join(',', map { "'$_'" } @captures) .'}]' |
|
114
|
|
|
|
|
|
|
: @captures == 1 ? qq{[\$+{'$captures[0]'}]} |
|
115
|
|
|
|
|
|
|
: q{[]}; |
|
116
|
|
|
|
|
|
|
my $PARAMS = join ',', map { '$'.$_ } @captures; |
|
117
|
|
|
|
|
|
|
$filter->{HANDLER} = qq{sub ($PARAMS)} |
|
118
|
|
|
|
|
|
|
. _line_comment($_,$filter->{BLOCKPOS},$start_line) |
|
119
|
|
|
|
|
|
|
. $filter->{BLOCK}; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Build progressive regexes for each filter... |
|
123
|
|
|
|
|
|
|
my ($PATTERN, $SELFPATTERN); |
|
124
|
|
|
|
|
|
|
for my $f (keys @filters) { |
|
125
|
|
|
|
|
|
|
my $filter = $filters[$f]; |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# The pattern for this filter needs to capture match information... |
|
128
|
|
|
|
|
|
|
$SELFPATTERN = $filter->{REGEX}; |
|
129
|
|
|
|
|
|
|
$PATTERN = qq{ |
|
130
|
|
|
|
|
|
|
(?<_> $filter->{REGEX} ) |
|
131
|
|
|
|
|
|
|
(?{ my \$len = length(\$+{_}); |
|
132
|
|
|
|
|
|
|
push \@Filter::Syntactic::captures, { RULENAME => '$filter->{RULENAME}', |
|
133
|
|
|
|
|
|
|
CAPTURES => $filter->{UNPACK}, |
|
134
|
|
|
|
|
|
|
MATCH => \$+{_}, |
|
135
|
|
|
|
|
|
|
POS => pos() - \$len, |
|
136
|
|
|
|
|
|
|
LEN => \$len, |
|
137
|
|
|
|
|
|
|
END => pos(), |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
}) |
|
140
|
|
|
|
|
|
|
}; |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# If this filter extends a current rule, it needs to include the standard syntax... |
|
143
|
|
|
|
|
|
|
if ($filter->{MODE} eq ':extend') { |
|
144
|
|
|
|
|
|
|
$PATTERN .= qq{ | (?>(?&$filter->{STDNAME})) }; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# The reparsing rule ALWAYS includes the standard syntax... |
|
148
|
|
|
|
|
|
|
# (because it's reparsing partially transformed source code, which may be standard Perl) |
|
149
|
|
|
|
|
|
|
$SELFPATTERN .= qq{ | (?>(?&$filter->{STDNAME})) }; |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# Then we wrap it in the appropriately named subrule... |
|
152
|
|
|
|
|
|
|
$PATTERN = qq{ (?<$filter->{RULENAME}> $PATTERN ) }; |
|
153
|
|
|
|
|
|
|
$SELFPATTERN = qq{ (?<$filter->{RULENAME}> $SELFPATTERN ) }; |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# The filter also needs to recognize any new syntax for any later filters... |
|
156
|
|
|
|
|
|
|
my $SELFEXTRAS = q{}; |
|
157
|
|
|
|
|
|
|
for my $next_filter (@filters[$f+1..$#filters]) { |
|
158
|
|
|
|
|
|
|
my $NEXT_PAT = $next_filter->{REGEX}; |
|
159
|
|
|
|
|
|
|
$NEXT_PAT = $next_filter->{MODE} eq ':extend' |
|
160
|
|
|
|
|
|
|
? qq{ (?<$next_filter->{RULENAME}> $NEXT_PAT | (?>(?&$next_filter->{STDNAME}))) } |
|
161
|
|
|
|
|
|
|
: qq{ (?<$next_filter->{RULENAME}> $NEXT_PAT ) }; |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
$PATTERN .= $NEXT_PAT; |
|
164
|
|
|
|
|
|
|
$SELFEXTRAS .= $NEXT_PAT; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# And the filter's version of the full document-parsing regex gets saved in the filter... |
|
168
|
|
|
|
|
|
|
$filter->{FULLREGEX} |
|
169
|
|
|
|
|
|
|
= qq{ \\A (?&PerlEntireDocument) \\z (?(DEFINE) $PATTERN ) \$PPR::X::GRAMMAR }; |
|
170
|
|
|
|
|
|
|
$filter->{SELFREGEX} |
|
171
|
|
|
|
|
|
|
= qq{ \\A $SELFPATTERN \\z (?(DEFINE) $SELFEXTRAS ) \$PPR::X::GRAMMAR }; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Build handlers... |
|
175
|
|
|
|
|
|
|
for my $filter (@filters) { |
|
176
|
|
|
|
|
|
|
my $PARAMS = join ',', map { '$'.$_ } @{$filter->{CAPTURES}}; |
|
177
|
|
|
|
|
|
|
my $__LINE__ = _line_loc($_,$filter->{POS},$start_line); |
|
178
|
|
|
|
|
|
|
$filter->{HANDLER} = qq{sub ($PARAMS)} |
|
179
|
|
|
|
|
|
|
. _line_comment($_,$filter->{BLOCKPOS},$start_line) |
|
180
|
|
|
|
|
|
|
. qq{ { # Check for nested replacements... |
|
181
|
|
|
|
|
|
|
if (\$_ ne \$_{MATCH}) { |
|
182
|
|
|
|
|
|
|
if (m{$filter->{SELFREGEX}}xms) { |
|
183
|
|
|
|
|
|
|
($PARAMS) = \@{$filter->{UNPACK}}; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
else { |
|
186
|
|
|
|
|
|
|
warn 'filter $filter->{NAME} from ', __PACKAGE__, |
|
187
|
|
|
|
|
|
|
' (', __FILE__, ' $__LINE__)', |
|
188
|
|
|
|
|
|
|
' is not recursively self-consistent at ', |
|
189
|
|
|
|
|
|
|
"\$_{LOC}\n"; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# Execute the transformation... |
|
194
|
|
|
|
|
|
|
$filter->{BLOCK}; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
. _line_comment($_,$filter->{END},$start_line); |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Build the lookup table of transformation handlers for each filter... |
|
201
|
|
|
|
|
|
|
my $LUT = q{my %_HANDLER = (} |
|
202
|
|
|
|
|
|
|
. join(',', map { qq{ '$_->{RULENAME}' => $_->{HANDLER} } } @filters) |
|
203
|
|
|
|
|
|
|
. q{);}; |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Build replacement processing loops... |
|
206
|
|
|
|
|
|
|
my $FIRST_FILTER = 1; |
|
207
|
|
|
|
|
|
|
my $PROC_LOOPS = q{ my ($filename, $start_line); }; |
|
208
|
|
|
|
|
|
|
for my $filter (@filters) { |
|
209
|
|
|
|
|
|
|
$PROC_LOOPS .= q{ local @Filter::Syntactic::captures; |
|
210
|
|
|
|
|
|
|
($filename, $start_line) = (caller 1)[1,2]; |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
. qq{ if (m{$filter->{FULLREGEX}}xms) } |
|
213
|
|
|
|
|
|
|
. (q{ { |
|
214
|
|
|
|
|
|
|
# Index captures and generate error message context info... |
|
215
|
|
|
|
|
|
|
my $index = 1; |
|
216
|
|
|
|
|
|
|
for my $capture (sort {$a->{POS} <=> $b->{POS}} @Filter::Syntactic::captures) { |
|
217
|
|
|
|
|
|
|
$capture->{ORD} = $index++; |
|
218
|
|
|
|
|
|
|
$capture->{LOC} = qq{$filename } |
|
219
|
|
|
|
|
|
|
. Filter::Syntactic::_line_loc( |
|
220
|
|
|
|
|
|
|
$_, $capture->{POS}, $start_line |
|
221
|
|
|
|
|
|
|
); |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# Identify and record any nested captures... |
|
225
|
|
|
|
|
|
|
for my $c (reverse keys @Filter::Syntactic::captures) { |
|
226
|
|
|
|
|
|
|
my $capture = $Filter::Syntactic::captures[$c]; |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
POSSIBLE_OUTER: |
|
229
|
|
|
|
|
|
|
for my $prev (@Filter::Syntactic::captures[reverse 0..$c-1]) { |
|
230
|
|
|
|
|
|
|
last POSSIBLE_OUTER if $prev->{END} < $capture->{POS}; |
|
231
|
|
|
|
|
|
|
if ($capture->{END} > $prev->{END}) { |
|
232
|
|
|
|
|
|
|
push @{$prev->{OUTERS}}, $capture; |
|
233
|
|
|
|
|
|
|
use Scalar::Util 'weaken'; |
|
234
|
|
|
|
|
|
|
weaken($prev->{OUTERS}[-1]); |
|
235
|
|
|
|
|
|
|
} |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# Install replacement code and any adjust outer captures... |
|
240
|
|
|
|
|
|
|
for my $capture |
|
241
|
|
|
|
|
|
|
(sort {$b->{POS} <=> $a->{POS}} @Filter::Syntactic::captures) { |
|
242
|
|
|
|
|
|
|
# Generate replacement code... |
|
243
|
|
|
|
|
|
|
my $replacement = do { |
|
244
|
|
|
|
|
|
|
local $_ = substr($_, $capture->{POS}, $capture->{LEN}); |
|
245
|
|
|
|
|
|
|
local *_ = $capture; |
|
246
|
|
|
|
|
|
|
$_HANDLER{ $capture->{RULENAME} }(@{$capture->{CAPTURES}}); |
|
247
|
|
|
|
|
|
|
}; |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# Replace capture... |
|
250
|
|
|
|
|
|
|
substr($_, $capture->{POS}, $capture->{LEN}) = $replacement; |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Adjust length of surrounding captures... |
|
253
|
|
|
|
|
|
|
my $delta = length($replacement) - $capture->{LEN}; |
|
254
|
|
|
|
|
|
|
for my $outer (@{$capture->{OUTERS}}) { |
|
255
|
|
|
|
|
|
|
$outer->{LEN} += $delta; |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
if ($_debugging) { |
|
259
|
|
|
|
|
|
|
Filter::Syntactic::_debug( |
|
260
|
|
|
|
|
|
|
'Before filter ' => $_prev_under, |
|
261
|
|
|
|
|
|
|
' After filter ' => $_, |
|
262
|
|
|
|
|
|
|
); |
|
263
|
|
|
|
|
|
|
$_prev_under = $_; |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
} =~ s{}{$filter->{NAME}}gr |
|
267
|
|
|
|
|
|
|
) |
|
268
|
|
|
|
|
|
|
. ( $FIRST_FILTER |
|
269
|
|
|
|
|
|
|
? q{ else { |
|
270
|
|
|
|
|
|
|
# Failure to parse the initial source code is an external issue... |
|
271
|
|
|
|
|
|
|
my $error = $PPR::X::ERROR->origin($start_line, $filename); |
|
272
|
|
|
|
|
|
|
my $diagnostic = "syntax error at $filename line " . $error->line; |
|
273
|
|
|
|
|
|
|
$diagnostic .= qq{\nnear: } |
|
274
|
|
|
|
|
|
|
. ($error->source =~ s{ \A (\s* \S \N* ) .* }{$1}xmsr |
|
275
|
|
|
|
|
|
|
=~ tr/\n/ /r) |
|
276
|
|
|
|
|
|
|
if $diagnostic !~ /, near/; |
|
277
|
|
|
|
|
|
|
die "$diagnostic\n"; |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
: q{ else { |
|
281
|
|
|
|
|
|
|
# Report the (presumably) filter-induced syntax error... |
|
282
|
|
|
|
|
|
|
my $error = $PPR::X::ERROR->origin($start_line, $filename); |
|
283
|
|
|
|
|
|
|
my $diagnostic = "syntax error at $filename line " . $error->line; |
|
284
|
|
|
|
|
|
|
$diagnostic .= qq{\nnear: } |
|
285
|
|
|
|
|
|
|
. ($error->source =~ s{ \A (\s* \S \N* ) .* }{$1}xmsr |
|
286
|
|
|
|
|
|
|
=~ tr/\n/ /r) |
|
287
|
|
|
|
|
|
|
if $diagnostic !~ /, near/; |
|
288
|
|
|
|
|
|
|
die "Possible problem with source filter at ", |
|
289
|
|
|
|
|
|
|
(caller 1)[1] . " line ", ($start_line-1) . "\n", |
|
290
|
|
|
|
|
|
|
"\n$diagnostic\n", |
|
291
|
|
|
|
|
|
|
"(possibly the result of source filtering by ", |
|
292
|
|
|
|
|
|
|
__PACKAGE__ . " at line " . ($start_line-1) . ")\n"; |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
); |
|
296
|
|
|
|
|
|
|
$FIRST_FILTER = 0; |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# Create a final syntax check after all the filters have been applied... |
|
300
|
|
|
|
|
|
|
my $FINAL_CHECK = q{ |
|
301
|
|
|
|
|
|
|
if ($_ !~ m{ \A (?>(?&PerlEntireDocument)) \z $PPR::X::GRAMMAR }xms) { |
|
302
|
|
|
|
|
|
|
# Report that the final transformation isn't valid Perl... |
|
303
|
|
|
|
|
|
|
my ($file, $line) = (caller 1)[1,2]; $line--; |
|
304
|
|
|
|
|
|
|
my $error = $PPR::X::ERROR->origin($start_line, $filename); |
|
305
|
|
|
|
|
|
|
my $diagnostic = "syntax error at $filename line " . $error->line; |
|
306
|
|
|
|
|
|
|
$diagnostic .= qq{\nnear: } |
|
307
|
|
|
|
|
|
|
. ($error->source =~ s{ \A (\s* \S \N* ) .* }{$1}xmsr |
|
308
|
|
|
|
|
|
|
=~ tr/\n/ /r) |
|
309
|
|
|
|
|
|
|
if $diagnostic !~ /, near/; |
|
310
|
|
|
|
|
|
|
die "Possible problem with source filter at $file line $line\n", |
|
311
|
|
|
|
|
|
|
"\n$diagnostic\n", |
|
312
|
|
|
|
|
|
|
"(possibly the result of source filtering by " . __PACKAGE__ . " at line $line)\n"; |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
} =~ s{}{$start_line - 1}gre; |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# If there was more than one filter, debug the final state... |
|
317
|
|
|
|
|
|
|
if (@filters > 1) { |
|
318
|
|
|
|
|
|
|
$FINAL_CHECK .= q{ |
|
319
|
|
|
|
|
|
|
Filter::Syntactic::_debug( |
|
320
|
|
|
|
|
|
|
'Initial source' => $_initial_under, ' Final source' => $_, "final" |
|
321
|
|
|
|
|
|
|
) if $_debugging; |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# Put the entire source filter together... |
|
326
|
|
|
|
|
|
|
my $FILTER = qq{ |
|
327
|
|
|
|
|
|
|
use Filter::Simple; |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
FILTER { |
|
330
|
|
|
|
|
|
|
# Handle options... |
|
331
|
|
|
|
|
|
|
my \$_debugging = \@_ && \$_[1] && \$_[1] eq '-debug'; |
|
332
|
|
|
|
|
|
|
if (!\$_debugging && \$_[1]) { |
|
333
|
|
|
|
|
|
|
warn "Unknown option: \$_[1] at " . join(' line ', (caller 1)[1,2]) . "\n"; |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
# Prep for debugging... |
|
337
|
|
|
|
|
|
|
my \$_prev_under = \$_; |
|
338
|
|
|
|
|
|
|
my \$_initial_under = \$_; |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# Build filter... |
|
341
|
|
|
|
|
|
|
$LUT; |
|
342
|
|
|
|
|
|
|
$PROC_LOOPS |
|
343
|
|
|
|
|
|
|
$FINAL_CHECK |
|
344
|
|
|
|
|
|
|
} { terminator => "" }; |
|
345
|
|
|
|
|
|
|
}; |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
# Install new filter, adjusting line reporting... |
|
348
|
|
|
|
|
|
|
substr ($_, $filters[0]{POS}//0, 0) |
|
349
|
|
|
|
|
|
|
= $FILTER . _line_comment($_, $filters[0]{POS}, $start_line); |
|
350
|
|
|
|
|
|
|
} |
|
351
|
|
|
|
|
|
|
else { |
|
352
|
|
|
|
|
|
|
# Report syntax error... |
|
353
|
|
|
|
|
|
|
my $error = $PPR::X::ERROR->origin($start_line, $filename); |
|
354
|
|
|
|
|
|
|
my $diagnostic = $error->diagnostic || "syntax error at $filename line " . $error->line; |
|
355
|
|
|
|
|
|
|
$diagnostic .= qq{\nnear: } . ($error->source =~ tr/\n/ /r) if $diagnostic !~ /, near/; |
|
356
|
|
|
|
|
|
|
die "$diagnostic\n"; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
} {terminator => ""}; |
|
359
|
|
|
|
|
|
|
|
|
360
|
3
|
|
|
3
|
|
12
|
sub _uniq (@list) { |
|
|
3
|
|
|
|
|
13
|
|
|
|
3
|
|
|
|
|
7
|
|
|
361
|
3
|
|
|
|
|
7
|
my %seen; |
|
362
|
3
|
|
|
|
|
16
|
return grep {!$seen{$_}++} @list; |
|
|
4
|
|
|
|
|
32
|
|
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
|
|
365
|
1
|
|
|
1
|
|
110
|
sub _debug ($pre_label, $pre, $post_label, $post, $is_final = 0) { |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2
|
|
|
366
|
|
|
|
|
|
|
# Set up the (possibly paged) output stream for debugging info... |
|
367
|
1
|
|
|
|
|
3
|
state $DBOUT = do { |
|
368
|
1
|
|
|
|
|
3
|
my $fh; |
|
369
|
1
|
50
|
33
|
|
|
15
|
if ($ENV{DIFFPAGER} && open $fh, "|$ENV{DIFFPAGER}") { $fh } |
|
|
0
|
50
|
33
|
|
|
0
|
|
|
370
|
0
|
|
|
|
|
0
|
elsif ($ENV{PAGER} && open $fh, "|$ENV{PAGER}" ) { $fh } |
|
371
|
1
|
|
|
|
|
4
|
else { \*STDERR } |
|
372
|
|
|
|
|
|
|
}; |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# If we can diff, then diff... |
|
375
|
1
|
50
|
|
|
|
5
|
if (eval { require Text::Diff }) { |
|
|
1
|
0
|
|
|
|
853
|
|
|
376
|
1
|
|
|
|
|
10944
|
print {$DBOUT} "--- $pre_label\n+++ $post_label\n", |
|
|
1
|
|
|
|
|
8
|
|
|
377
|
|
|
|
|
|
|
Text::Diff::diff(\$pre, \$post) . "\n"; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# Otherwise, just print out each post-transformation source (except the last)... |
|
381
|
|
|
|
|
|
|
elsif (!$is_final) { |
|
382
|
0
|
|
|
|
|
|
print {$DBOUT} '=====[ '. _trim($post_label) . " ]========================\n\n$post\n"; |
|
|
0
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
} |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
# For the last, just rule a line under the previous output (which will be identical)... |
|
386
|
|
|
|
|
|
|
else { |
|
387
|
0
|
|
|
|
|
|
print {$DBOUT} ('=' x 50), "\n\n"; |
|
|
0
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
} |
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
|
|
391
|
0
|
|
|
0
|
|
|
sub _trim ($str) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
|
return $str =~ s{^\s+}{}r =~ s{\s*$}{}r; |
|
393
|
|
|
|
|
|
|
} |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
1; # Magic true value required at end of module |
|
396
|
|
|
|
|
|
|
__END__ |