summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2012-09-12 14:03:08 -0700
committerFather Chrysostomos <sprout@cpan.org>2012-09-12 16:23:50 -0700
commit819b004ed974e0fe5ac23e956c3830dcc56b7c3e (patch)
tree56bfd4d8fc4d85ce9ea06857f20e1f6566380ef1
parent74736ae6be18c8156adf865e9641f1f6d230ede1 (diff)
downloadperl-819b004ed974e0fe5ac23e956c3830dcc56b7c3e.tar.gz
Fix listop-hash-infix parsing
With some list operators, this happens: $ ./miniperl -e 'warn({$_ => 1} + 1) if 0' syntax error at -e line 1, near "} +" Execution of -e aborted due to compilation errors. Putting + before the { or changing warn to print makes the prob- lem go away. The lexer is losing track of what token it expects next, so it ends up interpreting the + as a unary plus, instead of an infix plus. The parser doesn’t like that. It happens because of this logic under case '{' (aka leftbracket:) in toke.c:yylex: switch (PL_expect) { case XTERM: if (PL_oldoldbufptr == PL_last_lop) PL_lex_brackstack[PL_lex_brackets++] = XTERM; else PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR; PL_lex_allbrackets++; OPERATOR(HASHBRACK); The value we put on the brackstack is what we expect to find after the closing brace (case '}' pops it off). This particular if/else goes all the back to ef6361f9c226 (perl 5.000), or at least that was when it moved inside the XTERM case. Before that, we had this: if (oldoldbufptr == last_lop) lex_brackstack[lex_brackets++] = XTERM; else lex_brackstack[lex_brackets++] = XOPERATOR; if (expect == XTERM) OPERATOR(HASHBRACK); So it appears that the XTERM/XOPERATOR distinction, based on last_lop was the ‘old’ (and wrong) way of doing it, but it had to be changed in perl 5.000 for cases other than XTERM. That it remained for XTERM was probably an oversight, which is easy to understand, since I seem to be the first one to stumble across this after 18 years (what’s the rele- vant Klortho number?). Removing this last_lop check causes no tests to fail. And it makes sense, since anything coming right after an anonymous hash that could be either an infix or prefix operator must be infix.
-rw-r--r--t/base/lex.t7
-rw-r--r--toke.c5
2 files changed, 7 insertions, 5 deletions
diff --git a/t/base/lex.t b/t/base/lex.t
index 93985e7381..dc4abe50e9 100644
--- a/t/base/lex.t
+++ b/t/base/lex.t
@@ -1,6 +1,6 @@
#!./perl
-print "1..74\n";
+print "1..75\n";
$x = 'x';
@@ -367,3 +367,8 @@ print "$_ - s//\${\\%x}{3}/e\n";
eval 's/${foo#}//e';
print "not " unless $@;
print "ok 74 - s/\${foo#}//e\n";
+
+eval 'warn ({$_ => 1} + 1) if 0';
+print "not " if $@;
+print "ok 75 - listop({$_ => 1} + 1)\n";
+print "# $@" if $@;
diff --git a/toke.c b/toke.c
index 1db835c252..d6ac7529f9 100644
--- a/toke.c
+++ b/toke.c
@@ -5753,10 +5753,7 @@ Perl_yylex(pTHX)
}
switch (PL_expect) {
case XTERM:
- if (PL_oldoldbufptr == PL_last_lop)
- PL_lex_brackstack[PL_lex_brackets++] = XTERM;
- else
- PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR;
+ PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR;
PL_lex_allbrackets++;
OPERATOR(HASHBRACK);
case XOPERATOR: