# tests that aren't important enough for base.term
-print "1..14\n";
+print "1..22\n";
$x = "\\n";
print "#1\t:$x: eq " . ':\n:' . "\n";
if ("@foo[0..1]b" eq "1 2b") { print "ok 13\n";} else {print "not ok 13\n";}
$" = '::';
if ("@foo[0..1]b" eq "1::2b") { print "ok 14\n";} else {print "not ok 14\n";}
+
+# test if C<eval "{...}"> distinguishes between blocks and hashrefs
+
+$a = "{ '\\'' , 'foo' }";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 15\n";} else {print "not ok 15\n";}
+
+$a = "{ '\\\\\\'abc' => 'foo' }";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 16\n";} else {print "not ok 16\n";}
+
+$a = "{'a\\\n\\'b','foo'}";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 17\n";} else {print "not ok 17\n";}
+
+$a = "{'\\\\\\'\\\\'=>'foo'}";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 18\n";} else {print "not ok 18\n";}
+
+$a = "{q,a'b,,'foo'}";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 19\n";} else {print "not ok 19\n";}
+
+$a = "{q[[']]=>'foo'}";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 20\n";} else {print "not ok 20\n";}
+
+# needs disambiguation if first term is a variable
+$a = "+{ \$a , 'foo'}";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 21\n";} else {print "not ok 21\n";}
+
+$a = "+{ \$a=>'foo'}";
+$a = eval $a;
+if (ref($a) eq 'HASH') {print "ok 22\n";} else {print "not ok 22\n";}
s = skipspace(s);
if (*s == '}')
OPERATOR(HASHBRACK);
- if (isALPHA(*s)) {
- for (t = s; t < bufend && isALNUM(*t); t++) ;
+ /* This hack serves to disambiguate a pair of curlies
+ * as being a block or an anon hash. Normally, expectation
+ * determines that, but in cases where we're not in a
+ * position to expect anything in particular (like inside
+ * eval"") we have to resolve the ambiguity. This code
+ * covers the case where the first term in the curlies is a
+ * quoted string. Most other cases need to be explicitly
+ * disambiguated by prepending a `+' before the opening
+ * curly in order to force resolution as an anon hash.
+ *
+ * XXX should probably propagate the outer expectation
+ * into eval"" to rely less on this hack, but that could
+ * potentially break current behavior of eval"".
+ * GSAR 97-07-21
+ */
+ t = s;
+ if (*s == '\'' || *s == '"' || *s == '`') {
+ /* common case: get past first string, handling escapes */
+ for (t++; t < bufend && *t != *s;)
+ if (*t++ == '\\' && (*t == '\\' || *t == *s))
+ t++;
+ t++;
+ }
+ else if (*s == 'q') {
+ if (++t < bufend
+ && (!isALNUM(*t)
+ || ((*t == 'q' || *t == 'x') && ++t < bufend
+ && !isALNUM(*t)))) {
+ char *tmps;
+ char open, close, term;
+ I32 brackets = 1;
+
+ while (t < bufend && isSPACE(*t))
+ t++;
+ term = *t;
+ open = term;
+ if (term && (tmps = strchr("([{< )]}> )]}>",term)))
+ term = tmps[5];
+ close = term;
+ if (open == close)
+ for (t++; t < bufend; t++) {
+ if (*t == '\\' && t+1 < bufend && term != '\\')
+ t++;
+ else if (*t == term)
+ break;
+ }
+ else
+ for (t++; t < bufend; t++) {
+ if (*t == '\\' && t+1 < bufend && term != '\\')
+ t++;
+ else if (*t == term && --brackets <= 0)
+ break;
+ else if (*t == open)
+ brackets++;
+ }
+ }
+ t++;
}
- else if (*s == '\'' || *s == '"') {
- t = strchr(s+1,*s);
- if (!t++)
- t = s;
+ else if (isALPHA(*s)) {
+ for (t++; t < bufend && isALNUM(*t); t++) ;
}
- else
- t = s;
while (t < bufend && isSPACE(*t))
t++;
- if ((*t == ',' && !isLOWER(*s)) || (*t == '=' && t[1] == '>'))
+ /* if comma follows first term, call it an anon hash */
+ /* XXX it could be a comma expression with loop modifiers */
+ if (t < bufend && ((*t == ',' && (*s == 'q' || !isLOWER(*s)))
+ || (*t == '=' && t[1] == '>')))
OPERATOR(HASHBRACK);
if (expect == XREF)
expect = XTERM;