sub is_string ($) { $_[0]{T} =~ m/heredoc|string/; }
sub is_trans ($) { grep { $_[0]{E} eq $_ } qw(__ f_ i_); }
+sub qp ($) {
+ my ($p) = @_;
+ $p =~ s{\\}{\\\\}g;
+ $p =~ s{\'}{\\'}g;
+ $p =~ s{\n}{\\n}g;
+ $p =~ s{\t}{\\t}g;
+ return "'$p'";
+};
+
sub semiparse ($) {
($_) = @_;
my @o;
+ #my $in = $_;
# entries contain
# T type
# E exact input text (does not contain here doc contents)
$q ||= '"';
push @o, { T => 'heredoc', Q => $q, Delim => $d,
E => $&, P => "<<$q$d$q" };
- s{^
- ( .* \n )
- ( (?: (?! $d) .* \n )* )
- $d \n
- }{ $1 }xe or die "missing end of here doc $d\n";
- $o[$#o]{V} = $2;
+ if (s{^
+ ( .* \n )
+ ( (?: (?! $d \n ) .* \n )*? )
+ $d \n
+ }{ $1 }xe) {
+ $o[$#o]{V} = $2;
+ } else {
+ m{^.*\n} or confess;
+ $_ = $&;
+ $o[$#o]{V} = $';
+ $o[$#o]{Invented} = 1;
+ }
} elsif (s{^ (["'])( (?: [^\\'"]
| \\ [^"']
| (?! \1 ) [^"]
next if grep { !is_string($_) } @inputs;
my $q = $inputs[0]{Q};
next if grep { $_->{Q} ne $q } @inputs;
+ next if grep { $_->{Invented} } @inputs;
my $new = { T => 'joinedstrings',
E => (join '.', map { $_->{E} } @inputs),
P => (join '.', map { $_->{P} } @inputs),
$i--; # counteracts $i++
}
debug $ichunkstart, "semiparsed: ".join ' ', map { $_->{P} } @o;
+ # debug $ichunkstart, "semiparsed V: ".join ' ', map { defined $_->{V} ? ">$_->{V}<" : '-' } @o;
return @o;
}
next if $x->{E} eq $y->{E};
next if $x->{E} eq 'sprintf' and $y->{E} eq 'f_';
next if $x->{E} eq 'die' and $y->{E} eq 'confess';
+ next if $x->{E} eq 'die' and $y->{E} eq 'fail';
if ($y->{E} eq '+'
and @ys >= 3
and $ys[0]{E} eq '('
my ($lit, $what) = @_;
my $xl = substr($xs, 0, length($lit));
if ($xl ne $lit) {
- debug $ichunkstart, "not exactly x: \"..$xs\"";
- debug $ichunkstart, "not exactly y: $lit";
+ debug $ichunkstart, "not exactly x: ..".qp($xs);
+ debug $ichunkstart, "not exactly y: ".qp($lit);
my $next = @ys ? $ys[0]{P} : '(end)';
die "string contents mismatch near $what before $next\n";
}
$xs = substr($xs, length($lit));
};
for (;;) {
+ #print STDERR Dumper($fmt, $xs, \@xs, @ys);
if ($fmt !~ m{\%[^\%]}) {
$exactly->($fmt, '(tail)');
$fmt = '';
- die "text deleted from end of string\n" if length $xs;
+ die "text deleted from end of string: ".qp($xs)."\n"
+ if length $xs;
last;
}
$exactly->($`, '(literal)');
return unless length $@;
if ($@ =~ m{^missing end of here doc (\S+)\n}) {
# fudge this
+ # (this never happens now, but in the future we might
+ # want this code again eg to try adding to the chunk)
$before .= "\n$1\n";
$after .= "\n$1\n";
next;