summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2015-05-18 09:56:00 +0100
committerPeter Stephenson <pws@zsh.org>2015-05-18 09:56:00 +0100
commit52aeb9aaeb4799b760138a7c34b18ede4b47242a (patch)
tree0da193cbc61ac0000ae0bad210619276f63dccd5 /Src
parent34a1489f436d95bc2404f8e371130a469cbccebe (diff)
downloadzsh-52aeb9aaeb4799b760138a7c34b18ede4b47242a.tar.gz
zsh-52aeb9aaeb4799b760138a7c34b18ede4b47242a.zip
35168: Improve parsing of case patterns.
"|" is now found properly by looking for words that come from the lexical analyser, rather than hacking a pattern returned in one dollop. Update some completion functions that need extra quoting as a result. Add test for new parsing. Update version number to 5.0.8-dev-3 because of wordcode incompatibility.
Diffstat (limited to 'Src')
-rw-r--r--Src/lex.c2
-rw-r--r--Src/loop.c88
-rw-r--r--Src/parse.c89
-rw-r--r--Src/text.c28
4 files changed, 96 insertions, 111 deletions
diff --git a/Src/lex.c b/Src/lex.c
index 841fb0b86..87b0cd3af 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -761,6 +761,8 @@ gettok(void)
lexstop = 0;
return BAR;
case LX1_INPAR:
+ if (incasepat == 2)
+ return INPAR;
d = hgetc();
if (d == '(') {
if (infor) {
diff --git a/Src/loop.c b/Src/loop.c
index d025fbb9f..e4e8e2df8 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -545,7 +545,7 @@ execcase(Estate state, int do_exec)
Wordcode end, next;
wordcode code = state->pc[-1];
char *word, *pat;
- int npat, save;
+ int npat, save, nalts, ialt, patok;
Patprog *spprog, pprog;
end = state->pc + WC_CASE_SKIP(code);
@@ -561,60 +561,74 @@ execcase(Estate state, int do_exec)
if (wc_code(code) != WC_CASE)
break;
- pat = NULL;
- pprog = NULL;
save = 0;
- npat = state->pc[1];
- spprog = state->prog->pats + npat;
-
next = state->pc + WC_CASE_SKIP(code);
+ nalts = *state->pc++;
+ ialt = patok = 0;
if (isset(XTRACE)) {
- char *opat;
-
- pat = dupstring(opat = ecrawstr(state->prog, state->pc, NULL));
- singsub(&pat);
- save = (!(state->prog->flags & EF_HEAP) &&
- !strcmp(pat, opat) && *spprog != dummy_patprog2);
-
printprompt4();
fprintf(xtrerr, "case %s (", word);
- quote_tokenized_output(pat, xtrerr);
- fprintf(xtrerr, ")\n");
- fflush(xtrerr);
}
- state->pc += 2;
- if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
- pprog = *spprog;
-
- if (!pprog) {
- if (!pat) {
- char *opat;
+ while (!patok && nalts) {
+ npat = state->pc[1];
+ spprog = state->prog->pats + npat;
+ pprog = NULL;
+ pat = NULL;
+
+ if (isset(XTRACE)) {
int htok = 0;
-
- pat = dupstring(opat = ecrawstr(state->prog,
- state->pc - 2, &htok));
+ pat = dupstring(ecrawstr(state->prog, state->pc, &htok));
if (htok)
singsub(&pat);
- save = (!(state->prog->flags & EF_HEAP) &&
- !strcmp(pat, opat) && *spprog != dummy_patprog2);
+
+ if (ialt++)
+ fprintf(stderr, " | ");
+ quote_tokenized_output(pat, xtrerr);
}
- if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
- NULL)))
- zerr("bad pattern: %s", pat);
- else if (save)
- *spprog = pprog;
+
+ if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
+ pprog = *spprog;
+
+ if (!pprog) {
+ if (!pat) {
+ char *opat;
+ int htok = 0;
+
+ pat = dupstring(opat = ecrawstr(state->prog,
+ state->pc, &htok));
+ if (htok)
+ singsub(&pat);
+ save = (!(state->prog->flags & EF_HEAP) &&
+ !strcmp(pat, opat) && *spprog != dummy_patprog2);
+ }
+ if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
+ NULL)))
+ zerr("bad pattern: %s", pat);
+ else if (save)
+ *spprog = pprog;
+ }
+ if (pprog && pattry(pprog, word))
+ patok = 1;
+ state->pc += 2;
+ nalts--;
+ }
+ state->pc += 2 * nalts;
+ if (isset(XTRACE)) {
+ fprintf(xtrerr, ")\n");
+ fflush(xtrerr);
}
- if (pprog && pattry(pprog, word)) {
+ if (patok) {
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
do_exec));
while (!retflag && wc_code(code) == WC_CASE &&
WC_CASE_TYPE(code) == WC_CASE_AND) {
state->pc = next;
- code = *state->pc;
- state->pc += 3;
- next = state->pc + WC_CASE_SKIP(code) - 2;
+ code = *state->pc++;
+ next = state->pc + WC_CASE_SKIP(code);
+ nalts = *state->pc++;
+ state->pc += 2 * nalts;
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
do_exec));
}
diff --git a/Src/parse.c b/Src/parse.c
index 985eb8e71..c938d2dce 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -349,9 +349,8 @@ ecadd(wordcode c)
eclen += a;
}
ecbuf[ecused] = c;
- ecused++;
- return ecused - 1;
+ return ecused++;
}
/* Delete a wordcode. */
@@ -1128,7 +1127,7 @@ par_for(int *cmplx)
static void
par_case(int *cmplx)
{
- int oecused = ecused, brflag, p, pp, n = 1, type;
+ int oecused = ecused, brflag, p, pp, palts, type, nalts;
int ona, onc;
p = ecadd(0);
@@ -1153,7 +1152,7 @@ par_case(int *cmplx)
YYERRORV(oecused);
}
brflag = (tok == INBRACE);
- incasepat = 1;
+ incasepat = 2;
incmdpos = 0;
noaliases = ona;
nocorrect = onc;
@@ -1166,8 +1165,10 @@ par_case(int *cmplx)
zshlex();
if (tok == OUTBRACE)
break;
- if (tok == INPAR)
+ if (tok == INPAR) {
+ incasepat = 1;
zshlex();
+ }
if (tok != STRING)
YYERRORV(oecused);
if (!strcmp(tokstr, "esac"))
@@ -1176,89 +1177,45 @@ par_case(int *cmplx)
incasepat = 0;
incmdpos = 1;
type = WC_CASE_OR;
+ pp = ecadd(0);
+ palts = ecadd(0);
+ nalts = 0;
for (;;) {
+ ecstr(str);
+ ecadd(ecnpats++);
+ nalts++;
+
zshlex();
if (tok == OUTPAR) {
incasepat = 0;
incmdpos = 1;
zshlex();
break;
- } else if (tok == BAR) {
- char *str2;
- int sl = strlen(str);
-
- incasepat = 1;
- incmdpos = 0;
- str2 = hcalloc(sl + 2);
- strcpy(str2, str);
- str2[sl] = Bar;
- str2[sl+1] = '\0';
- str = str2;
- } else {
- int sl = strlen(str);
-
- if (!sl || str[sl - 1] != Bar) {
- /* POSIX allows (foo*) patterns */
- int pct;
- char *s;
-
- for (s = str, pct = 0; *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);
- break;
- } else {
- char *str2;
-
- if (tok != STRING)
- YYERRORV(oecused);
- str2 = hcalloc(sl + strlen(tokstr) + 1);
- strcpy(str2, str);
- strcpy(str2 + sl, tokstr);
- str = str2;
- }
- }
+ } else if (tok != BAR)
+ YYERRORV(oecused);
+
+ zshlex();
+ if (tok != STRING)
+ YYERRORV(oecused);
+ str = dupstring(tokstr);
}
- pp = ecadd(0);
- ecstr(str);
- ecadd(ecnpats++);
par_save_list(cmplx);
- n++;
if (tok == SEMIAMP)
type = WC_CASE_AND;
else if (tok == SEMIBAR)
type = WC_CASE_TESTAND;
ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp);
+ ecbuf[palts] = nalts;
if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag))
break;
if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR)
YYERRORV(oecused);
- incasepat = 1;
+ incasepat = 2;
incmdpos = 0;
zshlex();
}
incmdpos = 1;
+ incasepat = 0;
zshlex();
ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p);
diff --git a/Src/text.c b/Src/text.c
index b58c2516d..958303c68 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -602,6 +602,7 @@ gettext2(Estate state)
case WC_CASE:
if (!s) {
Wordcode end = state->pc + WC_CASE_SKIP(code);
+ wordcode nalts;
taddstr("case ");
taddstr(ecgetstr(state, EC_NODUP, NULL));
@@ -622,8 +623,13 @@ gettext2(Estate state)
taddchr(' ');
taddstr("(");
code = *state->pc++;
- taddstr(ecgetstr(state, EC_NODUP, NULL));
- state->pc++;
+ nalts = *state->pc++;
+ while (nalts--) {
+ taddstr(ecgetstr(state, EC_NODUP, NULL));
+ state->pc++;
+ if (nalts)
+ taddstr(" | ");
+ }
taddstr(") ");
tindent++;
n = tpush(code, 0);
@@ -631,6 +637,7 @@ gettext2(Estate state)
n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end);
}
} else if (state->pc < s->u._case.end) {
+ wordcode nalts;
dec_tindent();
switch (WC_CASE_TYPE(code)) {
case WC_CASE_OR:
@@ -638,11 +645,11 @@ gettext2(Estate state)
break;
case WC_CASE_AND:
- taddstr(";&");
+ taddstr(" ;&");
break;
default:
- taddstr(";|");
+ taddstr(" ;|");
break;
}
if (tnewlins)
@@ -651,8 +658,13 @@ gettext2(Estate state)
taddchr(' ');
taddstr("(");
code = *state->pc++;
- taddstr(ecgetstr(state, EC_NODUP, NULL));
- state->pc++;
+ nalts = *state->pc++;
+ while (nalts--) {
+ taddstr(ecgetstr(state, EC_NODUP, NULL));
+ state->pc++;
+ if (nalts)
+ taddstr(" | ");
+ }
taddstr(") ");
tindent++;
s->code = code;
@@ -666,11 +678,11 @@ gettext2(Estate state)
break;
case WC_CASE_AND:
- taddstr(";&");
+ taddstr(" ;&");
break;
default:
- taddstr(";|");
+ taddstr(" ;|");
break;
}
dec_tindent();