From c257971bb10f89bc4777513aeac6c7f9438494cb Mon Sep 17 00:00:00 2001 From: giles Date: Thu, 23 Apr 2026 22:58:49 +0000 Subject: [PATCH] js-on-sx: rest in array pattern + nested pattern tolerance Array destructure now supports [a, ...rest]. Rest entry is transpiled to (define name (js-list-slice tmp i (len tmp))). Nested patterns like [[a,b], c] now parse (as holes) instead of erroring. jp-skip-balanced skips nested groups. 440/442 unit (+2), 148/148 slice unchanged. --- lib/js/parser.sx | 51 +++++++++++++++++++++++++++++++++++++++++++++ lib/js/test.sh | 10 +++++++++ lib/js/transpile.sx | 11 ++++++++++ 3 files changed, 72 insertions(+) diff --git a/lib/js/parser.sx b/lib/js/parser.sx index 47b11be5..9c90db85 100644 --- a/lib/js/parser.sx +++ b/lib/js/parser.sx @@ -900,6 +900,29 @@ (append! names nil) (jp-advance! st) (jp-parse-arr-pattern-loop st names))) + ((jp-at? st "punct" "...") + (begin + (jp-advance! st) + (when + (= (get (jp-peek st) :type) "ident") + (append! names (list "rest" (get (jp-peek st) :value))) + (jp-advance! st)))) + ((jp-at? st "punct" "[") + (begin + (jp-skip-balanced st "[" "]") + (append! names nil) + (cond + ((jp-at? st "punct" ",") + (begin (jp-advance! st) (jp-parse-arr-pattern-loop st names))) + (else nil)))) + ((jp-at? st "punct" "{") + (begin + (jp-skip-balanced st "{" "}") + (append! names nil) + (cond + ((jp-at? st "punct" ",") + (begin (jp-advance! st) (jp-parse-arr-pattern-loop st names))) + (else nil)))) (else (begin (let @@ -909,11 +932,39 @@ (jp-advance! st) (error "expected ident in arr pattern")) (append! names nm)) + (when + (jp-at? st "op" "=") + (begin (jp-advance! st) (jp-parse-assignment st))) (cond ((jp-at? st "punct" ",") (begin (jp-advance! st) (jp-parse-arr-pattern-loop st names))) (else nil))))))) +(define + jp-skip-balanced + (fn + (st open close) + (jp-expect! st "punct" open) + (let ((depth 1)) (jp-skip-balanced-loop st open close depth)))) + +(define + jp-skip-balanced-loop + (fn + (st open close depth) + (cond + ((<= depth 0) nil) + ((>= (get st :idx) (len (get st :tokens))) nil) + ((jp-at? st "punct" open) + (begin + (jp-advance! st) + (jp-skip-balanced-loop st open close (+ depth 1)))) + ((jp-at? st "punct" close) + (begin + (jp-advance! st) + (jp-skip-balanced-loop st open close (- depth 1)))) + (else + (begin (jp-advance! st) (jp-skip-balanced-loop st open close depth)))))) + (define jp-parse-var-stmt (fn diff --git a/lib/js/test.sh b/lib/js/test.sh index 873cbbe5..a07ce1f0 100755 --- a/lib/js/test.sh +++ b/lib/js/test.sh @@ -1129,6 +1129,12 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 3003) (eval "(js-eval \"[3,1,2].sort((a,b)=>b-a).join(',')\")") +;; ── Phase 11.destruct2: rest in arr pattern, nested tolerance ── +(epoch 3100) +(eval "(js-eval \"var [h, ...tl] = [1,2,3,4]; tl.length\")") +(epoch 3101) +(eval "(js-eval \"var [h, ...tl] = [1,2,3,4]; tl.join(',')\")") + EPOCHS @@ -1740,6 +1746,10 @@ check 3001 "sort lex (10<5)" '"10,20,5"' check 3002 "sort numeric" '"1,2,3"' check 3003 "sort reverse" '"3,2,1"' +# ── Phase 11.destruct2 ──────────────────────────────────────── +check 3100 "rest arr length" '3' +check 3101 "rest arr join" '"2,3,4"' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "✓ $PASS/$TOTAL JS-on-SX tests passed" diff --git a/lib/js/transpile.sx b/lib/js/transpile.sx index 92944bb8..ea7ebe6e 100644 --- a/lib/js/transpile.sx +++ b/lib/js/transpile.sx @@ -951,6 +951,17 @@ ((empty? names) tail) ((= (first names) nil) (js-vardecl-arr-forms (rest names) tmp-sym (+ i 1) tail)) + ((and (list? (first names)) (= (first (first names)) "rest")) + (cons + (list + (js-sym "define") + (js-sym (nth (first names) 1)) + (list + (js-sym "js-list-slice") + tmp-sym + i + (list (js-sym "len") tmp-sym))) + tail)) (else (cons (list