diff --git a/lib/js/parser.sx b/lib/js/parser.sx index 481af105..a2664866 100644 --- a/lib/js/parser.sx +++ b/lib/js/parser.sx @@ -537,6 +537,11 @@ (st elems) (cond ((jp-at? st "punct" "]") nil) + ((jp-at? st "punct" ",") + (begin + (append! elems (list (quote js-undef))) + (jp-advance! st) + (jp-array-loop st elems))) (else (begin (cond diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 836e2dfc..2a2e7de1 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -809,6 +809,15 @@ ((and (= (type-of obj) "dict") (contains? (keys obj) "__proto__")) (js-instanceof-walk obj proto)) (else false)))) + ((list? obj) + (let + ((proto (js-get-ctor-proto ctor)) + (arrproto (get Array "prototype")) + (objproto (get Object "prototype"))) + (cond + ((= proto arrproto) true) + ((= proto objproto) true) + (else false)))) ((not (= (type-of obj) "dict")) false) (else (let @@ -3327,7 +3336,7 @@ ((= key "findLast") (js-array-method obj "findLast")) ((= key "findLastIndex") (js-array-method obj "findLastIndex")) ((= key "reduceRight") (js-array-method obj "reduceRight")) - ((= key "toString") (js-array-method obj "toString")) + ((= key "toString") (js-dict-get-walk (get Array "prototype") "toString")) ((= key "toLocaleString") (js-array-method obj "toLocaleString")) ((= key "keys") (js-array-method obj "keys")) ((= key "values") (js-array-method obj "values")) diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 68387aa8..2d3cca7a 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 — **Array literal elision (holes), `list instanceof Array`, `array.toString` identity.** Three coupled fixes for `language/expressions/array`. (1) Parser: `jp-array-loop` accepts a leading or interior `,` as elision and pushes `(js-undef)`, so `[,]`, `[,,3,,,]`, `[1,,3]` parse and produce length 1, 5, 3. (2) Runtime: `js-instanceof` adds a `(list? obj)` arm that returns true when the right-hand side is `Array` (or `Object`). (3) Runtime: `js-get-prop` for `key="toString"` on a list returns the actual `Array.prototype.toString` slot via `js-dict-get-walk` instead of a fresh `js-array-method` callable, so `[1,2,3].toString === Array.prototype.toString`. `toLocaleString` left on the legacy arm — its proto entry is a dict-with-`__callable__` whose body re-enters `js-invoke-method`, which would loop. Result: language/expressions/array 13/30 → 21/30 (+8). conformance.sh: 148/148. + - 2026-05-10 — **`Object.getOwnPropertyDescriptor` skips internal `__proto__` and `__js_order__` keys.** Was returning a regular property descriptor for our internal `__proto__` and `__js_order__` markers — `Object.getOwnPropertyDescriptor({__proto__: null}, "__proto__")` returned `{configurable, enumerable, value: null, writable}` instead of `undefined` per spec. Added a `(js-key-internal? sk)` short-circuit in the descriptor path that returns `:js-undefined` for internal keys. Result: language/expressions/object 13/30 → 16/30. Object 30/30 holds, getOwnPropertyDescriptor 28/30. conformance.sh: 148/148. - 2026-05-09 — **Object literal spread `{...src}` parses + executes.** Per ES spec, object literals can include `...expr` to copy own enumerable properties from a source. `jp-parse-object-entry` was rejecting the leading `...` punct. Added a parser branch that records the AST under `:spread`. `js-transpile-object` emits `(js-obj-spread! _obj )` for spread entries, alongside the existing `(js-obj-set! _obj k v)` for regular entries. New `js-obj-spread!` runtime helper: dict source copies own enumerable keys (skipping internal `__js_order__` / `__proto__`); string source copies each character at its numeric index; list source copies elements at their numeric index; null/undefined no-op. Result: language/expressions/array 5/30 → 13/30 (+8). Object 30/30 holds. conformance.sh: 148/148.