summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Src/lex.c2
-rw-r--r--Src/parse.c95
-rw-r--r--Test/A01grammar.ztst36
4 files changed, 124 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index b1b96379c..4c1fe2116 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-05-21 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 35248: Src/lex.c, Src/parse.c, Test/A01grammar.ztst:
+ treat fully parenthesised zsh patterns as complete
+ case patterns again.
+
2015-05-20 Peter Stephenson <p.stephenson@samsung.com>
* Ismail: 35232: Completion/Unix/Type/_urls: matching
diff --git a/Src/lex.c b/Src/lex.c
index 87b0cd3af..841fb0b86 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -761,8 +761,6 @@ gettok(void)
lexstop = 0;
return BAR;
case LX1_INPAR:
- if (incasepat == 2)
- return INPAR;
d = hgetc();
if (d == '(') {
if (infor) {
diff --git a/Src/parse.c b/Src/parse.c
index c48669995..053db3fe2 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -1152,7 +1152,7 @@ par_case(int *cmplx)
YYERRORV(oecused);
}
brflag = (tok == INBRACE);
- incasepat = 2;
+ incasepat = 1;
incmdpos = 0;
noaliases = ona;
nocorrect = onc;
@@ -1165,10 +1165,8 @@ par_case(int *cmplx)
zshlex();
if (tok == OUTBRACE)
break;
- if (tok == INPAR) {
- incasepat = 1;
+ if (tok == INPAR)
zshlex();
- }
if (tok != STRING)
YYERRORV(oecused);
if (!strcmp(tokstr, "esac"))
@@ -1178,19 +1176,96 @@ par_case(int *cmplx)
pp = ecadd(0);
palts = ecadd(0);
nalts = 0;
+ /*
+ * Hack here.
+ *
+ * [Pause for astonished hubbub to subside.]
+ *
+ * The next token we get may be
+ * - ")" or "|" if we're looking at an honest-to-god
+ * "case" patten, either because there's no opening
+ * parenthesis, or because SH_GLOB is set and we
+ * managed to grab an initial "(" to mark the start
+ * of the case pattern.
+ * - Something else --- we don't care what --- because
+ * we're parsing a complete "(...)" as a complete
+ * zsh pattern. In that case, we treat this as a
+ * single instance of a case pattern but we pretend
+ * we're doing proper case parsing --- in which the
+ * parentheses and bar are in different words from
+ * the string, so may be separated by whitespace.
+ * So we quietly massage the whitespace and hope
+ * no one noticed. This is horrible, but it's
+ * unfortunately too difficult to comine traditional
+ * zsh patterns with a properly parsed case pattern
+ * without generating incompatibilities which aren't
+ * all that popular (I've discovered).
+ * - We can also end up with something other than ")" or "|"
+ * just because we're looking at garbage.
+ *
+ * Because of the second case, what happens next might
+ * be the start of the command after the pattern, so we
+ * need to treat it as in command position. Luckily
+ * this doesn't affect our ability to match a | or ) as
+ * these are valid on command lines.
+ */
+ incasepat = 0;
+ incmdpos = 1;
for (;;) {
- ecstr(str);
- ecadd(ecnpats++);
- nalts++;
-
zshlex();
if (tok == OUTPAR) {
+ ecstr(str);
+ ecadd(ecnpats++);
+ nalts++;
+
incasepat = 0;
incmdpos = 1;
zshlex();
break;
- } else if (tok != BAR)
+ } else if (tok == BAR) {
+ ecstr(str);
+ ecadd(ecnpats++);
+ nalts++;
+
+ incasepat = 1;
+ incmdpos = 0;
+ } else {
+ if (!nalts && str[0] == Inpar) {
+ int pct = 0, sl;
+ char *s;
+
+ for (s = str; *s; s++) {
+ if (*s == Inpar)
+ pct++;
+ if (!pct)
+ break;
+ if (pct == 1) {
+ if (*s == Bar || *s == Inpar)
+ while (iblank(s[1]))
+ chuck(s+1);
+ if (*s == Bar || *s == Outpar)
+ while (iblank(s[-1]) &&
+ (s < str + 1 || s[-2] != Meta))
+ chuck(--s);
+ }
+ if (*s == Outpar)
+ pct--;
+ }
+ if (*s || pct || s == str)
+ YYERRORV(oecused);
+ /* Simplify pattern by removing surrounding (...) */
+ sl = strlen(str);
+ DPUTS(*str != Inpar || str[sl - 1] != Outpar,
+ "BUG: strange case pattern");
+ str[sl - 1] = '\0';
+ chuck(str);
+ ecstr(str);
+ ecadd(ecnpats++);
+ nalts++;
+ break;
+ }
YYERRORV(oecused);
+ }
zshlex();
if (tok != STRING)
@@ -1208,7 +1283,7 @@ par_case(int *cmplx)
break;
if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR)
YYERRORV(oecused);
- incasepat = 2;
+ incasepat = 1;
incmdpos = 0;
zshlex();
}
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
index 41fb48688..50058e25d 100644
--- a/Test/A01grammar.ztst
+++ b/Test/A01grammar.ztst
@@ -614,7 +614,8 @@
>mytrue
>END
- fn() {
+ (emulate sh -c '
+ fn() {
case $1 in
( one | two | three )
print Matched $1
@@ -627,6 +628,7 @@
;;
esac
}
+ '
which fn
fn one
fn two
@@ -635,8 +637,8 @@
fn five
fn six
fn abecedinarian
- fn xylophone
-0: case word handling
+ fn xylophone)
+0: case word handling in sh emulation (SH_GLOB parentheses)
>fn () {
> case $1 in
> (one | two | three) print Matched $1 ;;
@@ -665,3 +667,31 @@
0: case patterns within words
>1 OK
>2 OK
+
+ case horrible in
+ ([a-m])(|[n-z])rr(|ib(um|le|ah)))
+ print It worked
+ ;;
+ esac
+ case "a string with separate words" in
+ (*with separate*))
+ print That worked, too
+ ;;
+ esac
+0:Unbalanced parentheses and spaces with zsh pattern
+>It worked
+>That worked, too
+
+ case horrible in
+ (([a-m])(|[n-z])rr(|ib(um|le|ah)))
+ print It worked
+ ;;
+ esac
+ case "a string with separate words" in
+ (*with separate*)
+ print That worked, too
+ ;;
+ esac
+0:Balanced parentheses and spaces with zsh pattern
+>It worked
+>That worked, too