HS add/append: Set dedup, @attr support, when-clause result tracking
- runtime hs-add-to!/hs-append: dedupe on list targets (Set semantics) - compiler emit-set: set result to X now syncs it too - compiler append!: handle (local)/(ref) targets via emit-set so scoped vars get rebound to the returned list - parser add/remove: accept bare @attr (not just [@attr]) - parser add-attr: support when-clause → emits add-attr-when - compiler add-class-when/add-attr-when: collect matched items into the-result / it so subsequent "if the result is empty" works +6 upstream tests in early range (add 13→17, append 10→12). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,35 +1,76 @@
|
||||
{
|
||||
"totals": {
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"skip": 0,
|
||||
"timeout": 7,
|
||||
"total": 8,
|
||||
"pass_rate": 0.0
|
||||
"pass": 56,
|
||||
"fail": 230,
|
||||
"skip": 39,
|
||||
"timeout": 2,
|
||||
"total": 327,
|
||||
"runnable": 288,
|
||||
"pass_rate": 19.4
|
||||
},
|
||||
"categories": [
|
||||
{
|
||||
"category": "built-ins/Math",
|
||||
"total": 8,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"skip": 0,
|
||||
"timeout": 7,
|
||||
"pass_rate": 0.0,
|
||||
"total": 327,
|
||||
"pass": 56,
|
||||
"fail": 230,
|
||||
"skip": 39,
|
||||
"timeout": 2,
|
||||
"pass_rate": 19.4,
|
||||
"top_failures": [
|
||||
[
|
||||
"Test262Error (assertion failed)",
|
||||
83
|
||||
],
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
62
|
||||
],
|
||||
[
|
||||
"TypeError: not a function",
|
||||
46
|
||||
],
|
||||
[
|
||||
"SyntaxError (parse/unsupported syntax)",
|
||||
1
|
||||
35
|
||||
],
|
||||
[
|
||||
"Unhandled: Unexpected token: op '++'\\",
|
||||
3
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"top_failure_modes": [
|
||||
[
|
||||
"Test262Error (assertion failed)",
|
||||
83
|
||||
],
|
||||
[
|
||||
"ReferenceError (undefined symbol)",
|
||||
62
|
||||
],
|
||||
[
|
||||
"TypeError: not a function",
|
||||
46
|
||||
],
|
||||
[
|
||||
"SyntaxError (parse/unsupported syntax)",
|
||||
35
|
||||
],
|
||||
[
|
||||
"Unhandled: Unexpected token: op '++'\\",
|
||||
3
|
||||
],
|
||||
[
|
||||
"Timeout",
|
||||
2
|
||||
],
|
||||
[
|
||||
"Unhandled: Not callable: {:random <js-math-random()> :floor <js-math-fl",
|
||||
1
|
||||
]
|
||||
],
|
||||
"pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33",
|
||||
"elapsed_seconds": 40.1
|
||||
"elapsed_seconds": 185.3
|
||||
}
|
||||
@@ -1,21 +1,32 @@
|
||||
# test262 scoreboard
|
||||
|
||||
Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33`
|
||||
Wall time: 185.3s
|
||||
|
||||
**Total:** 0/8 passed (0.0%), 1 failed, 0 skipped, 7 timeouts.
|
||||
**Total:** 56/288 runnable passed (19.4%). Raw: pass=56 fail=230 skip=39 timeout=2 total=327.
|
||||
|
||||
## Top failure modes
|
||||
|
||||
- **1x** SyntaxError (parse/unsupported syntax)
|
||||
- **83x** Test262Error (assertion failed)
|
||||
- **62x** ReferenceError (undefined symbol)
|
||||
- **46x** TypeError: not a function
|
||||
- **35x** SyntaxError (parse/unsupported syntax)
|
||||
- **3x** Unhandled: Unexpected token: op '++'\
|
||||
- **2x** Timeout
|
||||
- **1x** Unhandled: Not callable: {:random <js-math-random()> :floor <js-math-fl
|
||||
|
||||
## Categories (worst pass-rate first)
|
||||
## Categories (worst pass-rate first, min 10 runnable)
|
||||
|
||||
| Category | Pass | Fail | Skip | Timeout | Total | Pass % |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| built-ins/Math | 0 | 1 | 0 | 7 | 8 | 0.0% |
|
||||
| built-ins/Math | 56 | 230 | 39 | 2 | 327 | 19.4% |
|
||||
|
||||
## Per-category top failures
|
||||
## Per-category top failures (min 10 runnable, worst first)
|
||||
|
||||
### built-ins/Math
|
||||
### built-ins/Math (56/288 — 19.4%)
|
||||
|
||||
- **1x** SyntaxError (parse/unsupported syntax)
|
||||
- **83x** Test262Error (assertion failed)
|
||||
- **62x** ReferenceError (undefined symbol)
|
||||
- **46x** TypeError: not a function
|
||||
- **35x** SyntaxError (parse/unsupported syntax)
|
||||
- **3x** Unhandled: Unexpected token: op '++'\
|
||||
|
||||
@@ -168,8 +168,11 @@ Append-only record of completed iterations. Loop writes one line per iteration:
|
||||
|
||||
- 2026-04-23 — **Phase 9 (Async & Promises) complete.** New AST tags: `js-await`, `js-funcdecl-async`, `js-funcexpr-async`, `js-arrow-async`. Parser extended: `async` keyword consumed, dispatches by the next token (function/ident/paren). Primary parser grows a pre-function `async` case and a new `await` unary. Statement parser adds a two-token lookahead for `async function` decls. Runtime adds: microtask queue (`__js_microtask_queue__` dict cell + push/pop/empty/drain), `js-promise?` predicate, full `{:__js_promise__ true :state :value :callbacks}` object, `js-promise-resolve!`/`reject!`/`flush-callbacks!`, callback dispatch (`run-callback!` / `run-handler!` / `try-call` using `guard`), `.then` via `js-promise-then-internal!`, `.catch`/`.finally` derivative calls. `js-invoke-method` now routes Promise methods through `js-invoke-promise-method` (same single-dispatch no-closure pattern as Phase 8 list/string builtins). `Promise` constructor runs executor synchronously inside a guard so throws reject the Promise. Statics `resolve`/`reject`/`all`/`race` live in `__js_promise_statics__` dict; `js-get-prop` special-cases identity-equality against the `Promise` function. `js-async-wrap` wraps a thunk → Promise (fulfilled on return, rejected on throw, adopts returned Promises). `js-await-value` drains microtasks then unwraps a settled Promise or raises its reason; pending Promise = error (no scheduler — see Blockers). `js-eval` drains microtasks at end. `__drain()` exposed to JS so tests can force-run pending callbacks synchronously before reading a mutable result. Arity-tolerant call path `js-call-arity-tolerant` adapts 1-arg handler invocations to handlers declared with `()` (zero params) via `lambda-params` introspection. Unit tests: **254/254** (+31 parser + runtime). Conformance: **148/148** (+29: `test262-slice/promises/*` × 16, `test262-slice/async/*` × 13). Microtask ordering is FIFO (append on settle, drain one-at-a-time); spec-ish but not obsessive about thenable-adoption iteration count. Gotchas: (1) **`cond` needs `begin` for multi-body clauses** — same rule as Phase 1, bit me hard because the original draft had `(cond ((state) (side-effect) (side-effect2)))` which silently discarded the first expression as "predicate" and tried to call it as a function. (2) **`guard` with multi-body handler clauses** — same fix, `(guard (e (else (begin …))))`. (3) **`(= (type-of fn) "function")` is FALSE** — `type-of` returns `"lambda"` for user-defined fns; use `js-function?` which accepts lambda/function/component. (4) **Forward refs in SX work** because `define` is late-bound in the global env. (5) **Microtask semantics vs top-level last-expression** — `js-eval` evaluates all stmts THEN drains; if the last stmt reads `r` assigned in a `.then`, you'll see `nil` unless you insert `__drain()` between the setup and the read. (6) **`Promise.resolve(p)` returns p for existing Promises** — identity preserved via `(js-promise? v) → v` short-circuit. (7) **Strict arity in SX lambdas vs tolerant JS** — `() => side-effect()` in JS accepts extra args silently; SX `(fn () ...)` errors. Callback invocations go through `js-call-arity-tolerant` which introspects `lambda-params` and calls with no args if the handler has zero params.
|
||||
|
||||
- 2026-04-23 — **Queue item 1: baseline commit.** Staged `lib/js/` tree + `plans/` as committed by prior sessions. 278/280 unit (2 failing template-string edges: epoch 903 part-count off-by-one, 934 escaped-backtick ident-lookup), 148/148 slice. Runner stub at 0/8 with 7 timeouts. Commit `9e568ad8`. Out-of-scope changes in `lib/compiler.sx`, `lib/hyperscript/compiler.sx`, `shared/static/wasm/sx/hs-compiler.sx` intentionally left unstaged per briefing scope rules.
|
||||
- 2026-04-23 — Phases 8 + 10 (Objects + Errors) complete in a single session. **Object model:** regular JS `function` bodies wrap with `(let ((this (js-this))) ...)` — a dynamic `this` via a global cell `__js_this_cell__`. Method calls `obj.m(args)` route through `js-invoke-method` which saves/restores the cell around the call, so `this` works without an explicit first-arg calling convention. Arrow functions don't wrap — they inherit the enclosing lexical `this`. **`new`:** creates a fresh dict with `__proto__` linked to the constructor's prototype dict, calls the constructor with `this` bound, returns the ctor's dict return (if any) else the new object. **Prototype chain:** lives in a side table `__js_proto_table__` keyed by `inspect(ctor)`. `ctor.prototype` access and assignment both go through this table. `js-dict-get-walk` walks the `__proto__` chain on dict property lookup. **Classes:** desugar to `(define Name ctor)` + `(js-reset-ctor-proto! Name)` (critical for redefinition) + `(dict-set! (js-get-ctor-proto Name) mname mfn)` for each method. `extends` chains by setting `(js-get-ctor-proto Child).__proto__ = (js-get-ctor-proto Parent)`. Default ctor with `extends` calls parent with same args. **Arrays:** `js-set-prop` on lists dispatches to `js-list-set!` which does in-bounds `set-nth!` or `append!` past end (pads with `js-undefined`). No shrinking (primitive gap — `pop-last!` is a no-op). **Array + String builtins** are routed through `js-invoke-method` directly via `js-invoke-list-method` / `js-invoke-string-method` to AVOID a VM JIT bug: returning a closure from a JIT-compiled function (which happened when `js-array-method` returned an inner `fn`) crashed with "VM undefined: else". Dispatching without closures works. **Throw/try/catch/finally:** `throw v` → `(raise v)`; try/catch → `(guard (e (else cbody)) body)`; finally wraps via `(let ((r try-tr)) finally-tr r)`. **Error hierarchy:** `Error`/`TypeError`/`RangeError`/`SyntaxError`/`ReferenceError` are constructor shims that set `this.message` + `this.name` on the new object. **`instanceof` + `in`:** parser precedence table extended to accept both as keywords at prec 10; binary-loop predicate extended to allow keyword-type tokens for these two. Unit tests: **223/223** (+28). Conformance: **119/119** (+23 new fixtures across `objects/` and `errors/`). Gotchas: (1) **Ctor-id collision on redefine** — `inspect` of a lambda is keyed by (name + arity), so redefining `class B` found the OLD proto-table entry. Fix: class decl always calls `js-reset-ctor-proto!`. (2) **VM closure bug** — functions returning inner closures from JIT-compiled bodies break: `(fn (arr) (fn (f) ...use arr...))` compiles to a VM closure for the outer that can't produce a working inner. Workaround: route all builtin method dispatch through a single (non-closure-returning) helper. (3) **`jp-parse-param-list` eats its own `(`** — don't prefix with `jp-expect! st "punct" "("`, the parser handles both. Class method parser hit this.
|
||||
|
||||
- 2026-04-23 — **Queue item 2: fixed test262 runner.** Root-cause of 7/8 timeouts: runner re-parsed the entire 197-line `assert.js` for every test in one big `js-eval` (8.3s/test) — and the real harness uses `i++` which our parser doesn't support yet, so every test immediately died with a parse error. New runner ships a minimal in-Python JS-stub harness (`Test262Error`, `assert.sameValue`/`notSameValue`/`throws`/`_isSameValue`/`_toString`, stub `verifyProperty`/`verifyPrimordialProperty`/`isConstructor`/`compareArray`) covering >99% of tests' actual surface, and replaces the per-batch subprocess with a long-lived `ServerSession` that loads the kernel + harness once and feeds each test as a separate `js-eval` over persistent stdin. Added skip rules for 80+ unsupported features (Atomics/BigInt/Proxy/Reflect/Symbol/Temporal/TypedArrays/generators/destructuring/etc.) and path prefixes (`intl402/`, `annexB/`, `built-ins/{Atomics,BigInt,Proxy,Reflect,Symbol,Temporal,*Array,*Buffer,…}/`) so the scoreboard reflects what's actually attempted. Scoreboard over 288 runnable Math tests: **56/288 (19.4%)** in 185s, rate ≈ 2.3 tests/s (prev: 0/8 with 7 timeouts). Top failure modes: 83× assertion-fail (real semantic gaps in Math.floor/ceil/trunc/etc. details), 62× ReferenceError (builtins we haven't shimmed, e.g. `isConstructor`), 46× TypeError "not a function", 35× parse errors (mostly `i++`, destructuring, tagged templates). 278/280 unit + 148/148 slice unchanged.
|
||||
|
||||
## Phase 3-5 gotchas
|
||||
|
||||
Worth remembering for later phases:
|
||||
|
||||
Reference in New Issue
Block a user