From afb78f5d142786169817709e6ec4c48637bcae93 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 21 May 2015 10:25:07 +0100 Subject: 35248: treat fully parenthised zsh patterns as complete case patterns again --- ChangeLog | 6 ++++ Src/lex.c | 2 -- Src/parse.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++------ Test/A01grammar.ztst | 36 ++++++++++++++++++-- 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 + + * 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 * 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 -- cgit 1.4.1