From d8b8de61951670922bdf6aef2fdfb6da0291c13c Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 20:55:13 +0000 Subject: [PATCH] js-on-sx: Error.isError + [[ErrorData]] slot + verifyEqualTo --- lib/js/runtime.sx | 52 ++++++++++++++++++++++++++++++++++------ lib/js/test262-runner.py | 3 +++ plans/js-on-sx.md | 2 ++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index c8f8aec6..4d550ec9 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -834,10 +834,36 @@ (= (len args) 0) "" (js-to-string (nth args 0)))) - (dict-set! this "name" "Error")) + (dict-set! this "name" "Error") + (dict-set! this "__js_error_data__" true)) nil) this)))) +(define + js-error-is-error + (fn + (&rest args) + (cond + ((= (len args) 0) false) + (else + (let + ((v (nth args 0))) + (and + (= (type-of v) "dict") + (or + (contains? (keys v) "__js_error_data__") + (js-error-proto-walk? v)))))))) + +(define + js-error-proto-walk? + (fn + (v) + (cond + ((not (= (type-of v) "dict")) false) + ((contains? (keys v) "__js_error_data__") true) + ((not (contains? (keys v) "__proto__")) false) + (else (js-error-proto-walk? (get v "__proto__")))))) + ;; ── Math object ─────────────────────────────────────────────────── (define @@ -857,7 +883,8 @@ (= (len args) 0) "" (js-to-string (nth args 0)))) - (dict-set! this "name" "TypeError")) + (dict-set! this "name" "TypeError") + (dict-set! this "__js_error_data__" true)) nil) this)))) (define @@ -877,7 +904,8 @@ (= (len args) 0) "" (js-to-string (nth args 0)))) - (dict-set! this "name" "RangeError")) + (dict-set! this "name" "RangeError") + (dict-set! this "__js_error_data__" true)) nil) this)))) (define @@ -897,7 +925,8 @@ (= (len args) 0) "" (js-to-string (nth args 0)))) - (dict-set! this "name" "SyntaxError")) + (dict-set! this "name" "SyntaxError") + (dict-set! this "__js_error_data__" true)) nil) this)))) (define @@ -917,7 +946,8 @@ (= (len args) 0) "" (js-to-string (nth args 0)))) - (dict-set! this "name" "ReferenceError")) + (dict-set! this "name" "ReferenceError") + (dict-set! this "__js_error_data__" true)) nil) this)))) (define @@ -935,7 +965,8 @@ this "message" (if (empty? args) "" (js-to-string (nth args 0)))) - (dict-set! this "name" "URIError"))) + (dict-set! this "name" "URIError") + (dict-set! this "__js_error_data__" true))) this)))) (define EvalError @@ -952,8 +983,13 @@ this "message" (if (empty? args) "" (js-to-string (nth args 0)))) - (dict-set! this "name" "EvalError"))) + (dict-set! this "name" "EvalError") + (dict-set! this "__js_error_data__" true))) this)))) + +(define AggregateError :js-undefined) + +(define SuppressedError :js-undefined) (define js-function? (fn @@ -2965,6 +3001,8 @@ (js-dict-get-walk obj (js-to-string key))) ((and (= obj Promise) (dict-has? __js_promise_statics__ (js-to-string key))) (get __js_promise_statics__ (js-to-string key))) + ((and (= obj Error) (= (js-to-string key) "isError")) + js-error-is-error) ((and (js-function? obj) (or (= key "prototype") (= key "name") (= key "length") (= key "call") (= key "apply") (= key "bind") (= key "constructor"))) (cond ((= key "prototype") (js-get-ctor-proto obj)) diff --git a/lib/js/test262-runner.py b/lib/js/test262-runner.py index 87efe9ec..e7d532fa 100644 --- a/lib/js/test262-runner.py +++ b/lib/js/test262-runner.py @@ -134,6 +134,9 @@ var verifyProperty = function (obj, name, desc, opts) { } }; var verifyPrimordialProperty = verifyProperty; +var verifyEqualTo = function (obj, name, value) { + assert.sameValue(obj[name], value, name + " equals"); +}; var verifyNotEnumerable = function (o, n, v, w, x) { }; var verifyNotWritable = function (o, n, v, w, x) { }; var verifyNotConfigurable = function (o, n, v, w, x) { }; diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 09fe40a0..e26db918 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 — **`Error.isError` static + `[[ErrorData]]` slot + `verifyEqualTo` harness helper.** Added `Error.isError(v)` per the Stage-3 proposal: returns `true` only for objects with the internal `[[ErrorData]]` slot. Implemented as `__js_error_data__: true` set on `this` by every Error subclass constructor (Error/TypeError/RangeError/SyntaxError/ReferenceError/URIError/EvalError); `js-error-is-error` walks `__proto__` looking for the marker. Wired through the lambda-static-prop path next to the existing `Promise.resolve` / `Promise.reject` lookup. Defined `AggregateError` and `SuppressedError` as `:js-undefined` so `typeof AggregateError !== 'undefined'` resolves cleanly (without these, the bare ident lookup throws ReferenceError). Added `verifyEqualTo` to the harness — `propertyHelper.js` includes it, used by `Error/message_property.js` etc. Result: built-ins/Error 6/30 → 11/30 (+5), Error/isError sub-suite 0/9 → 5/9. Map/Object unchanged. conformance.sh: 148/148. + - 2026-05-08 — **Harness: `$DONE` / `asyncTest` and `checkSequence` / `checkSettledPromises` stubs added.** Async-flagged Promise tests call `$DONE(err?)` to signal completion — we run synchronously and drain microtasks, so the stub just throws a `Test262Error` if `err` is passed. `asyncTest(fn)` wraps the test fn in `Promise.resolve().then(..., $DONE)`. `checkSequence(arr, msg)` (from `promiseHelper.js`) verifies `arr[i] === i+1` — used by ordering tests on `Promise.all` / `Promise.race`. `checkSettledPromises(actual, expected, msg)` matches what `Promise.allSettled` tests expect. Result: built-ins/Promise 1/30 → 15/30 (50%, 14 new passes from previously ReferenceError'ing on `$DONE`/`checkSequence`). conformance.sh: 148/148. - 2026-05-08 — **`Map` and `Set` constructors with full instance API.** Both were undefined globally — every test in those categories died at `new Map()` / `new Set()` with ReferenceError. Implemented as plain SX storage on the instance dict (`__map_keys__` + `__map_vals__` parallel lists for Map, `__set_items__` for Set) using SX `=` for key/value comparisons. Wired prototype methods: `.get`, `.set`, `.has`, `.delete`, `.clear`, `.forEach`, `.keys`, `.values`, `.entries` for Map; `.add`, `.has`, `.delete`, `.clear`, `.forEach`, `.keys`, `.values`, `.entries` for Set. `.size` is a real own property updated on every mutation (no getters). Constructors use the dict-with-`__callable__` pattern (like `Object`) so `Map.length`, `Map.name`, `Map.prototype` work as regular dict reads. Constructor accepts an iterable of `[k,v]` pairs (Map) or values (Set). Added `Map`/`Set` to `js-global` and to the prototype-chain post-init block. Result: built-ins/Map 1/30 → 18/30 (60%), built-ins/Set 0/30 → 15/30 (50%, rest mostly timeouts on iterator-protocol tests). conformance.sh: 148/148.