Commit Graph

6 Commits

Author SHA1 Message Date
4ca92960c4 Fix 13 conformance bugs: 62/109 passing (55%)
Parser:
- null-literal: null/undefined produce (null-literal) AST, not bare nil
- is a/an String!: check ! as next token, not suffix in string
- type-check! renamed to type-check-strict (! in symbol names)

Compiler:
- the first/last of: emit hs-first/hs-last instead of (get x "first")
- empty? dispatch: match parser-emitted empty?, emit hs-empty?
- modulo: emit modulo instead of % symbol

Runtime:
- hs-contains?: recursive implementation (avoids some primitive)
- hs-empty?: len-based checks (avoids empty? primitive in tree-walker)
- hs-falsy?: handles empty lists and zero
- hs-first/hs-last: wrappers for tree-walker context
- hs-type-check-strict: renamed from hs-type-check!

Test infrastructure:
- eval-hs: try-call wraps both compile AND eval steps
- Mutable _hs-result captures value through try-call boundary
- Removed DOM-dependent fixtures that cause uncatchable OCaml crashes
  (selectors <body/>, .class refs in exists/empty tests)

Scorecard: 62/109 tests passing (55%), up from 57/112.
3 fixtures removed (DOM-only crashers), net +5 passing tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:02:26 +00:00
c521ff8731 Fix hs-repeat-times: wrap when multi-body in (do ...) for IO suspension
The when form's continuation for the second body expression was lost
across perform/cek_resume cycles. Wrapping (thunk) and (do-repeat)
in an explicit (do ...) gives when a single body, and do's own
continuation handles the sequencing correctly.

Sandbox confirms: 6/6 io-sleep suspensions now chain through
host-callback → _driveAsync → resume_vm (was 1/6 before fix).

Also fix sandbox async timing: _asyncPending counter tracks in-flight
IO chains so page.evaluate waits for all resumes to complete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:31:12 +00:00
aeaa8cb498 Playwright sandbox: offline browser test environment for WASM kernel
New sx_playwright mode="sandbox" — injects the WASM kernel into about:blank
with full FFI, IO suspension tracing, and real DOM. No server needed.

Predefined stacks: core (kernel only), web (full web stack), hs (+ hyperscript),
test (+ test framework). Custom files and setup expressions supported.

Reproduces the host-callback IO suspension bug: direct callFn chains 6/6
suspensions correctly, but host-callback → addEventListener → _driveAsync
only completes 1/6. Bug is in the _driveAsync resume chain context.

Also: debug.sx mock DOM harness, test_hs_repeat.js Node.js reproduction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:24:42 +00:00
1f7f47b4c1 Fix hyperscript conformance: 54/112 passing (was 31/81 baseline)
Runtime visibility fix:
- eval-hs now injects runtime helpers (hs-add, hs-falsy?, hs-strict-eq,
  hs-type-check, hs-matches?, hs-contains?, hs-coerce) via outer let
  binding so the tree-walker evaluator can resolve them

Parser fixes:
- null/undefined: return (null-literal) AST node instead of bare nil
  (nil was indistinguishable from "no parse result" sentinel)
- === / !== tokenized as single 3-char operators
- mod operator: emit (modulo) instead of (%) — modulo is a real primitive

Compiler fixes:
- null-literal → nil
- % → modulo
- contains? → hs-contains? (avoids tree-walker primitive arity conflict)

Runtime additions:
- hs-contains?: wraps list membership + string containment

Tokenizer:
- Added keywords: a, an (removed — broke all tokenization), exist
- Triple operators: === and !== now tokenized correctly

Scorecard: 54/112 test groups passing, +23 from baseline.
Unlocked: really-equals, english comparisons, is-in, null is empty,
null exists, type checks, strict equality, mod.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:46:42 +00:00
2278443182 Hyperscript conformance: 222 test fixtures from _hyperscript 0.9.14
Extract pure expression tests from the official _hyperscript test suite
and implement parser/compiler/runtime extensions to pass them.

Test infrastructure:
- 222 fixtures extracted from evalHyperScript calls (no DOM dependency)
- SX data format with eval-hs bridge and run-hs-fixture runner
- 24 suites covering expressions, comparisons, coercion, logic, etc.

Parser extensions (parser.sx):
- mod as infix arithmetic operator
- English comparison phrases (is less than, is greater than or equal to)
- is a/an Type typecheck syntax
- === / !== strict equality operators
- I as me synonym, am as is for comparisons
- does not exist/match/contain postfix
- some/every ... with quantifier expressions
- undefined keyword → nil

Compiler updates (compiler.sx):
- + emits hs-add (type-dispatching: string concat or numeric add)
- no emits hs-falsy? (HS truthiness: empty string is falsy)
- matches? emits hs-matches? (string regex in non-DOM context)
- New cases: not-in?, in?, type-check, strict-eq, some, every

Runtime additions (runtime.sx):
- hs-coerce: Int/Integer truncation via floor
- hs-add: string concat when either operand is string
- hs-falsy?: HS-compatible truthiness (nil, false, "" are falsy)
- hs-matches?: string pattern matching
- hs-type-check/hs-type-check!: lenient/strict type checking
- hs-strict-eq: type + value equality

Tokenizer (tokenizer.sx):
- Added keywords: I, am, does, some, mod, equal, equals, really,
  include, includes, contain, undefined, exist

Scorecard: 47/112 test groups passing. 0 non-HS regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:53:50 +00:00
9a57bd5beb Step 18 (part 5): _hyperscript runtime shims — 25 functions
lib/hyperscript/runtime.sx — thin wrappers over web/lib/dom.sx
primitives implementing hyperscript-specific semantics:

Event handling: hs-on, hs-on-every, hs-init
Async/timing: hs-wait (IO suspend), hs-wait-for, hs-settle
Classes: hs-toggle-class!, hs-toggle-between!, hs-take!
DOM insertion: hs-put! (into/before/after)
Navigation: hs-navigate!, hs-next, hs-previous, hs-query-first/last
Iteration: hs-repeat-times, hs-repeat-forever
Fetch: hs-fetch (json/text/html format dispatch)
Type coercion: hs-coerce (Int/Float/String/Boolean/Array)
Object creation: hs-make (Object/Array/Set/Map)
Behaviors: hs-install
Measurement: hs-measure
Transitions: hs-transition (CSS property + optional duration)

23 runtime + 7 end-to-end pipeline tests.
3099/3099 full build, zero regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:40:55 +00:00