From 9b07f97341b3d652f0d165325d61905e22a17a6f Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 02:52:11 +0000 Subject: [PATCH] js-on-sx: js-new-call honours function-typed constructor returns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit new Object(func) should return func itself (per ES spec - "if value is a native ECMAScript object, return it"), but js-new-call only kept the ctor's return when it was dict or list — functions fell through to the empty wrapper. Added (js-function? ret) to the accept set. built-ins/Object: 42/50 → 44/50. conformance.sh: 148/148. --- lib/js/runtime.sx | 2 +- lib/js/test262-scoreboard.json | 54 ++++++++++++---------------------- lib/js/test262-scoreboard.md | 20 +++++-------- plans/js-on-sx.md | 2 ++ 4 files changed, 30 insertions(+), 48 deletions(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index f42690ce..65f8ab6e 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -648,7 +648,7 @@ (if (and (not (js-undefined? ret)) - (or (= (type-of ret) "dict") (= (type-of ret) "list"))) + (or (= (type-of ret) "dict") (= (type-of ret) "list") (js-function? ret))) ret obj)))))) diff --git a/lib/js/test262-scoreboard.json b/lib/js/test262-scoreboard.json index 09db5212..4d985772 100644 --- a/lib/js/test262-scoreboard.json +++ b/lib/js/test262-scoreboard.json @@ -1,61 +1,45 @@ { "totals": { - "pass": 78, - "fail": 15, - "skip": 1, - "timeout": 6, - "total": 100, - "runnable": 99, - "pass_rate": 78.8 + "pass": 44, + "fail": 6, + "skip": 0, + "timeout": 0, + "total": 50, + "runnable": 50, + "pass_rate": 88.0 }, "categories": [ { - "category": "built-ins/String", - "total": 100, - "pass": 78, - "fail": 15, - "skip": 1, - "timeout": 6, - "pass_rate": 78.8, + "category": "built-ins/Object", + "total": 50, + "pass": 44, + "fail": 6, + "skip": 0, + "timeout": 0, + "pass_rate": 88.0, "top_failures": [ - [ - "Test262Error (assertion failed)", - 13 - ], - [ - "Timeout", - 6 - ], [ "ReferenceError (undefined symbol)", - 1 + 4 ], [ "SyntaxError (parse/unsupported syntax)", - 1 + 2 ] ] } ], "top_failure_modes": [ - [ - "Test262Error (assertion failed)", - 13 - ], - [ - "Timeout", - 6 - ], [ "ReferenceError (undefined symbol)", - 1 + 4 ], [ "SyntaxError (parse/unsupported syntax)", - 1 + 2 ] ], "pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33", - "elapsed_seconds": 224.9, + "elapsed_seconds": 42.1, "workers": 1 } \ No newline at end of file diff --git a/lib/js/test262-scoreboard.md b/lib/js/test262-scoreboard.md index 0611ce69..5da4c0fb 100644 --- a/lib/js/test262-scoreboard.md +++ b/lib/js/test262-scoreboard.md @@ -1,28 +1,24 @@ # test262 scoreboard Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33` -Wall time: 224.9s +Wall time: 42.1s -**Total:** 78/99 runnable passed (78.8%). Raw: pass=78 fail=15 skip=1 timeout=6 total=100. +**Total:** 44/50 runnable passed (88.0%). Raw: pass=44 fail=6 skip=0 timeout=0 total=50. ## Top failure modes -- **13x** Test262Error (assertion failed) -- **6x** Timeout -- **1x** ReferenceError (undefined symbol) -- **1x** SyntaxError (parse/unsupported syntax) +- **4x** ReferenceError (undefined symbol) +- **2x** SyntaxError (parse/unsupported syntax) ## Categories (worst pass-rate first, min 10 runnable) | Category | Pass | Fail | Skip | Timeout | Total | Pass % | |---|---:|---:|---:|---:|---:|---:| -| built-ins/String | 78 | 15 | 1 | 6 | 100 | 78.8% | +| built-ins/Object | 44 | 6 | 0 | 0 | 50 | 88.0% | ## Per-category top failures (min 10 runnable, worst first) -### built-ins/String (78/99 — 78.8%) +### built-ins/Object (44/50 — 88.0%) -- **13x** Test262Error (assertion failed) -- **6x** Timeout -- **1x** ReferenceError (undefined symbol) -- **1x** SyntaxError (parse/unsupported syntax) +- **4x** ReferenceError (undefined symbol) +- **2x** SyntaxError (parse/unsupported syntax) diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 9f66b7a7..7e0258ff 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-08 — **`js-new-call` honours function-typed constructor returns (not just dict/list).** `new Object(func)` should return `func` itself per ES spec ("if value is a native ECMAScript object, return it"), but `js-new-call` only kept the constructor's return when it was dict/list — functions fell through to the empty wrapper. Added `(js-function? ret)` to the accept set. Now `new Object(fn) === fn` and `new Object(fn)()` invokes `fn`. built-ins/Object: 42/50 → 44/50. conformance.sh: 148/148. + - 2026-05-08 — **`var` declarations hoist out of nested blocks; nested `var` becomes `set!`.** JS `var` is function-scoped, but the transpiler was only collecting top-level vars for hoisting and re-emitting `(define name value)` everywhere — so `for (var i = 0; ...) { var r = i; } r` saw `r` as undefined because the inner `(define r ...)` shadowed the (un-hoisted) outer scope. Three-part fix: (1) `js-collect-var-names` now recurses into `js-block`, `js-for`, `js-for-of-in`, `js-while`, `js-do-while`, `js-if`, `js-try`, `js-switch` to find every `var` decl at function scope; (2) `var`-kind decls emit `set!` (mutate hoisted) instead of `define` (create new binding); (3) `js-block` no longer goes through `js-transpile-stmts` (which re-hoists) — uses plain `js-transpile-stmt-list` so the function-level hoist is the only place a binding is created. built-ins/Array: 17/45 → 18/45, String: 77/99 → 78/99. conformance.sh: 148/148. - 2026-05-08 — **`arr.length = N` extends the array (no-op for shrink).** `js-list-set!` was a no-op for the `length` key. Added a clause that pads with `js-undefined` via `js-pad-list!` when N > current length. Skipped truncation for now: the `pop-last!` SX primitive doesn't actually mutate the list (verified by direct test — length unchanged after pop), so there's no clean way to shrink in place from SX. Extension covers the common test262 cases (`var x = []; x.length = 5`). built-ins/Array: 16/45 → 17/45. conformance.sh: 148/148.