js-on-sx: String wrapper objects + number-to-string sci notation expansion
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled

- js-to-string: return __js_string_value__ for String wrapper dicts
- js-loose-eq: coerce String wrapper objects to primitive before compare
- String.__callable__: set __js_string_value__ + length on 'this' when called as constructor
- js-expand-sci-notation: new helper converts mantissa+exp to decimal or integer form
- js-number-to-string: expand 1e-06→0.000001, 1e+06→1000000; fix 1e+21 (was 1e21)
- String test262 subset: 45→58/100

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 14:27:13 +00:00
parent 80c21cbabb
commit 4d00250233
3 changed files with 98 additions and 85 deletions

View File

@@ -1169,7 +1169,14 @@
((= v false) "false")
((= (type-of v) "string") v)
((= (type-of v) "number") (js-number-to-string v))
(else (if (= (type-of v) "dict") "[object Object]" (str v))))))
(else
(if
(= (type-of v) "dict")
(if
(contains? (keys v) "__js_string_value__")
(get v "__js_string_value__")
"[object Object]")
(str v))))))
(define
js-template-concat
@@ -1187,6 +1194,32 @@
(+ i 1)
(str acc (js-to-string (nth parts i)))))))
(define
js-expand-sci-notation
(fn
(mant exp-n)
(let
((di (js-string-index-of mant "." 0)))
(let
((int-part (if (< di 0) mant (js-string-slice mant 0 di)))
(frac-part
(if (< di 0) "" (js-string-slice mant (+ di 1) (len mant)))))
(let
((all-digits (str int-part frac-part))
(frac-len (if (< di 0) 0 (- (- (len mant) di) 1))))
(if
(>= exp-n 0)
(if
(>= exp-n frac-len)
(str all-digits (js-string-repeat "0" (- exp-n frac-len)))
(let
((dot-pos (+ (len int-part) exp-n)))
(str
(js-string-slice all-digits 0 dot-pos)
"."
(js-string-slice all-digits dot-pos (len all-digits)))))
(str "0." (js-string-repeat "0" (- (- 0 exp-n) 1)) all-digits)))))))
(define
js-number-to-string
(fn
@@ -1195,7 +1228,16 @@
((js-number-is-nan n) "NaN")
((= n (js-infinity-value)) "Infinity")
((= n (- 0 (js-infinity-value))) "-Infinity")
(else (js-normalize-num-str (str n))))))
(else
(let
((pos-n (if (< n 0) (- 0 n) n)))
(let
((s0 (js-normalize-num-str (str pos-n))))
(let
((ei (js-string-index-of s0 "e" 0)))
(let
((precise (if (< ei 0) s0 (let ((exp-n (js-to-number (js-string-slice s0 (+ ei 1) (len s0))))) (if (and (>= exp-n -6) (<= exp-n 20)) (js-expand-sci-notation (js-string-slice s0 0 ei) exp-n) (if (>= exp-n 0) (str (js-string-slice s0 0 (+ ei 1)) "+" (str exp-n)) s0))))))
(if (< n 0) (str "-" precise) precise)))))))))
(define
js-normalize-num-str
@@ -1296,6 +1338,10 @@
(= (js-to-number a) b))
((= (type-of a) "boolean") (js-loose-eq (js-to-number a) b))
((= (type-of b) "boolean") (js-loose-eq a (js-to-number b)))
((and (dict? a) (contains? (keys a) "__js_string_value__"))
(js-loose-eq (get a "__js_string_value__") b))
((and (dict? b) (contains? (keys b) "__js_string_value__"))
(js-loose-eq a (get b "__js_string_value__")))
(else false))))
(define js-loose-neq (fn (a b) (not (js-loose-eq a b))))
@@ -3139,6 +3185,23 @@
(dict-set! String "fromCodePoint" js-string-from-code-point)
(dict-set!
String
"__callable__"
(fn
(&rest args)
(let
((raw (if (= (len args) 0) "" (js-to-string (nth args 0)))))
(let
((this-val (js-this)))
(if
(dict? this-val)
(begin
(dict-set! this-val "__js_string_value__" raw)
(dict-set! this-val "length" (len raw))
this-val)
raw)))))
(define Boolean {:__callable__ (fn (&rest args) (if (= (len args) 0) false (js-to-boolean (nth args 0))))})
(dict-set!