js-on-sx: callable Number/String/Boolean/Array + Array.sort

Builtin constructors now have :__callable__ slot. js-call-plain
and js-function? detect dicts with __callable__ and dispatch
through it. Number('42')===42, String(true)==='true', Boolean(0)
===false, Array(3) builds length-3 list.

Array.prototype.sort(comparator?): bubble sort via js-list-sort-
outer!/-inner!. Default lex order, custom comparator supported.

Wide scoreboard committed: 259/5354 (4.8%) from earlier runtime.

438/440 unit (+11), 148/148 slice unchanged.
This commit is contained in:
2026-04-23 22:53:13 +00:00
parent d6975d3c79
commit 1459f7a637
5 changed files with 501 additions and 5 deletions

View File

@@ -195,6 +195,10 @@ Append-only record of completed iterations. Loop writes one line per iteration:
- 2026-04-23 — **Object + array destructuring in var/let/const decls.** Parser: `jp-parse-vardecl` now handles three shapes — plain `ident`, `{a, b, c}` object pattern, `[a, , c]` array pattern with hole support. `jp-parse-obj-pattern` / `jp-parse-arr-pattern` / their loops collect the names. AST: `(js-vardecl-obj (names...) rhs)` and `(js-vardecl-arr (names-with-holes-as-nil...) rhs)`. Transpile: `js-vardecl-forms` dispatches on the three tags. Destructures emit `(define __destruct__ rhs)` then `(define name (js-get-prop __destruct__ key-or-index))` for each pattern element (skips nil holes in array patterns). 4 new unit tests. 418/420 (414→+4). Conformance unchanged. Gotcha: running destructuring tests sequentially — if epoch N defines `a, b` globally and epoch N+1 uses the same names as different types, "Not callable: N" results. Top-level `var` transpiles to `(define name value)`; re-defining a name that's held a value in a prior call to eval carries over. The proper fix would be to use `let` block-scoping; workaround for tests is unique names.
- 2026-04-23 — **Optional chaining `?.` + logical assignment `&&= / ||= / ??=`.** Parser: `jp-parse-postfix` handles `op "?."` followed by ident / `[` / `(` emitting `(js-optchain-member obj name)` / `(js-optchain-index obj k)` / `(js-optchain-call callee args)`. Transpile: all emit `(js-optchain-get obj key)` or `(js-optchain-call fn args)` — runtime short-circuits to undefined when the receiver is null/undefined. Logical assignment: `js-compound-update` gains `&&=` / `||=` / `??=` cases that emit `(if (js-to-boolean lhs) rhs lhs)` / `(if (js-to-boolean lhs) lhs rhs)` / `(if nullish? rhs lhs)`. 9 new tests. 427/429 (418→+9). Conformance unchanged.
- 2026-04-23 — **Callable `Number() / String() / Boolean() / Array()` + `Array.prototype.sort`.** Made the builtin constructor dicts callable by adding a `:__callable__` slot that points to a conversion function; `js-call-plain` and `js-function?` now detect dicts with `__callable__` and dispatch through it. `Number("42") === 42`, `String(true) === "true"`, `Boolean(0) === false`, `Array(3)` returns length-3 list, `Array(1,2,3)` returns `[1,2,3]`. `Array.prototype.sort(comparator?)` added via bubble-sort O(n²) `js-list-sort-outer!` / `-inner!`. Default comparator is lexicographic (JS-spec `toString()` then compare). Custom comparators get `(cmp a b) → number` and swap when positive. 11 new tests. 438/440 (427→+11). Conformance unchanged. Wide scoreboard (Math+Number+String+Array+{addition,equals,if,for,while}): baseline **259/5354 (4.8%)** before these improvements; top failures were ReferenceError (1056×), TypeError not-a-function (514×), array-like `{length:3, 0:41, 1:42, 2:43}` receivers (455×), SyntaxError (454×). Need to re-run scoreboard to see the delta from all the April 23rd work.
## Phase 3-5 gotchas
Worth remembering for later phases: