Filter-Syntactic
view release on metacpan or search on metacpan
lib/Filter/Syntactic.pm view on Meta::CPAN
# Build handlers...
for my $filter (@filters) {
my $PARAMS = join ',', map { '$'.$_ } @{$filter->{CAPTURES}};
my $__LINE__ = _line_loc($_,$filter->{POS},$start_line);
$filter->{HANDLER} = qq{sub ($PARAMS)}
. _line_comment($_,$filter->{BLOCKPOS},$start_line)
. qq{ { # Check for nested replacements...
if (\$_ ne \$_{MATCH}) {
if (m{$filter->{SELFREGEX}}xms) {
($PARAMS) = \@{$filter->{UNPACK}};
}
else {
warn 'filter $filter->{NAME} from ', __PACKAGE__,
' (', __FILE__, ' $__LINE__)',
' is not recursively self-consistent at ',
"\$_{LOC}\n";
}
}
# Execute the transformation...
$filter->{BLOCK};
}
}
. _line_comment($_,$filter->{END},$start_line);
}
# Build the lookup table of transformation handlers for each filter...
my $LUT = q{my %_HANDLER = (}
. join(',', map { qq{ '$_->{RULENAME}' => $_->{HANDLER} } } @filters)
. q{);};
# Build replacement processing loops...
my $FIRST_FILTER = 1;
my $PROC_LOOPS = q{ my ($filename, $start_line); };
for my $filter (@filters) {
$PROC_LOOPS .= q{ local @Filter::Syntactic::captures;
($filename, $start_line) = (caller 1)[1,2];
}
. qq{ if (m{$filter->{FULLREGEX}}xms) }
. (q{ {
# Index captures and generate error message context info...
my $index = 1;
for my $capture (sort {$a->{POS} <=> $b->{POS}} @Filter::Syntactic::captures) {
$capture->{ORD} = $index++;
$capture->{LOC} = qq{$filename }
. Filter::Syntactic::_line_loc(
$_, $capture->{POS}, $start_line
);
}
# Identify and record any nested captures...
for my $c (reverse keys @Filter::Syntactic::captures) {
my $capture = $Filter::Syntactic::captures[$c];
POSSIBLE_OUTER:
for my $prev (@Filter::Syntactic::captures[reverse 0..$c-1]) {
last POSSIBLE_OUTER if $prev->{END} < $capture->{POS};
if ($capture->{END} > $prev->{END}) {
push @{$prev->{OUTERS}}, $capture;
use Scalar::Util 'weaken';
weaken($prev->{OUTERS}[-1]);
}
}
}
# Install replacement code and any adjust outer captures...
for my $capture
(sort {$b->{POS} <=> $a->{POS}} @Filter::Syntactic::captures) {
# Generate replacement code...
my $replacement = do {
local $_ = substr($_, $capture->{POS}, $capture->{LEN});
local *_ = $capture;
$_HANDLER{ $capture->{RULENAME} }(@{$capture->{CAPTURES}});
};
# Replace capture...
substr($_, $capture->{POS}, $capture->{LEN}) = $replacement;
# Adjust length of surrounding captures...
my $delta = length($replacement) - $capture->{LEN};
for my $outer (@{$capture->{OUTERS}}) {
$outer->{LEN} += $delta;
}
}
if ($_debugging) {
Filter::Syntactic::_debug(
'Before filter <FILTERNAME>' => $_prev_under,
' After filter <FILTERNAME>' => $_,
);
$_prev_under = $_;
}
}
} =~ s{<FILTERNAME>}{$filter->{NAME}}gr
)
. ( $FIRST_FILTER
? q{ else {
# Failure to parse the initial source code is an external issue...
my $error = $PPR::X::ERROR->origin($start_line, $filename);
my $diagnostic = "syntax error at $filename line " . $error->line;
$diagnostic .= qq{\nnear: }
. ($error->source =~ s{ \A (\s* \S \N* ) .* }{$1}xmsr
=~ tr/\n/ /r)
if $diagnostic !~ /, near/;
die "$diagnostic\n";
}
}
: q{ else {
# Report the (presumably) filter-induced syntax error...
my $error = $PPR::X::ERROR->origin($start_line, $filename);
my $diagnostic = "syntax error at $filename line " . $error->line;
$diagnostic .= qq{\nnear: }
. ($error->source =~ s{ \A (\s* \S \N* ) .* }{$1}xmsr
=~ tr/\n/ /r)
if $diagnostic !~ /, near/;
die "Possible problem with source filter at ",
(caller 1)[1] . " line ", ($start_line-1) . "\n",
"\n$diagnostic\n",
"(possibly the result of source filtering by ",
__PACKAGE__ . " at line " . ($start_line-1) . ")\n";
}
}
( run in 0.699 second using v1.01-cache-2.11-cpan-39bf76dae61 )