js-on-sx: wrapper constructor-detection, Array.prototype.toString, >>> operator
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 11s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 11s
Number.__callable__ and String.__callable__ now check this.__proto__ === Number/String.prototype before writing wrapper slots, preventing false-positive mutation when called as plain function. js-to-number extended to unwrap wrapper dicts and call valueOf/toString for plain objects. Array.prototype.toString replaced with a direct js-list-join implementation (eliminates infinite recursion via js-invoke-method on dict-based arrays). >>> added to transpiler + runtime. String test262 subset: 62→66/100. 529/530 unit, 147/148 slice. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -904,6 +904,36 @@
|
||||
((= v false) 0)
|
||||
((= (type-of v) "number") v)
|
||||
((= (type-of v) "string") (js-string-to-number v))
|
||||
((= (type-of v) "dict")
|
||||
(cond
|
||||
((contains? (keys v) "__js_number_value__")
|
||||
(get v "__js_number_value__"))
|
||||
((contains? (keys v) "__js_boolean_value__")
|
||||
(if (get v "__js_boolean_value__") 1 0))
|
||||
((contains? (keys v) "__js_string_value__")
|
||||
(js-string-to-number (get v "__js_string_value__")))
|
||||
(else
|
||||
(let
|
||||
((valueof-fn (js-get-prop v "valueOf")))
|
||||
(if
|
||||
(= (type-of valueof-fn) "lambda")
|
||||
(let
|
||||
((result (js-call-with-this v valueof-fn ())))
|
||||
(if
|
||||
(not (= (type-of result) "dict"))
|
||||
(js-to-number result)
|
||||
(let
|
||||
((tostr-fn (js-get-prop v "toString")))
|
||||
(if
|
||||
(= (type-of tostr-fn) "lambda")
|
||||
(let
|
||||
((result2 (js-call-with-this v tostr-fn ())))
|
||||
(if
|
||||
(not (= (type-of result2) "dict"))
|
||||
(js-to-number result2)
|
||||
(js-nan-value)))
|
||||
(js-nan-value)))))
|
||||
(js-nan-value))))))
|
||||
(else 0))))
|
||||
|
||||
(define
|
||||
@@ -1172,10 +1202,35 @@
|
||||
(else
|
||||
(if
|
||||
(= (type-of v) "dict")
|
||||
(if
|
||||
(contains? (keys v) "__js_string_value__")
|
||||
(get v "__js_string_value__")
|
||||
"[object Object]")
|
||||
(cond
|
||||
((contains? (keys v) "__js_string_value__")
|
||||
(get v "__js_string_value__"))
|
||||
((contains? (keys v) "__js_number_value__")
|
||||
(js-number-to-string (get v "__js_number_value__")))
|
||||
((contains? (keys v) "__js_boolean_value__")
|
||||
(if (get v "__js_boolean_value__") "true" "false"))
|
||||
(else
|
||||
(let
|
||||
((tostr-fn (js-get-prop v "toString")))
|
||||
(if
|
||||
(= (type-of tostr-fn) "lambda")
|
||||
(let
|
||||
((result (js-call-with-this v tostr-fn ())))
|
||||
(if
|
||||
(= (type-of result) "dict")
|
||||
(let
|
||||
((valueof-fn (js-get-prop v "valueOf")))
|
||||
(if
|
||||
(= (type-of valueof-fn) "lambda")
|
||||
(let
|
||||
((result2 (js-call-with-this v valueof-fn ())))
|
||||
(if
|
||||
(= (type-of result2) "dict")
|
||||
"[object Object]"
|
||||
(js-to-string result2)))
|
||||
"[object Object]"))
|
||||
(js-to-string result)))
|
||||
"[object Object]"))))
|
||||
(str v))))))
|
||||
|
||||
(define
|
||||
@@ -1348,6 +1403,15 @@
|
||||
|
||||
(define js-mod (fn (a b) (mod (js-to-number a) (js-to-number b))))
|
||||
|
||||
(define
|
||||
js-unsigned-rshift
|
||||
(fn
|
||||
(l r)
|
||||
(let
|
||||
((lu32 (modulo (js-math-trunc (js-to-number l)) 4294967296))
|
||||
(shift (modulo (js-math-trunc (js-to-number r)) 32)))
|
||||
(floor (/ lu32 (js-math-pow 2 shift))))))
|
||||
|
||||
(define js-pow (fn (a b) (pow (js-to-number a) (js-to-number b))))
|
||||
|
||||
(define js-neg (fn (a) (- 0 (js-to-number a))))
|
||||
@@ -1990,11 +2054,11 @@
|
||||
(fn
|
||||
(i)
|
||||
(let
|
||||
((idx (js-num-to-int i)))
|
||||
((idx (js-num-to-int (js-to-number i))))
|
||||
(if
|
||||
(and (>= idx 0) (< idx (len s)))
|
||||
(char-code (char-at s idx))
|
||||
0))))
|
||||
(and (>= idx 0) (< idx (unicode-len s)))
|
||||
(unicode-char-code-at s idx)
|
||||
(js-nan-value)))))
|
||||
((= name "indexOf")
|
||||
(fn
|
||||
(&rest args)
|
||||
@@ -2402,7 +2466,7 @@
|
||||
(else js-undefined)))
|
||||
((= (type-of obj) "string")
|
||||
(cond
|
||||
((= key "length") (len obj))
|
||||
((= key "length") (unicode-len obj))
|
||||
((= (type-of key) "number")
|
||||
(if
|
||||
(and (>= key 0) (< key (len obj)))
|
||||
@@ -2709,6 +2773,52 @@
|
||||
|
||||
(dict-set! (get Number "prototype") "constructor" Number)
|
||||
|
||||
(dict-set!
|
||||
Number
|
||||
"__callable__"
|
||||
(fn
|
||||
(&rest args)
|
||||
(let
|
||||
((raw (if (= (len args) 0) 0 (js-to-number (nth args 0)))))
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(if
|
||||
(and
|
||||
(dict? this-val)
|
||||
(contains? (keys this-val) "__proto__")
|
||||
(= (get this-val "__proto__") (get Number "prototype")))
|
||||
(begin (dict-set! this-val "__js_number_value__" raw) this-val)
|
||||
raw)))))
|
||||
|
||||
(dict-set!
|
||||
(get Number "prototype")
|
||||
"valueOf"
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(if
|
||||
(and
|
||||
(dict? this-val)
|
||||
(contains? (keys this-val) "__js_number_value__"))
|
||||
(get this-val "__js_number_value__")
|
||||
this-val))))
|
||||
|
||||
(dict-set!
|
||||
(get Number "prototype")
|
||||
"toString"
|
||||
(fn
|
||||
(&rest args)
|
||||
(let
|
||||
((this-raw (js-this)))
|
||||
(let
|
||||
((this-val (if (and (dict? this-raw) (contains? (keys this-raw) "__js_number_value__")) (get this-raw "__js_number_value__") this-raw)))
|
||||
(let
|
||||
((radix (if (empty? args) 10 (js-to-number (nth args 0)))))
|
||||
(js-num-to-str-radix
|
||||
this-val
|
||||
(if (or (= radix nil) (js-undefined? radix)) 10 radix)))))))
|
||||
|
||||
(define isFinite js-global-is-finite)
|
||||
|
||||
(define isNaN js-global-is-nan)
|
||||
@@ -3167,6 +3277,17 @@
|
||||
|
||||
(dict-set! Array "name" "Array")
|
||||
|
||||
(dict-set!
|
||||
(get Array "prototype")
|
||||
"toString"
|
||||
(fn
|
||||
(&rest args)
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(let
|
||||
((items (cond ((list? this-val) this-val) ((and (dict? this-val) (contains? (keys this-val) "length")) (js-arraylike-to-list this-val)) (else (list)))))
|
||||
(js-list-join items ",")))))
|
||||
|
||||
(define
|
||||
js-string-from-char-code
|
||||
(fn (&rest args) (js-string-from-char-code-loop args 0 "")))
|
||||
@@ -3207,10 +3328,14 @@
|
||||
(if
|
||||
(>= i (len args))
|
||||
acc
|
||||
(js-string-from-char-code-loop
|
||||
args
|
||||
(+ i 1)
|
||||
(str acc (js-code-to-char (js-num-to-int (nth args i))))))))
|
||||
(let
|
||||
((n (js-to-number (nth args i))))
|
||||
(let
|
||||
((code (if (js-global-is-nan n) 0 (modulo (js-math-trunc n) 65536))))
|
||||
(js-string-from-char-code-loop
|
||||
args
|
||||
(+ i 1)
|
||||
(str acc (char-from-code code))))))))
|
||||
|
||||
(define
|
||||
js-string-proto-fn
|
||||
@@ -3220,7 +3345,9 @@
|
||||
(&rest args)
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(js-invoke-method (js-to-string this-val) name args)))))
|
||||
(let
|
||||
((s (cond ((= (type-of this-val) "string") this-val) ((and (= (type-of this-val) "dict") (contains? (keys this-val) "__js_string_value__")) (get this-val "__js_string_value__")) (else "[object Object]"))))
|
||||
(js-invoke-method s name args))))))
|
||||
|
||||
(define String {:fromCharCode js-string-from-char-code :__callable__ (fn (&rest args) (if (= (len args) 0) "" (js-to-string (nth args 0)))) :prototype {:toLowerCase (js-string-proto-fn "toLowerCase") :concat (js-string-proto-fn "concat") :startsWith (js-string-proto-fn "startsWith") :padEnd (js-string-proto-fn "padEnd") :codePointAt (js-string-proto-fn "codePointAt") :lastIndexOf (js-string-proto-fn "lastIndexOf") :indexOf (js-string-proto-fn "indexOf") :localeCompare (js-string-proto-fn "localeCompare") :split (js-string-proto-fn "split") :endsWith (js-string-proto-fn "endsWith") :trim (js-string-proto-fn "trim") :valueOf (js-string-proto-fn "valueOf") :at (js-string-proto-fn "at") :normalize (js-string-proto-fn "normalize") :substring (js-string-proto-fn "substring") :replaceAll (js-string-proto-fn "replaceAll") :repeat (js-string-proto-fn "repeat") :padStart (js-string-proto-fn "padStart") :search (js-string-proto-fn "search") :toUpperCase (js-string-proto-fn "toUpperCase") :trimEnd (js-string-proto-fn "trimEnd") :toString (js-string-proto-fn "toString") :toLocaleLowerCase (js-string-proto-fn "toLocaleLowerCase") :charCodeAt (js-string-proto-fn "charCodeAt") :slice (js-string-proto-fn "slice") :charAt (js-string-proto-fn "charAt") :match (js-string-proto-fn "match") :includes (js-string-proto-fn "includes") :trimStart (js-string-proto-fn "trimStart") :toLocaleUpperCase (js-string-proto-fn "toLocaleUpperCase") :replace (js-string-proto-fn "replace")} :raw (fn (&rest args) (if (empty? args) "" (js-to-string (nth args 0))))})
|
||||
|
||||
@@ -3232,6 +3359,8 @@
|
||||
|
||||
(dict-set! String "fromCodePoint" js-string-from-code-point)
|
||||
|
||||
(dict-set! String "fromCharCode" js-string-from-char-code)
|
||||
|
||||
(dict-set!
|
||||
String
|
||||
"__callable__"
|
||||
@@ -3242,7 +3371,10 @@
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(if
|
||||
(dict? this-val)
|
||||
(and
|
||||
(dict? this-val)
|
||||
(contains? (keys this-val) "__proto__")
|
||||
(= (get this-val "__proto__") (get String "prototype")))
|
||||
(begin
|
||||
(dict-set! this-val "__js_string_value__" raw)
|
||||
(dict-set! this-val "length" (len raw))
|
||||
@@ -3260,6 +3392,50 @@
|
||||
|
||||
(dict-set! Boolean "name" "Boolean")
|
||||
|
||||
(dict-set! Boolean "prototype" {:constructor Boolean})
|
||||
|
||||
(dict-set!
|
||||
Boolean
|
||||
"__callable__"
|
||||
(fn
|
||||
(&rest args)
|
||||
(let
|
||||
((val (if (> (len args) 0) (js-to-boolean (nth args 0)) false)))
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(if
|
||||
(dict? this-val)
|
||||
(begin
|
||||
(dict-set! this-val "__js_boolean_value__" val)
|
||||
(dict-set! this-val "__proto__" (get Boolean "prototype"))
|
||||
this-val)
|
||||
(if val true false))))))
|
||||
|
||||
(dict-set!
|
||||
(get Boolean "prototype")
|
||||
"valueOf"
|
||||
(fn
|
||||
(&rest args)
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(if
|
||||
(and
|
||||
(= (type-of this-val) "dict")
|
||||
(contains? (keys this-val) "__js_boolean_value__"))
|
||||
(get this-val "__js_boolean_value__")
|
||||
this-val))))
|
||||
|
||||
(dict-set!
|
||||
(get Boolean "prototype")
|
||||
"toString"
|
||||
(fn
|
||||
(&rest args)
|
||||
(let
|
||||
((this-val (js-this)))
|
||||
(let
|
||||
((b (if (and (= (type-of this-val) "dict") (contains? (keys this-val) "__js_boolean_value__")) (get this-val "__js_boolean_value__") this-val)))
|
||||
(if b "true" "false")))))
|
||||
|
||||
(define
|
||||
parseInt
|
||||
(fn
|
||||
|
||||
Reference in New Issue
Block a user