From 8d9ce7838d0abbdfd1670991d9aea9e5df823566 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 04:26:37 +0000 Subject: [PATCH] js-on-sx: Object.prototype.toString dispatches by [[Class]] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was hardcoded to "[object Object]" for everything; per ES it should return "[object Array]", "[object Function]", "[object Number]", etc. by class. Added js-object-tostring-class helper that switches on type-of and dict-internal markers (__js_*_value__, __callable__). Prototype-identity checks ensure Object.prototype.toString.call(Number.prototype) returns "[object Number]" (similar for String/Boolean/Array). built-ins/Array: 18/45 → 20/45, built-ins/Number: 43/50 → 44/50. conformance.sh: 148/148. --- lib/js/runtime.sx | 28 +++++++++++++++++++- lib/js/test262-scoreboard.json | 48 +++++++++++++++++++++++----------- lib/js/test262-scoreboard.md | 13 ++++++--- plans/js-on-sx.md | 2 ++ 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index ef44de7a..b8c8afc2 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -942,6 +942,32 @@ "function") (else "object")))) +(define + js-object-tostring-class + (fn + (v) + (cond + ((js-undefined? v) "[object Undefined]") + ((= v nil) "[object Null]") + ((= (type-of v) "list") "[object Array]") + ((= (type-of v) "string") "[object String]") + ((= (type-of v) "number") "[object Number]") + ((= (type-of v) "boolean") "[object Boolean]") + ((or (= (type-of v) "lambda") (= (type-of v) "function") (= (type-of v) "component")) + "[object Function]") + ((= (type-of v) "dict") + (cond + ((contains? (keys v) "__callable__") "[object Function]") + ((contains? (keys v) "__js_string_value__") "[object String]") + ((contains? (keys v) "__js_number_value__") "[object Number]") + ((contains? (keys v) "__js_boolean_value__") "[object Boolean]") + ((= v (get Number "prototype")) "[object Number]") + ((= v (get String "prototype")) "[object String]") + ((= v (get Boolean "prototype")) "[object Boolean]") + ((= v (get Array "prototype")) "[object Array]") + (else "[object Object]"))) + (else "[object Object]")))) + (define js-to-boolean (fn @@ -3444,7 +3470,7 @@ (and (>= idx 0) (< idx (len o)) (integer? idx)))) (else false)))) -(define Object {:keys js-object-keys :getPrototypeOf js-object-get-prototype-of :isSealed js-object-is-sealed :seal js-object-seal :create js-object-create :isExtensible js-object-is-extensible :is js-object-is :setPrototypeOf js-object-set-prototype-of :getOwnPropertyNames js-object-get-own-property-names :getOwnPropertyDescriptors js-object-get-own-property-descriptors :defineProperty js-object-define-property :fromEntries js-object-from-entries :getOwnPropertyDescriptor js-object-get-own-property-descriptor :assign js-object-assign :isFrozen js-object-is-frozen :freeze js-object-freeze :values js-object-values :hasOwn js-object-has-own :prototype {:hasOwnProperty (fn (k) (let ((o (js-this))) (js-object-has-own o k))) :toLocaleString (fn () "[object Object]") :isPrototypeOf (fn (o) (let ((this-val (js-this))) (cond ((not (dict? o)) false) (else (let ((proto (if (contains? (keys o) "__proto__") (get o "__proto__") nil))) (cond ((= proto this-val) true) ((= proto nil) false) (else ((get (get Object "prototype") "isPrototypeOf") proto)))))))) :toString (fn () "[object Object]") :propertyIsEnumerable (fn (k) (let ((o (js-this))) (js-object-has-own o k))) :valueOf (fn () (js-this))} :__callable__ (fn (&rest args) (let ((this-val (js-this))) (let ((is-new (and (dict? this-val) (contains? (keys this-val) "__proto__") (= (get this-val "__proto__") (get Object "prototype"))))) (cond ((= (len args) 0) (if is-new this-val (dict))) ((or (= (nth args 0) nil) (js-undefined? (nth args 0))) (if is-new this-val (dict))) ((= (type-of (nth args 0)) "string") (js-new-call String (list (nth args 0)))) ((= (js-typeof (nth args 0)) "number") (js-new-call Number (list (nth args 0)))) ((= (js-typeof (nth args 0)) "boolean") (js-new-call Boolean (list (nth args 0)))) (else (nth args 0)))))) :preventExtensions js-object-prevent-extensions :entries js-object-entries :defineProperties js-object-define-properties}) +(define Object {:keys js-object-keys :getPrototypeOf js-object-get-prototype-of :isSealed js-object-is-sealed :seal js-object-seal :create js-object-create :isExtensible js-object-is-extensible :is js-object-is :setPrototypeOf js-object-set-prototype-of :getOwnPropertyNames js-object-get-own-property-names :getOwnPropertyDescriptors js-object-get-own-property-descriptors :defineProperty js-object-define-property :fromEntries js-object-from-entries :getOwnPropertyDescriptor js-object-get-own-property-descriptor :assign js-object-assign :isFrozen js-object-is-frozen :freeze js-object-freeze :values js-object-values :hasOwn js-object-has-own :prototype {:hasOwnProperty (fn (k) (let ((o (js-this))) (js-object-has-own o k))) :toLocaleString (fn () "[object Object]") :isPrototypeOf (fn (o) (let ((this-val (js-this))) (cond ((not (dict? o)) false) (else (let ((proto (if (contains? (keys o) "__proto__") (get o "__proto__") nil))) (cond ((= proto this-val) true) ((= proto nil) false) (else ((get (get Object "prototype") "isPrototypeOf") proto)))))))) :toString (fn () (js-object-tostring-class (js-this))) :propertyIsEnumerable (fn (k) (let ((o (js-this))) (js-object-has-own o k))) :valueOf (fn () (js-this))} :__callable__ (fn (&rest args) (let ((this-val (js-this))) (let ((is-new (and (dict? this-val) (contains? (keys this-val) "__proto__") (= (get this-val "__proto__") (get Object "prototype"))))) (cond ((= (len args) 0) (if is-new this-val (dict))) ((or (= (nth args 0) nil) (js-undefined? (nth args 0))) (if is-new this-val (dict))) ((= (type-of (nth args 0)) "string") (js-new-call String (list (nth args 0)))) ((= (js-typeof (nth args 0)) "number") (js-new-call Number (list (nth args 0)))) ((= (js-typeof (nth args 0)) "boolean") (js-new-call Boolean (list (nth args 0)))) (else (nth args 0)))))) :preventExtensions js-object-prevent-extensions :entries js-object-entries :defineProperties js-object-define-properties}) (dict-set! Object "length" 1) diff --git a/lib/js/test262-scoreboard.json b/lib/js/test262-scoreboard.json index 77eca860..45a88075 100644 --- a/lib/js/test262-scoreboard.json +++ b/lib/js/test262-scoreboard.json @@ -1,27 +1,45 @@ { "totals": { - "pass": 45, - "fail": 0, - "skip": 5, - "timeout": 0, + "pass": 44, + "fail": 3, + "skip": 0, + "timeout": 3, "total": 50, - "runnable": 45, - "pass_rate": 100.0 + "runnable": 50, + "pass_rate": 88.0 }, "categories": [ { - "category": "built-ins/Math", + "category": "built-ins/Number", "total": 50, - "pass": 45, - "fail": 0, - "skip": 5, - "timeout": 0, - "pass_rate": 100.0, - "top_failures": [] + "pass": 44, + "fail": 3, + "skip": 0, + "timeout": 3, + "pass_rate": 88.0, + "top_failures": [ + [ + "Timeout", + 3 + ], + [ + "Test262Error (assertion failed)", + 3 + ] + ] } ], - "top_failure_modes": [], + "top_failure_modes": [ + [ + "Timeout", + 3 + ], + [ + "Test262Error (assertion failed)", + 3 + ] + ], "pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33", - "elapsed_seconds": 9.0, + "elapsed_seconds": 57.4, "workers": 1 } \ No newline at end of file diff --git a/lib/js/test262-scoreboard.md b/lib/js/test262-scoreboard.md index 89ffc358..de6707c5 100644 --- a/lib/js/test262-scoreboard.md +++ b/lib/js/test262-scoreboard.md @@ -1,17 +1,24 @@ # test262 scoreboard Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33` -Wall time: 9.0s +Wall time: 57.4s -**Total:** 45/45 runnable passed (100.0%). Raw: pass=45 fail=0 skip=5 timeout=0 total=50. +**Total:** 44/50 runnable passed (88.0%). Raw: pass=44 fail=3 skip=0 timeout=3 total=50. ## Top failure modes +- **3x** Timeout +- **3x** Test262Error (assertion failed) ## Categories (worst pass-rate first, min 10 runnable) | Category | Pass | Fail | Skip | Timeout | Total | Pass % | |---|---:|---:|---:|---:|---:|---:| -| built-ins/Math | 45 | 0 | 5 | 0 | 50 | 100.0% | +| built-ins/Number | 44 | 3 | 0 | 3 | 50 | 88.0% | ## Per-category top failures (min 10 runnable, worst first) + +### built-ins/Number (44/50 — 88.0%) + +- **3x** Timeout +- **3x** Test262Error (assertion failed) diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 48480641..12240798 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 — **`Object.prototype.toString` dispatches by [[Class]].** Was hardcoded to `"[object Object]"` for everything; per ES it should return `"[object Array]"`, `"[object Function]"`, `"[object Number]"`, etc. based on the receiver's class. Added `js-object-tostring-class` helper that switches on `(type-of v)` and on dict-internal markers (`__js_string_value__`, `__js_number_value__`, `__js_boolean_value__`, `__callable__`). Also added prototype-identity checks so `Object.prototype.toString.call(Number.prototype)` returns `"[object Number]"` (similar for String/Boolean/Array). built-ins/Array: 18/45 → 20/45, built-ins/Number: 43/50 → 44/50. conformance.sh: 148/148. + - 2026-05-08 — **`Math.X.name` returns the JS-style method name.** `Math.acos.name`, `Math.acosh.name`, `Math.asin.name` were returning the SX symbol name (`"js-math-acos"` etc.). `js-unmap-fn-name` had mappings for the older Math methods but not the trig/hyperbolic/log family added later. Added mappings for sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh, asinh, acosh, atanh, exp, log, log2, log10, expm1, log1p, clz32, imul, fround. built-ins/Math: 42/45 → 45/45 (100%). conformance.sh: 148/148. - 2026-05-08 — **`fn.constructor === Function` for function instances.** Per ES, every function instance's `constructor` slot points to the `Function` global. Was returning undefined for `(function () {}).constructor`. Added `constructor` to the function-property cond in `js-get-prop`; returns `js-function-global`. Headline scoreboards unchanged (the test that reads it also has unsupported features), but the fix unblocks future tests that check constructor identity. conformance.sh: 148/148.