js-on-sx: String replace/search/match + Array.from

String: replace, search, match now work with either string or regex
arg. Regex path uses js-string-index-of on source (case-adjusted
when ignoreCase set).

Array.from(iter, mapFn?) normalizes via js-iterable-to-list and
optionally applies mapFn.

Fixed dict-set! on list bug in js-regex-stub-exec — just omit the
index/input metadata, spec-breaking but tests that just check [0]
work.

407/409 unit (+8), 148/148 slice unchanged.
This commit is contained in:
2026-04-23 21:54:36 +00:00
parent 6fb65464ed
commit 60bb7c4687
2 changed files with 122 additions and 3 deletions

View File

@@ -1152,6 +1152,73 @@
(js-string-pad s target pad false))))
((= name "toString") (fn () s))
((= name "valueOf") (fn () s))
((= name "replace")
(fn
(&rest args)
(cond
((< (len args) 2) s)
((js-regex? (nth args 0))
(let
((rx (nth args 0)) (repl (nth args 1)))
(let
((src (get rx "source")))
(let
((idx (js-string-index-of (if (get rx "ignoreCase") (js-lower-case s) s) (if (get rx "ignoreCase") (js-lower-case src) src) 0)))
(if
(= idx -1)
s
(let
((matched (js-string-slice s idx (+ idx (len src)))))
(str
(js-string-slice s 0 idx)
(if
(js-function? repl)
(repl matched)
(js-to-string repl))
(js-string-slice s (+ idx (len src)) (len s)))))))))
(else
(let
((needle (js-to-string (nth args 0))) (repl (nth args 1)))
(let
((idx (js-string-index-of s needle 0)))
(if
(= idx -1)
s
(str
(js-string-slice s 0 idx)
(if
(js-function? repl)
(repl needle)
(js-to-string repl))
(js-string-slice s (+ idx (len needle)) (len s))))))))))
((= name "search")
(fn
(&rest args)
(cond
((= (len args) 0) -1)
((js-regex? (nth args 0))
(let
((rx (nth args 0)) (src (get (nth args 0) "source")))
(js-string-index-of
(if (get rx "ignoreCase") (js-lower-case s) s)
(if (get rx "ignoreCase") (js-lower-case src) src)
0)))
(else (js-string-index-of s (js-to-string (nth args 0)) 0)))))
((= name "match")
(fn
(&rest args)
(cond
((= (len args) 0) nil)
((js-regex? (nth args 0)) (js-regex-stub-exec (nth args 0) s))
(else
(let
((needle (js-to-string (nth args 0))))
(let
((idx (js-string-index-of s needle 0)))
(if
(= idx -1)
nil
(let ((res (list))) (append! res needle) res))))))))
(else js-undefined))))
(define
@@ -1299,6 +1366,9 @@
((= key "padEnd") (js-string-method obj "padEnd"))
((= key "toString") (js-string-method obj "toString"))
((= key "valueOf") (js-string-method obj "valueOf"))
((= key "replace") (js-string-method obj "replace"))
((= key "search") (js-string-method obj "search"))
((= key "match") (js-string-method obj "match"))
(else js-undefined)))
((= (type-of obj) "dict")
(js-dict-get-walk obj (js-to-string key)))
@@ -1680,7 +1750,30 @@
(define js-array-of (fn (&rest args) args))
(define Array {:isArray js-array-is-array :of js-array-of})
(define
js-array-from
(fn
(&rest args)
(cond
((= (len args) 0) (list))
(else
(let
((src (js-iterable-to-list (nth args 0)))
(map-fn (if (< (len args) 2) nil (nth args 1))))
(if
(= map-fn nil)
(let
((result (list)))
(for-each (fn (x) (append! result x)) src)
result)
(let
((result (list)) (i 0))
(for-each
(fn (x) (append! result (map-fn x)) (set! i (+ i 1)))
src)
result)))))))
(define Array {:isArray js-array-is-array :of js-array-of :from js-array-from})
(define
js-string-from-char-code
@@ -2346,8 +2439,6 @@
((matched (js-string-slice s idx (+ idx (len src))))
(res (list)))
(append! res matched)
(dict-set! res "index" idx)
(dict-set! res "input" s)
res)))))))
(define