js-on-sx: Date.UTC and new Date propagate NaN/Infinity args
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 4m20s

This commit is contained in:
2026-05-10 09:03:42 +00:00
parent df4aa8eb0a
commit 237ea5ce84
2 changed files with 35 additions and 3 deletions

View File

@@ -1111,8 +1111,10 @@
(v)
(cond
((number? v) v)
((= (type-of v) "rational") (exact->inexact v))
((= (type-of v) "string") (js-date-parse-string v))
(else 0))))
((js-undefined? v) (js-nan-value))
(else (js-to-number v)))))
(define
js-date-parse-string
@@ -1159,6 +1161,26 @@
(* secs 1000)
ms))))))
(define
js-date-args-have-nan?
(fn
(args i)
(cond
((>= i (len args)) false)
(else
(let
((n (js-to-number (nth args i))))
(cond
((or (number? n) (= (type-of n) "rational"))
(let
((nf (if (= (type-of n) "rational") (exact->inexact n) n)))
(cond
((js-number-is-nan nf) true)
((= nf (js-infinity-value)) true)
((= nf (- 0 (js-infinity-value))) true)
(else (js-date-args-have-nan? args (+ i 1))))))
(else (js-date-args-have-nan? args (+ i 1)))))))))
(define
js-date-civil-to-days
(fn
@@ -1219,6 +1241,7 @@
(cond
((= (len args) 0) 0)
((= (len args) 1) (js-date-from-one (nth args 0)))
((js-date-args-have-nan? args 0) (js-nan-value))
(else (js-date-from-parts args))))
(dict-set! this "__js_is_date__" true)
this)))))
@@ -1228,8 +1251,15 @@
(fn
(&rest args)
(cond
((= (len args) 0) 0)
(else (js-date-from-parts args))))
((= (len args) 0) (js-nan-value))
((js-date-args-have-nan? args 0) (js-nan-value))
(else
(let
((ms (js-date-from-parts args)))
(cond
((or (> ms 8640000000000000) (< ms -8640000000000000))
(js-nan-value))
(else ms))))))
:prototype
{:getTime (fn () (js-date-time-value (js-this)))
:valueOf (fn () (js-date-time-value (js-this)))

View File

@@ -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 — **`Date.UTC` / `new Date(...)` propagate NaN/±Infinity arguments and return NaN.** `Date.UTC()` (no args) returned 0 instead of NaN; `Date.UTC(NaN, ...)` did the math and produced bogus ms; `new Date(year, NaN)` constructed a normal Date instead of an invalid one. Added `js-date-args-have-nan?` (also detects ±Infinity and propagates from rationals) used by both `Date.UTC` and the multi-arg constructor branch; UTC now returns NaN on no-arg / any-NaN-arg / out-of-range result, and `new Date(args)` stores NaN in `__date_value__` when any arg is NaN. Also fixed `js-date-from-one(undefined)` to return NaN. Result: built-ins/Date/UTC 6/16 → 10/16 (+4). Date 17/30 → 26/30 (timeouts dropped from 12 → 4 because invalid Dates now short-circuit). conformance.sh: 148/148.
- 2026-05-10 — **Real `Date` construction + getters via Howard-Hinnant civil-day arithmetic.** `js-date-from-parts` now computes a true ms-since-epoch from `(year, month, day, hour, min, sec, ms)` via `js-date-civil-to-days` (the inverse of last iteration's `days-to-ymd`), with the legacy 2-digit-year coercion (0..99 → 1900+y). `getFullYear/Month/Date/Day/Hours/Minutes/Seconds/Milliseconds` (UTC + non-UTC) all share a new `js-date-getter`: TypeErrors on non-Date this, returns NaN on invalid time, otherwise decomposes ms into y/m/d/h/m/s/ms/dow. Plus added `Date.prototype.constructor = Date` (was missing). Result: each of the 8 Date getter categories went 2/6 → 5/6 (+3 each, +24 total). Date toISOString 11/16 → 13/16. Some Date construction-loop tests now exceed the 15s per-test timeout — the new civil math is heavier than the old (year-1970)*ms-per-year approximation, but correctness wins. conformance.sh: 148/148.
- 2026-05-10 — **`Date.prototype.toISOString` produces real `YYYY-MM-DDTHH:mm:ss.sssZ` and validates input.** Old `js-date-iso` only computed the year and hardcoded the rest as `01-01T00:00:00.000Z`. Added: (1) TypeError when this isn't a Date (no `__js_is_date__` slot); (2) RangeError when ms is NaN, undefined, or |ms| > 8.64e15; (3) full date breakdown via Howard-Hinnant `days_to_civil` algorithm (`js-date-days-to-ymd`) → year/month/day, plus modular hours/min/sec/ms; (4) extended-year format `±YYYYYY` for years outside 0..9999. Result: built-ins/Date/prototype/toISOString 7/16 → 11/16 (+4). Date 21/30. conformance.sh: 148/148.