js-on-sx: String fixes — fromCodePoint, multi-arg indexOf/split/lastIndexOf, matchAll, constructor, js-to-string dict
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled

- String.fromCodePoint added (BMP + surrogate pairs)
- indexOf/lastIndexOf/split now accept optional second argument (fromIndex / limit)
- matchAll stub added to js-string-method and String.prototype
- String property else-branch now falls back to String.prototype (fixes 'a'.constructor === String)
- js-to-string for dict returns [object Object] instead of recursing into circular String.prototype.constructor structure
- js-list-take helper added for split limit

Scoreboard: String 42→43, timeouts 32→13, total 162→202/300 (54%→67.3%). 529/530 unit, 148/148 slice.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 13:41:58 +00:00
parent 70f91ef3d8
commit 80c21cbabb
4 changed files with 144 additions and 71 deletions

View File

@@ -1169,7 +1169,7 @@
((= v false) "false")
((= (type-of v) "string") v)
((= (type-of v) "number") (js-number-to-string v))
(else (str v)))))
(else (if (= (type-of v) "dict") "[object Object]" (str v))))))
(define
js-template-concat
@@ -1903,7 +1903,15 @@
(char-code (char-at s idx))
0))))
((= name "indexOf")
(fn (needle) (js-string-index-of s (js-to-string needle) 0)))
(fn
(&rest args)
(if
(empty? args)
-1
(js-string-index-of
s
(js-to-string (nth args 0))
(if (< (len args) 2) 0 (max 0 (js-num-to-int (nth args 1))))))))
((= name "slice")
(fn
(&rest args)
@@ -1927,7 +1935,16 @@
(js-string-slice s lo (min hi (len s)))))))
((= name "toUpperCase") (fn () (js-upper-case s)))
((= name "toLowerCase") (fn () (js-lower-case s)))
((= name "split") (fn (sep) (js-string-split s (js-to-string sep))))
((= name "split")
(fn
(&rest args)
(let
((sep (if (= (len args) 0) :js-undefined (nth args 0)))
(limit
(if (< (len args) 2) -1 (js-num-to-int (nth args 1)))))
(let
((result (js-string-split s (js-to-string sep))))
(if (< limit 0) result (js-list-take result limit))))))
((= name "concat")
(fn (&rest args) (js-string-concat-loop s args 0)))
((= name "includes")
@@ -2042,6 +2059,17 @@
(= idx -1)
nil
(let ((res (list))) (append! res needle) res))))))))
((= name "matchAll")
(fn
(&rest args)
(if
(empty? args)
(list)
(let
((needle (js-to-string (nth args 0))))
(let
((loop (fn (start acc) (let ((idx (js-string-index-of s needle start))) (if (= idx -1) acc (let ((m (list))) (begin (append! m needle) (dict-set! m "index" idx) (loop (+ idx (max 1 (len needle))) (begin (append! acc m) acc)))))))))
(loop 0 (list)))))))
((= name "at")
(fn
(i)
@@ -2068,7 +2096,14 @@
-1
(let
((needle (js-to-string (nth args 0))))
(js-string-last-index-of s needle (- (len s) (len needle)))))))
(let
((default-start (- (len s) (len needle)))
(from
(if (< (len args) 2) -1 (js-num-to-int (nth args 1)))))
(js-string-last-index-of
s
needle
(if (< from 0) default-start (min from default-start))))))))
((= name "localeCompare")
(fn
(&rest args)
@@ -2166,6 +2201,15 @@
((not (= (char-at s (+ si ni)) (char-at needle ni))) false)
(else (js-string-matches? s needle si (+ ni 1))))))
(define
js-list-take
(fn
(lst n)
(if
(or (<= n 0) (empty? lst))
(list)
(cons (first lst) (js-list-take (rest lst) (- n 1))))))
(define
js-string-split
(fn
@@ -2306,7 +2350,13 @@
(js-string-method obj "toLocaleUpperCase"))
((= key "isWellFormed") (js-string-method obj "isWellFormed"))
((= key "toWellFormed") (js-string-method obj "toWellFormed"))
(else js-undefined)))
(else
(let
((proto (get String "prototype")))
(if
(and (dict? proto) (contains? (keys proto) key))
(get proto key)
js-undefined)))))
((= (type-of obj) "dict")
(js-dict-get-walk obj (js-to-string key)))
((and (= obj Promise) (dict-has? __js_promise_statics__ (js-to-string key)))
@@ -3028,6 +3078,35 @@
js-string-from-char-code
(fn (&rest args) (js-string-from-char-code-loop args 0 "")))
(define
js-string-from-code-point-loop
(fn
(args i acc)
(if
(>= i (len args))
acc
(let
((cp (floor (js-to-number (nth args i)))))
(if
(< cp 65536)
(js-string-from-code-point-loop
args
(+ i 1)
(str acc (js-code-to-char (js-num-to-int cp))))
(let
((hi (+ 55296 (floor (/ (- cp 65536) 1024))))
(lo (+ 56320 (modulo (- cp 65536) 1024))))
(js-string-from-code-point-loop
args
(+ i 1)
(str
(str acc (js-code-to-char (js-num-to-int hi)))
(js-code-to-char (js-num-to-int lo))))))))))
(define
js-string-from-code-point
(fn (&rest args) (js-string-from-code-point-loop args 0 "")))
(define
js-string-from-char-code-loop
(fn
@@ -3058,8 +3137,15 @@
(dict-set! String "name" "String")
(dict-set! String "fromCodePoint" js-string-from-code-point)
(define Boolean {:__callable__ (fn (&rest args) (if (= (len args) 0) false (js-to-boolean (nth args 0))))})
(dict-set!
(get String "prototype")
"matchAll"
(js-string-proto-fn "matchAll"))
(dict-set! Boolean "length" 1)
(dict-set! Boolean "name" "Boolean")