js-on-sx: spread ... in array literals and call args

Parser: jp-array-loop and jp-call-args-loop detect punct "..."
and emit (js-spread inner).

Transpile: when any element is spread, build array/args via
js-array-spread-build with (list "js-value" v) and (list
"js-spread" xs) tags.

Runtime: js-array-spread-build walks items, appending values or
splicing spreads via js-iterable-to-list (handles list/string/dict).

Works in arrays, call args, variadic fns (Math.max(...arr)),
and string spread ([...'abc']).

414/416 unit (+5), 148/148 slice unchanged.
This commit is contained in:
2026-04-23 22:10:15 +00:00
parent b502b8f58e
commit 4800246b23
5 changed files with 137 additions and 24 deletions

View File

@@ -254,15 +254,15 @@
(fn
(callee args)
(cond
((and (list? callee) (js-tag? callee "js-member"))
((and (js-tag? callee "js-member") (not (js-has-spread? args)))
(let
((recv (js-transpile (nth callee 1))) (key (nth callee 2)))
(list
(js-sym "js-invoke-method")
recv
key
(cons (js-sym "list") (map js-transpile args)))))
((and (list? callee) (js-tag? callee "js-index"))
(js-transpile-args args))))
((and (js-tag? callee "js-index") (not (js-has-spread? args)))
(let
((recv (js-transpile (nth callee 1)))
(key (js-transpile (nth callee 2))))
@@ -270,12 +270,29 @@
(js-sym "js-invoke-method-dyn")
recv
key
(cons (js-sym "list") (map js-transpile args)))))
(js-transpile-args args))))
((js-tag? callee "js-member")
(let
((recv (js-transpile (nth callee 1))) (key (nth callee 2)))
(list
(js-sym "js-invoke-method")
recv
key
(js-transpile-args args))))
((js-tag? callee "js-index")
(let
((recv (js-transpile (nth callee 1)))
(key (js-transpile (nth callee 2))))
(list
(js-sym "js-invoke-method-dyn")
recv
key
(js-transpile-args args))))
(else
(list
(js-sym "js-call-plain")
(js-transpile callee)
(cons (js-sym "list") (map js-transpile args)))))))
(js-transpile-args args))))))
;; ── Array literal ─────────────────────────────────────────────────
@@ -295,10 +312,58 @@
;; order and allows computed values.
(define
js-transpile-array
(fn (elts) (cons (js-sym "list") (map js-transpile elts))))
(fn
(elts)
(if
(js-has-spread? elts)
(cons
(js-sym "js-array-spread-build")
(map
(fn
(e)
(if
(js-tag? e "js-spread")
(list (js-sym "list") "js-spread" (js-transpile (nth e 1)))
(list (js-sym "list") "js-value" (js-transpile e))))
elts))
(cons (js-sym "list") (map js-transpile elts)))))
;; ── Conditional ───────────────────────────────────────────────────
(define
js-has-spread?
(fn
(lst)
(cond
((empty? lst) false)
((js-tag? (first lst) "js-spread") true)
(else (js-has-spread? (rest lst))))))
;; ── Arrow function ────────────────────────────────────────────────
(define
js-transpile-args
(fn
(args)
(if
(js-has-spread? args)
(cons
(js-sym "js-array-spread-build")
(map
(fn
(e)
(if
(js-tag? e "js-spread")
(list (js-sym "list") "js-spread" (js-transpile (nth e 1)))
(list (js-sym "list") "js-value" (js-transpile e))))
args))
(cons (js-sym "list") (map js-transpile args)))))
;; ── Assignment ────────────────────────────────────────────────────
;; `a = b` on an ident → (set! a b).
;; `a += b` on an ident → (set! a (js-add a b)).
;; `obj.k = v` / `obj[k] = v` → (js-set-prop obj "k" v).
(define
js-transpile-object
(fn
@@ -320,8 +385,6 @@
entries)
(list (js-sym "_obj")))))))
;; ── Arrow function ────────────────────────────────────────────────
(define
js-transpile-cond
(fn
@@ -332,11 +395,6 @@
(js-transpile t)
(js-transpile f))))
;; ── Assignment ────────────────────────────────────────────────────
;; `a = b` on an ident → (set! a b).
;; `a += b` on an ident → (set! a (js-add a b)).
;; `obj.k = v` / `obj[k] = v` → (js-set-prop obj "k" v).
(define
js-transpile-arrow
(fn
@@ -367,6 +425,9 @@
(append inits (list (js-transpile body))))))))
(list (js-sym "fn") param-syms body-tr))))
;; ── End-to-end entry points ───────────────────────────────────────
;; Transpile + eval a single JS expression string.
(define
js-transpile-tpl
(fn
@@ -378,6 +439,8 @@
(else
(cons (js-sym "js-template-concat") (js-transpile-tpl-parts parts))))))
;; Transpile a JS expression string to SX source text (for inspection
;; in tests). Useful for asserting the exact emitted tree.
(define
js-transpile-tpl-parts
(fn
@@ -389,9 +452,6 @@
(js-transpile (first parts))
(js-transpile-tpl-parts (rest parts))))))
;; ── End-to-end entry points ───────────────────────────────────────
;; Transpile + eval a single JS expression string.
(define
js-transpile-assign
(fn
@@ -429,8 +489,6 @@
(js-transpile rhs))))
(else (error "js-transpile-assign: unsupported target")))))
;; Transpile a JS expression string to SX source text (for inspection
;; in tests). Useful for asserting the exact emitted tree.
(define
js-compound-update
(fn