diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 42f9f843..6e170d61 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -1123,23 +1123,28 @@ (if (>= esplit 0) (let - ((mant (js-string-slice trimmed 0 esplit)) - (expstr - (js-string-slice - trimmed - (+ esplit 1) - (len trimmed)))) - (let - ((m (js-parse-decimal mant 0 0 1 false 0)) - (e - (js-parse-decimal - expstr - 0 - 0 - 1 - false - 0))) - (* m (pow 10 e)))) + ((parsed (string->number trimmed))) + (if + (= parsed nil) + (let + ((mant (js-string-slice trimmed 0 esplit)) + (expstr + (js-string-slice + trimmed + (+ esplit 1) + (len trimmed)))) + (let + ((m (js-parse-decimal mant 0 0 1 false 0)) + (e + (js-parse-decimal + expstr + 0 + 0 + 1 + false + 0))) + (* m (pow 10 e)))) + parsed)) (js-parse-decimal trimmed 0 diff --git a/lib/js/test262-scoreboard.json b/lib/js/test262-scoreboard.json index 753f9b70..f4cdbc0c 100644 --- a/lib/js/test262-scoreboard.json +++ b/lib/js/test262-scoreboard.json @@ -56,6 +56,6 @@ ] ], "pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33", - "elapsed_seconds": 273.6, + "elapsed_seconds": 152.5, "workers": 1 } \ No newline at end of file diff --git a/lib/js/test262-scoreboard.md b/lib/js/test262-scoreboard.md index 385613d2..802eeb95 100644 --- a/lib/js/test262-scoreboard.md +++ b/lib/js/test262-scoreboard.md @@ -1,7 +1,7 @@ # test262 scoreboard Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33` -Wall time: 273.6s +Wall time: 152.5s **Total:** 78/99 runnable passed (78.8%). Raw: pass=78 fail=15 skip=1 timeout=6 total=100. diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index cc919152..91cc916b 100644 --- a/plans/js-on-sx.md +++ b/plans/js-on-sx.md @@ -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-07 — **`js-num-from-string` uses SX `string->number` for exponent-form numbers.** Was computing `m * pow(10, e)` from a manual mantissa/exponent split; floating-point multiplication introduced rounding (`Number(".12345e-3") - 0.00012345 == 2.7e-20`). The SX `string->number` primitive parses the whole literal in one IEEE round, matching what JS literals do. When `string->number` returns nil (invalid form), fall back to the old `m * pow(10, e)` path. built-ins/Number: 42/50 → 43/50. conformance.sh: 148/148. + - 2026-05-07 — **Constructors (`Object`/`Array`/`Number`/`String`/`Boolean`) carry `__proto__ = Function.prototype`.** Per spec, the constructors are functions and inherit from `Function.prototype`, so `Function.prototype.foo = 1; Array.foo === 1`. Previously the constructor dicts had no `__proto__`, so they only saw `Object.prototype` via the recent fallback — `Function.prototype` mutations were invisible. Added a `(begin (dict-set! ...))` post-init at the end of `runtime.sx` after the constructors are defined. Combined with the existing Object.prototype fallback, the proto chain now terminates correctly for the constructor → `Function.prototype` → `Object.prototype` walk. built-ins/Number: 41/50 → 42/50, built-ins/String: 75/99 → 78/99, built-ins/Array: 12/45 → 13/45. conformance.sh: 148/148. - 2026-05-07 — **`js-neg` preserves IEEE-754 negative zero.** `-0` was returning `0` (rational integer) because `js-neg` did `(- 0 (js-to-number a))`, which loses sign-of-zero in any arithmetic implementation that follows IEEE 754. Per JS spec, `-0` and `1/-0 === -Infinity` must be observable. Switched to `(* -1 (exact->inexact (js-to-number a)))` so the result is always a float and `-0.0` is preserved. Fixes `Math.asinh(-0)` and other `-0`-sensitive tests; `1/(-0) === -Infinity` now works. built-ins/Math: 41/45 → 42/45. conformance.sh: 148/148.