js-on-sx: switch/case/default/break

Parser: jp-parse-switch-stmt + jp-parse-switch-cases + jp-parse-switch-body.
AST: (js-switch discr (("case" val body) ("default" nil body) ...)).

Transpile: wraps body in (call/cc (fn (__break__) ...)). Each case
clause becomes (when (or __matched__ (js-strict-eq discr val))
(set! __matched__ true) body). Fall-through works naturally via
__matched__. Default appended as (when (not __matched__) body).

363/365 unit (+6), 148/148 slice unchanged.
This commit is contained in:
2026-04-23 21:04:22 +00:00
parent 275d2ecbae
commit 9d3e54029a
4 changed files with 167 additions and 0 deletions

View File

@@ -937,6 +937,20 @@ cat > "$TMPFILE" << 'EPOCHS'
(epoch 1505)
(eval "(js-eval \"Array.of(1,2,3).length\")")
;; ── Phase 11.switch: switch/case/default/break ──────────────────
(epoch 1600)
(eval "(js-eval \"var r=0; switch(1){case 1: r=10; break;} r\")")
(epoch 1601)
(eval "(js-eval \"var r=0; switch(2){case 1: r=10; break; case 2: r=20; break;} r\")")
(epoch 1602)
(eval "(js-eval \"var r=0; switch(9){case 1: r=10; break; default: r=99;} r\")")
(epoch 1603)
(eval "(js-eval \"var r=0; switch(1){case 1: case 2: r=12; break;} r\")")
(epoch 1604)
(eval "(js-eval \"var r=''; switch('a'){case 'a': r='yes'; break;} r\")")
(epoch 1605)
(eval "(js-eval \"var r=0; switch(1){case 1: r=10; case 2: r=20; break;} r\")")
EPOCHS
OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
@@ -1436,6 +1450,14 @@ check 1503 "Array.isArray yes" 'true'
check 1504 "Array.isArray no" 'false'
check 1505 "Array.of length" '3'
# ── Phase 11.switch ─────────────────────────────────────────────
check 1600 "switch case 1 match" '10'
check 1601 "switch case 2 match" '20'
check 1602 "switch default" '99'
check 1603 "switch fallthrough stops on break" '12'
check 1604 "switch on string" '"yes"'
check 1605 "switch fallthrough chains" '20'
TOTAL=$((PASS + FAIL))
if [ $FAIL -eq 0 ]; then
echo "$PASS/$TOTAL JS-on-SX tests passed"