diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 5bf45ba6..7932213e 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -4562,12 +4562,13 @@ (&rest args) (let ((this-val (js-this))) - (if - (and - (= (type-of this-val) "dict") - (contains? (keys this-val) "__js_boolean_value__")) - (get this-val "__js_boolean_value__") - this-val)))) + (cond + ((= (type-of this-val) "boolean") this-val) + ((and + (= (type-of this-val) "dict") + (contains? (keys this-val) "__js_boolean_value__")) + (get this-val "__js_boolean_value__")) + (else (raise (js-new-call TypeError (js-args "Boolean.prototype.valueOf requires a Boolean")))))))) (dict-set! (get Boolean "prototype") @@ -4576,9 +4577,11 @@ (&rest args) (let ((this-val (js-this))) - (let - ((b (if (and (= (type-of this-val) "dict") (contains? (keys this-val) "__js_boolean_value__")) (get this-val "__js_boolean_value__") this-val))) - (if b "true" "false"))))) + (cond + ((= (type-of this-val) "boolean") (if this-val "true" "false")) + ((and (= (type-of this-val) "dict") (contains? (keys this-val) "__js_boolean_value__")) + (if (get this-val "__js_boolean_value__") "true" "false")) + (else (raise (js-new-call TypeError (js-args "Boolean.prototype.toString requires a Boolean")))))))) (define parseInt diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index cc4b4f40..8a32f38c 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-09 — **`Boolean.prototype.toString`/`valueOf` throw TypeError on non-Boolean receivers.** Per spec, both methods are not generic — calling them with a `this` that isn't a Boolean primitive or wrapper must throw TypeError. Was silently returning `"true"`/`"false"` based on whether the receiver was truthy (`s1.toString = Boolean.prototype.toString; s1.toString()` returned `"true"` for any non-empty string instead of throwing). Added an `else (raise (js-new-call TypeError ...))` branch to both prototype methods. Result: built-ins/Boolean 28/30 → 29/30. Object 30/30 holds. conformance.sh: 148/148. + - 2026-05-09 — **`Array.prototype.reduce`/`reduceRight` callback receives `(acc, cur, idx, array)`.** Was calling `(f acc cur)` — only two args, no index, no source array. Per spec the reducer signature is `(accumulator, currentValue, currentIndex, array)`. Updated `js-list-reduce-loop` and `js-list-reduce-right-loop` to call via `js-call-with-this js-undefined f (list acc cur i arr)`. Result: built-ins/Array/prototype/reduce 6/30 → 8/30, reduceRight 6/30 → 8/30. Object 30/30 holds. conformance.sh: 148/148. - 2026-05-09 — **`Array.prototype.find`/`findIndex`/`some`/`every` honour `thisArg` and pass `(value, index, array)`.** Same shape as the previous `forEach`/`map`/`filter` fix — these were calling `(f x)` directly. Updated each prototype method to extract optional `thisArg` (defaulting to globalThis when null/undefined) and route through `js-call-with-this` with the full `(value, index, array)` triple. Updated `js-list-find-loop` / `js-list-find-index-loop` / `js-list-some-loop` / `js-list-every-loop` to match. Result: built-ins/Array/prototype/find 5/30 → 6/30. Modest delta this round (most remaining failures need deeper Array semantics — sparse arrays, ToLength on `length`, etc.). Object 30/30, Map 18/30 unchanged. conformance.sh: 148/148.