From 24a67fae978af041dd36d97ce299c1db843b8358 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 01:38:51 +0000 Subject: [PATCH] js-on-sx: arr.length = N extends the array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit js-list-set! was a no-op for the length key. Added a clause that pads with js-undefined via js-pad-list! when target > current. Truncation skipped: the pop-last! SX primitive doesn't actually mutate the list (length unchanged after the call), so no clean way to shrink in place from SX. Extension covers common cases. built-ins/Array: 16/45 → 17/45. conformance.sh: 148/148. --- lib/js/runtime.sx | 8 ++++- lib/js/test262-scoreboard.json | 58 ++++++++++++++++++++++++---------- lib/js/test262-scoreboard.md | 22 ++++++++----- plans/js-on-sx.md | 2 ++ 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index c27f353a..f42690ce 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -2800,7 +2800,13 @@ (else (do (js-pad-list! lst n i) (append! lst val)))))) ((and (= (type-of key) "string") (js-is-numeric-string? key)) (js-list-set! lst (js-string-to-number key) val)) - ((= key "length") nil) + ((= key "length") + (let + ((target (js-num-to-int (js-to-number val))) (n (len lst))) + (cond + ((< target 0) nil) + ((> target n) (js-pad-list! lst n target)) + (else nil)))) (else nil)))) (define js-pad-list! diff --git a/lib/js/test262-scoreboard.json b/lib/js/test262-scoreboard.json index 4e87dc67..e8d3818c 100644 --- a/lib/js/test262-scoreboard.json +++ b/lib/js/test262-scoreboard.json @@ -1,30 +1,42 @@ { "totals": { - "pass": 43, - "fail": 4, - "skip": 0, - "timeout": 3, + "pass": 17, + "fail": 21, + "skip": 5, + "timeout": 7, "total": 50, - "runnable": 50, - "pass_rate": 86.0 + "runnable": 45, + "pass_rate": 37.8 }, "categories": [ { - "category": "built-ins/Number", + "category": "built-ins/Array", "total": 50, - "pass": 43, - "fail": 4, - "skip": 0, - "timeout": 3, - "pass_rate": 86.0, + "pass": 17, + "fail": 21, + "skip": 5, + "timeout": 7, + "pass_rate": 37.8, "top_failures": [ [ "Test262Error (assertion failed)", - 4 + 16 ], [ "Timeout", - 3 + 7 + ], + [ + "TypeError: not a function", + 2 + ], + [ + "ReferenceError (undefined symbol)", + 2 + ], + [ + "Unhandled: Not callable: {:2 43 :1 42 :0 41 :length 3}\\", + 1 ] ] } @@ -32,14 +44,26 @@ "top_failure_modes": [ [ "Test262Error (assertion failed)", - 4 + 16 ], [ "Timeout", - 3 + 7 + ], + [ + "TypeError: not a function", + 2 + ], + [ + "ReferenceError (undefined symbol)", + 2 + ], + [ + "Unhandled: Not callable: {:2 43 :1 42 :0 41 :length 3}\\", + 1 ] ], "pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33", - "elapsed_seconds": 71.8, + "elapsed_seconds": 151.1, "workers": 1 } \ No newline at end of file diff --git a/lib/js/test262-scoreboard.md b/lib/js/test262-scoreboard.md index a4c45778..328abca4 100644 --- a/lib/js/test262-scoreboard.md +++ b/lib/js/test262-scoreboard.md @@ -1,24 +1,30 @@ # test262 scoreboard Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33` -Wall time: 71.8s +Wall time: 151.1s -**Total:** 43/50 runnable passed (86.0%). Raw: pass=43 fail=4 skip=0 timeout=3 total=50. +**Total:** 17/45 runnable passed (37.8%). Raw: pass=17 fail=21 skip=5 timeout=7 total=50. ## Top failure modes -- **4x** Test262Error (assertion failed) -- **3x** Timeout +- **16x** Test262Error (assertion failed) +- **7x** Timeout +- **2x** TypeError: not a function +- **2x** ReferenceError (undefined symbol) +- **1x** Unhandled: Not callable: {:2 43 :1 42 :0 41 :length 3}\ ## Categories (worst pass-rate first, min 10 runnable) | Category | Pass | Fail | Skip | Timeout | Total | Pass % | |---|---:|---:|---:|---:|---:|---:| -| built-ins/Number | 43 | 4 | 0 | 3 | 50 | 86.0% | +| built-ins/Array | 17 | 21 | 5 | 7 | 50 | 37.8% | ## Per-category top failures (min 10 runnable, worst first) -### built-ins/Number (43/50 — 86.0%) +### built-ins/Array (17/45 — 37.8%) -- **4x** Test262Error (assertion failed) -- **3x** Timeout +- **16x** Test262Error (assertion failed) +- **7x** Timeout +- **2x** TypeError: not a function +- **2x** ReferenceError (undefined symbol) +- **1x** Unhandled: Not callable: {:2 43 :1 42 :0 41 :length 3}\ diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index f740a0ea..c51d3b5b 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 — **`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. + - 2026-05-08 — **Arrays inherit unknown properties from `Array.prototype` (and onwards via `__proto__`).** `Array.prototype.myprop = 42; var x = []; x.myprop` was returning undefined and `x.hasOwnProperty(...)` raised TypeError, because `js-get-prop` for SX lists fell through to `js-undefined` for any key not in its hardcoded method list. Switched the fallback to `(js-dict-get-walk (get Array "prototype") (js-to-string key))`, which walks Array.prototype → (via the recent `__proto__` fallback) Object.prototype. Now custom Array.prototype properties propagate, and `arr.hasOwnProperty` resolves to `Object.prototype.hasOwnProperty`. built-ins/Array: 14/45 → 16/45. conformance.sh: 148/148. - 2026-05-08 — **Arrays accept numeric-string property keys (`arr["0"]`).** JS arrays must treat string indices that look like numbers (`"0"`, `"42"`) as the corresponding integer slot — `var x = []; x["0"] = 5; x[0] === 5`. `js-get-prop` and `js-list-set!` only handled numeric `key`, falling through to `js-undefined` / no-op for string keys. Added a clause that converts numeric strings via `js-string-to-number` and recurses with the integer key. built-ins/Array: 13/45 → 14/45. conformance.sh: 148/148.