Okay, I went through and did some debugging. I'm running in
5.005_03, like you, so I got the same error. I stepped through
the code using print statements, and it looks like the error is
basically that, in Switch.pm, when the filter is running over the
program source, it can't find any case statements.
Which means that the source isn't getting filtered properly,
and so the filtered source ends up with the same case statements
that are in your original source--but case isn't a valid Perl
bareword, so that's why you get that error.
But that's simply the symptom, really.
The *real* problem is this: Text::Balanced::_match_quotelike
is being called, and it matches from the first '?' to the last (the
one in the comment), and it sees that as a valid regex. In case
this doesn't quite make sense, it sees this:
? 'foo' : 'bar';
switch('x'){
case 'y' {print "y\n"}
else {print "x\n"}
}
# ?
Question marks ('?') are valid regex delimiters; valid in the
sense that you don't need a 'm' in front of them. They're like
'/'. You can just say:
if ($foo =~ ?bar?)
That's legal.
Here's a runthrough of what's going on, essentially; it makes
the most sense if you follow along in the original source.
- Switch.pm receives your program source, which looks like
this:
my $x = 2 ? 'foo' : 'bar';
switch('x'){
case 'y' {print "y\n"}
else {print "x\n"}
}
# ?
It steps through that source, matching against regular
expressions, in the form /\Gpattern/gc. This means that each
time the regex engine tries to do a match, it starts in the
source string *after* the last successful match. So using pos,
I tried to figure out what it was doing.
- The first match is at the end of the lexing loop. It's supposed
to match what looks like whitespace followed by non-whitespace,
and it matches this:
my
That's three characters: a newline, then 'my'. (I realize it's
hard to see the newline. :)
This puts pos at 3.
- The next thing it matches is done using
Text::Balanced::_match_variable, and it matches:
$x
Which is also three characters: a space, then '$x'. This puts pos
at 6.
- After this we go through a few other match attempts, then
are back down to the non-whitespace followed by whitespace,
which matches:
=
Which is two chars: a space, followed by '='. This puts pos at
8.
- Go through again, get back to non-whitespace followed
by whitespace. We match:
2
Which is two chars: a space, then '2'. This puts pos at 10.
- All of this matching is going on in a loop, and each time
through the loop we're trying to match against a bunch of
other things, as well. One rather important thing is each time
we try to match switch/case statements. We haven't done so
yet, because we've been doing other things. :)
We've also been trying to match "things that look like quotes",
using Text::Balanced::_match_quotelike. Nothing has matched
yet, but the next time we go through, we do:
In _match_quotelike we first match the '$pre' condition, which is
optional whitespace. This moves pos to 11. The next thing in
the string is '?': _match_quotelike looks at this and enters
an if condition, looking to see if this could be a regex match.
It looks to see if there's another '?' in the string--and there is!
It's hidden in a comment, but _match_quotelike doesn't notice,
and so the "quote" matched is:
? 'foo' : 'bar';
switch('x'){
case 'y' {print "y\n"}
else {print "x\n"}
}
# ?
This puts pos at 124. _match_quotelike returns this match,
and this puts us at the end of the string: we're done.
- Since we're done, that means we didn't match any of the
switch/case statements, which means that they got through
unfiltered. They get passed directly to Perl, which doesn't like
them, hence the error.
So this is my theory/observation on what's happening. I
haven't checked yet on 5.6 to see why it's working there; I
really have no idea why.
But it seems to fit pretty well.
UPDATE: I just tested this on Perl 5.6.0, and I got
errors there, as well. So it looks like it's matching in 5.6.0 as
a '?'-delimited regex as well. The error is slighty different:
syntax error at t.pl line 9, near "){"
String found where operator expected at t.pl line 10, near "case 'y'"
(Do you need to predeclare case?)
Execution of t.pl aborted due to compilation errors.
But it's certainly the same idea: it doesn't understand what
either switch or case is, which means that they didn't get
filtered properly. And stepping through using the same debugging
statements shows me that it's matching the same things in
5.005_03 as in 5.6.0.