js-on-sx: Number.prototype methods unwrap Number wrappers, TypeError on non-Number
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
This commit is contained in:
@@ -3718,7 +3718,19 @@
|
||||
|
||||
(define js-global-is-nan (fn (v) (js-number-is-nan (js-to-number v))))
|
||||
|
||||
(define Number {:MIN_SAFE_INTEGER -9007199254740991 :MIN_VALUE 4.94066e-324 :isNaN js-number-is-nan :isSafeInteger js-number-is-safe-integer :NEGATIVE_INFINITY (- 0 (js-infinity-value)) :NaN (js-nan-value) :prototype {:toFixed {:__callable__ (fn (d) (js-number-to-fixed (js-this) (if (= d nil) 0 (js-to-number d)))) :length 1 :name "toFixed"} :toExponential {:__callable__ (fn (&rest args) (js-to-string (js-this))) :length 1 :name "toExponential"} :toLocaleString {:__callable__ (fn () (js-to-string (js-this))) :length 0 :name "toLocaleString"} :toString {:__callable__ (fn (&rest args) (let ((this-val (js-this)) (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)))) :length 1 :name "toString"} :toPrecision {:__callable__ (fn (&rest args) (js-to-string (js-this))) :length 1 :name "toPrecision"} :valueOf {:__callable__ (fn () (js-this)) :length 0 :name "valueOf"}} :isInteger js-number-is-integer :__callable__ js-to-number :MAX_VALUE (js-max-value-approx) :POSITIVE_INFINITY (js-infinity-value) :isFinite js-number-is-finite :MAX_SAFE_INTEGER 9007199254740991 :EPSILON 2.22045e-16})
|
||||
(define
|
||||
js-number-this-val
|
||||
(fn ()
|
||||
(let ((this-val (js-this)))
|
||||
(cond
|
||||
((or (= (type-of this-val) "number") (= (type-of this-val) "rational"))
|
||||
(js-numeric-norm this-val))
|
||||
((and (= (type-of this-val) "dict") (contains? (keys this-val) "__js_number_value__"))
|
||||
(get this-val "__js_number_value__"))
|
||||
(else
|
||||
(raise (js-new-call TypeError (js-args "Number.prototype method requires a Number"))))))))
|
||||
|
||||
(define Number {:MIN_SAFE_INTEGER -9007199254740991 :MIN_VALUE 4.94066e-324 :isNaN js-number-is-nan :isSafeInteger js-number-is-safe-integer :NEGATIVE_INFINITY (- 0 (js-infinity-value)) :NaN (js-nan-value) :prototype {:toFixed {:__callable__ (fn (d) (js-number-to-fixed (js-number-this-val) (if (= d nil) 0 (js-to-number d)))) :length 1 :name "toFixed"} :toExponential {:__callable__ (fn (&rest args) (js-number-to-string (js-number-this-val))) :length 1 :name "toExponential"} :toLocaleString {:__callable__ (fn () (js-number-to-string (js-number-this-val))) :length 0 :name "toLocaleString"} :toString {:__callable__ (fn (&rest args) (let ((this-val (js-number-this-val)) (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)))) :length 1 :name "toString"} :toPrecision {:__callable__ (fn (&rest args) (js-number-to-string (js-number-this-val))) :length 1 :name "toPrecision"} :valueOf {:__callable__ (fn () (js-number-this-val)) :length 0 :name "valueOf"}} :isInteger js-number-is-integer :__callable__ js-to-number :MAX_VALUE (js-max-value-approx) :POSITIVE_INFINITY (js-infinity-value) :isFinite js-number-is-finite :MAX_SAFE_INTEGER 9007199254740991 :EPSILON 2.22045e-16})
|
||||
|
||||
(dict-set! Number "length" 1)
|
||||
|
||||
|
||||
@@ -158,6 +158,8 @@ Each item: implement → tests → update progress. Mark `[x]` when tests green.
|
||||
|
||||
Append-only record of completed iterations. Loop writes one line per iteration: date, what was done, test count delta.
|
||||
|
||||
- 2026-05-09 — **`Number.prototype.toFixed`/`toString`/etc. unwrap Number wrappers and throw TypeError on non-Number receivers.** Was passing `(js-this)` straight through to `js-number-to-fixed`, so calling `Number.prototype.toFixed(1)` directly on `Number.prototype` (a Number wrapper dict) raised `"Expected number, got dict"`. Per spec, these methods must extract the Number primitive value (from primitive or wrapper) and throw TypeError otherwise. Added `js-number-this-val` helper that handles primitive number, rational, `__js_number_value__`-marked wrapper, and raises TypeError for everything else. Routed all six Number.prototype methods through it. Result: built-ins/Number/prototype/toFixed 5/13 → 7/13. Number 26/30 holds. conformance.sh: 148/148.
|
||||
|
||||
- 2026-05-09 — **`Array.prototype` methods carry spec lengths and names.** Continuation of the same fix. `js-array-proto-fn` was returning bare lambdas → `Array.prototype.push.length === 0` instead of `1`. Added `js-array-proto-fn-length` (lookup table for the ~30 method names — `push:1`, `slice:2`, `splice:2`, `concat:1`, `forEach:1`, `every:1`, `flat:0`, etc.) and changed the helper to return the dict-with-`__callable__` form. Now `Array.prototype.push.length === 1`, `Array.prototype.slice.length === 2`. Array 27/50, Array.prototype 8/30, Object 30/30 unchanged. conformance.sh: 148/148.
|
||||
|
||||
- 2026-05-09 — **`Number.prototype` and `String.prototype` methods carry spec lengths and names.** Same shape as the earlier Function.prototype fix. Number.prototype.{toFixed/toExponential/toPrecision/toString/valueOf/toLocaleString} were bare `(fn ...)` lambdas → length 0 → tests assert e.g. `Number.prototype.toExponential.length === 1`. Wrapped each in a dict-with-`__callable__` with `:length` and `:name`. For String.prototype, `js-string-proto-fn` was a single helper applied to ~30 method names; added `js-string-proto-fn-length` (lookup table for spec-defined lengths: `concat:1`, `indexOf:1`, `slice:2`, `substring:2`, `replace:2`, etc.) and changed the helper to return the dict form, so all string methods now report correctly. Result: built-ins/Number/prototype 18/30 → 20/30, String/prototype 18/30 → 21/30. Number 26/30 holds, String 29/30. conformance.sh: 148/148.
|
||||
|
||||
Reference in New Issue
Block a user