DASH Shell discussions
 help / color / mirror / Atom feed
* [PATCH] case: Implement fallthrough (;&) operator
@ 2026-08-23 18:26 svav2021
  0 siblings, 0 replies; only message in thread
From: svav2021 @ 2026-08-23 18:26 UTC (permalink / raw)
  To: herbert; +Cc: dash, Arav Verma

From: Arav Verma <svav2021@gmail.com>

Add support for the fallthrough operator, as specified
in POSIX.1-2024, (defect 449). The ;& operator allows
execution to continue to the next case pattern without
re-evaluating the switch expression

Signed-off-by: Arav Verma <svav2021@gmail.com>
---
 src/eval.c   | 35 +++++++++++++++++++++++++----------
 src/mktokens |  1 +
 src/parser.c | 14 ++++++++++----
 3 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/src/eval.c b/src/eval.c
index 0f2a7ba..f9acea5 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -451,6 +451,7 @@ evalcase(union node *n, int flags)
 	union node *patp;
 	struct arglist arglist;
 	int status = 0;
+	int fallthrough = 0;
 
 	errlinno = lineno = n->ncase.linno;
 	if (funcline)
@@ -460,19 +461,33 @@ evalcase(union node *n, int flags)
 	expandarg(n->ncase.expr, &arglist, FNMATCH_IS_ENABLED ? EXP_TILDE :
 					   EXP_TILDE | EXP_MBCHAR);
 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
-		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
-			if (casematch(patp, arglist.list->text)) {
-				/* Ensure body is non-empty as otherwise
-				 * EV_EXIT may prevent us from setting the
-				 * exit status.
-				 */
-				if (evalskip == 0 && cp->nclist.body) {
-					status = evaltree(cp->nclist.body,
-							  flags);
+		int matched = 0;
+		
+		if (fallthrough) {
+			matched = 1;
+		} else {
+			for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+				if (casematch(patp, arglist.list->text)) {
+					matched = 1;
+					break;
 				}
-				goto out;
 			}
 		}
+		if (matched) {
+			int terminator = cp->type >> 8;
+			if (evalskip == 0 && cp->nclist.body) {
+				int eval_flags = flags;
+				if (terminator == TFALLTHRU)
+					eval_flags &= ~EV_EXIT;
+				status = evaltree(cp->nclist.body, eval_flags);
+				if (terminator != TFALLTHRU)
+					goto out;
+			} else if (terminator != TFALLTHRU)
+				goto out;
+			
+			if (terminator == TFALLTHRU)
+				fallthrough = 1;
+		}
 	}
 out:
 	return status;
diff --git a/src/mktokens b/src/mktokens
index dcef676..b7cd0ff 100644
--- a/src/mktokens
+++ b/src/mktokens
@@ -51,6 +51,7 @@ TPIPE	0	"|"
 TLP	0	"("
 TRP	1	")"
 TENDCASE 1	";;"
+TFALLTHRU 1    ";&"
 TENDBQUOTE 1	"`"
 TREDIR	0	redirection
 TWORD	0	word
diff --git a/src/parser.c b/src/parser.c
index e44b3c3..ede908f 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -463,10 +463,12 @@ next_case:
 
 			checkkwd = CHKNL | CHKKWD;
 			if ((t = readtoken()) != TESAC) {
-				if (t != TENDCASE)
+				if (t != TENDCASE && t != TFALLTHRU)
 					synexpect(TENDCASE);
-				else
+				else {
+					cp->type = NCLIST | (t << 8);
 					goto next_case;
+				}
 			}
 		}
 		*cpp = NULL;
@@ -833,11 +835,15 @@ xxreadtoken(void)
 				RETURN(TOR);
 			pungetc();
 			RETURN(TPIPE);
-		case ';':
-			if (pgetc_eatbnl() == ';')
+		case ';': {
+			int nextc = pgetc_eatbnl();
+			if (nextc == ';')
 				RETURN(TENDCASE);
+			else if (nextc == '&')
+				RETURN(TFALLTHRU);
 			pungetc();
 			RETURN(TSEMI);
+		}
 		case '(':
 			RETURN(TLP);
 		case ')':
-- 
2.47.3


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-23 18:27 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-23 18:26 [PATCH] case: Implement fallthrough (;&) operator svav2021

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox