From 154e2297fe536bda3be92deb9dc0a03c8998884d Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 11 May 2026 05:55:51 +0000 Subject: [PATCH] js-on-sx: fix js-string-repeat arity collision, repeat() raises RangeError on neg/inf --- lib/js/runtime.sx | 25 +++++++++++++++++-------- plans/js-on-sx.md | 2 ++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index f72010d0..180d01da 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -3238,12 +3238,18 @@ (define js-string-repeat + (fn + (s n) + (js-string-repeat-loop s n ""))) + +(define + js-string-repeat-loop (fn (s n acc) (if (<= n 0) acc - (js-string-repeat s (- n 1) (str acc s))))) + (js-string-repeat-loop s (- n 1) (str acc s))))) (define js-string-pad @@ -3383,7 +3389,16 @@ ((= name "trimStart") (fn () (js-trim-left s))) ((= name "trimEnd") (fn () (js-trim-right s))) ((= name "repeat") - (fn (n) (js-string-repeat s (js-num-to-int n) ""))) + (fn + (n) + (let + ((nn (js-to-number n))) + (cond + ((or (< nn 0) (= nn (js-infinity-value))) + (raise + (js-new-call RangeError + (js-args "Invalid count value")))) + (else (js-string-repeat-loop s (js-num-to-int nn) "")))))) ((= name "padStart") (fn (&rest args) @@ -5732,12 +5747,6 @@ (if (> (len sp) 10) (js-string-slice sp 0 10) sp)) (else "")))) -(define - js-string-repeat - (fn - (s n) - (if (<= n 0) "" (str s (js-string-repeat s (- n 1)))))) - (define js-json-unwrap-primitive (fn diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 620c6c4e..054b0495 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-10 — **`String.prototype.repeat` no longer arity-collides with itself; raises RangeError on negative or +Infinity counts.** Earlier JSON.stringify iteration introduced a 2-arg `js-string-repeat` that shadowed the existing 3-arg `(s n acc)` accumulator implementation, breaking every `s.repeat(n)` call with "expects 2 args, got 3". Renamed the accumulator helper to `js-string-repeat-loop` and made `js-string-repeat` a 2-arg facade that delegates. Hooked the repeat method to raise RangeError when `count < 0` or `count = Infinity` per spec. Result: built-ins/String/prototype/repeat 7/13 → 11/13 (+4). conformance.sh: 148/148. + - 2026-05-10 — **test262-runner inlines small upstream harness includes (`nans.js`, `sta.js`, `byteConversionValues.js`, `compareArray.js`) per-test.** The runner parsed `includes:` frontmatter but never used it, so tests like `built-ins/isNaN/return-true-nan.js` (which depends on `var NaNs = [...]`) failed with "ReferenceError: undefined symbol". Added `_load_harness_include` (cached) and `assemble_source` now prepends each allowlisted include's source to the test. Allowlist excludes large helpers like `propertyHelper.js` because per-test js-eval+JIT cost on a 371-line harness pushes tests over the 15s per-test timeout (regressed Math/abs 7/7 → 4/7 in a first-pass attempt before allowlisting). Result: built-ins/isNaN 2/7 → 3/7. conformance.sh: 148/148. - 2026-05-10 — **Real `Date.prototype.setFullYear/setMonth/setDate/setHours/setMinutes/setSeconds/setMilliseconds` (+ UTC variants) and a corrected `setTime`.** All Date setters were missing — only `setTime` existed and didn't validate. Added a unified `js-date-setter(d, field, args)` that decomposes the current ms into `(y mo da hh mm ss msv)` via `js-date-decompose`, splices in the `args` per the field's optional-arg contract (e.g. `setHours(h, m?, s?, ms?)`), recomposes via `js-date-civil-to-days`, and TimeClips at ±8.64e15. NaN args anywhere → ms set to NaN. Wired all 14 setters to the helper. Hit a parser gotcha: SX `cond` clause body is single-form only — multi-expression bodies like `(else (dict-set! ...) new-ms)` silently treat the second form as `( new-ms)` ("Not callable: false"). Wrapped these in `(begin ...)`. Result: setFullYear 5/18 → 13/18 (+8). setHours 5/21 → 15/21 (+10). setMonth 3/15 → 9/15 (+6). setMinutes 4/16 → 10/16 (+6). setSeconds 3/15 → 9/15 (+6). setDate 2/12 → 6/12 (+4). setMilliseconds 2/12 → 6/12 (+4). setTime 4/9 → 6/9 (+2). conformance.sh: 148/148.