From 11612a511b1fc681786528bf176285b7172aba6a Mon Sep 17 00:00:00 2001 From: giles Date: Thu, 7 May 2026 19:11:30 +0000 Subject: [PATCH] js-on-sx: js-neg preserves IEEE-754 negative zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JS -0 was returning rational integer 0; the (- 0 x) form loses the sign-of-zero. Switched js-neg to (* -1 (exact->inexact (js-to-number a))), which produces a float and preserves -0.0. Now 1/(-0) === -Infinity and Math.asinh(-0) preserves the sign as required by the spec. built-ins/Math: 41/45 → 42/45. conformance.sh: 148/148. --- lib/js/runtime.sx | 2 +- lib/js/test262-scoreboard.json | 2 +- lib/js/test262-scoreboard.md | 2 +- plans/js-on-sx.md | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 4fd634a3..0fff6486 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -1453,7 +1453,7 @@ (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)))) +(define js-neg (fn (a) (* -1 (exact->inexact (js-to-number a))))) (define js-pos (fn (a) (js-to-number a))) diff --git a/lib/js/test262-scoreboard.json b/lib/js/test262-scoreboard.json index cb45b21f..e52d87a4 100644 --- a/lib/js/test262-scoreboard.json +++ b/lib/js/test262-scoreboard.json @@ -56,6 +56,6 @@ ] ], "pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33", - "elapsed_seconds": 420.7, + "elapsed_seconds": 250.0, "workers": 1 } \ No newline at end of file diff --git a/lib/js/test262-scoreboard.md b/lib/js/test262-scoreboard.md index 0a5320c1..d9417b28 100644 --- a/lib/js/test262-scoreboard.md +++ b/lib/js/test262-scoreboard.md @@ -1,7 +1,7 @@ # test262 scoreboard Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33` -Wall time: 420.7s +Wall time: 250.0s **Total:** 77/99 runnable passed (77.8%). Raw: pass=77 fail=16 skip=1 timeout=6 total=100. diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 31058771..eef5a9b6 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-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. + - 2026-05-07 — **`js-div` coerces divisor to inexact before dividing.** When both operands are SX rationals (e.g. `(js-div 1 0)` from JS-transpiled `1/0` reaching the harness's `_isSameValue` +0/-0 check), SX integer-rational division throws "rational: division by zero" instead of producing JS `Infinity`. Wrapped the divisor in `(exact->inexact ...)` so it's always a float; integer-by-zero now returns `inf` (positive numerator), `-inf` (negative), `nan` (zero numerator), matching JS semantics. Was hitting harness assertion failures even when the test value matched expected. built-ins/Number: 37/50 → 41/50. built-ins/String: 77/99. conformance.sh: 148/148. - 2026-05-07 — **`js-to-string` throws `TypeError` when both toString and valueOf return non-primitives.** Per ECMA, `String(obj)` (and any string coercion) should throw TypeError when `obj.toString()` and `obj.valueOf()` both return objects. Was returning the literal `"[object Object]"` instead, silently swallowing the spec violation. Replaced the inner `"[object Object]"` fallback with `(raise (js-new-call TypeError (list "Cannot convert object to primitive value")))`. Preserves the outer `"[object Object]"` for the case where there's no `toString` lambda at all. Fixes `S8.12.8_A1`. built-ins/String: 75/99 → 77/99 (canonical, best of three runs; timeout flakiness varies the headline by ±3). conformance.sh: 148/148.