Three new socket tests passing:
- dispatchEvent: sends JSON-encoded event via wrapper.raw.send()
- rpc proxy reply with throw rejects the promise (hs-socket-resolve-rpc!)
- rpc reconnects: close listener sets closedFlag, _hsRpcCall creates fresh ws
Key fixes:
- _sent changed from JS Array to plain object {_len:0, 0:msg, ...} — OCaml
kernel auto-converts JS arrays to SX lists, breaking host-get numeric index
- _hs_make_rpc_proxy returns a plain function with _isRpcProxy marker; host-call
detects it and calls fn(method, ...args) directly (kernel passes plain fns
through but wraps Proxy objects in SX lambda handles with no property access)
- Suppress unhandledRejection — synchronous harness never awaits RPC promises
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- hs-id= uses JS === for DOM elements (hs-ref-eq), = for scalars
- != operator now uses hs-id= for structural correctness
- compound tag[attr=val] selector matching in test runner
- dom-query-all replaces host-call querySelectorAll
- DOM tree structure corrected in 4 generated tests (elements were
appended to wrong parents)
Generator emit_eval translates arr.reduce/map/filter to SX primitives
so SX list args work. host-call-fn sxToJs converts SX lists to native
JS arrays for native JS function calls. Fixes functionCalls
"can pass an array literal as an argument".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
hs-make-object no longer appends _order to every HS object literal.
Generator emit_eval now uses assert-equal (equal?) for dict-containing
expected values instead of assert= (= reference equality).
Together these fix arrayLiteral "arrays containing objects work".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
empty .class compiled (empty-target (query ".class")) to
(hs-empty-target! (hs-query-first ".class")) via hs-to-sx — only
emptying the first match. Fix: detect (query ...) target in the
empty-target compiler case and emit (for-each (fn (_el)
(hs-empty-target! _el)) (hs-query-all sel)) instead, mirroring the
add-class pattern. Suite hs-upstream-empty: 12/13 → 13/13.
Smoke 0-195: 175/195 unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
${}{"val"} pattern in add {prop: ${}{"val"}} uses two consecutive brace
groups: empty ${} followed by {"val"} for the actual expression. The prior
fix called parse-expr when already at the brace-close of the empty group,
returning nil. New fix: detect empty ${} (brace-open then brace-close),
skip the close, then read the actual value from the following {…} block.
Also handles non-empty ${expr} directly as before.
Suite hs-upstream-add: 17/19 → 18/19. Smoke 0-195: 174/195 → 175/195.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
call X then put it into Y was emitting (hs-win-call ...) without
wrapping in emit-set, so it remained nil. Wrap call result in
emit-set(the-result) so it/the-result are updated. Fixes +1 test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches OCaml run_tests.ml which binds these as NativeFn returning
"foo"/"42" directly. hs-win-call looks up window globals; registering
them synchronously lets put/set tests exercise function-call + put
without requiring real Promise awaiting. Fixes "waits on promises" +1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents click events from bubbling into ancestor elements that also
have hs handlers (e.g. parent re-inserting HTML after child click).
Fixes put-reprocessing tests 1147/1149/1150 (+3 tests).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Native JS wrapper: replace SX dict with (host-new "Object") so
host-set! mutations persist for rpc and closed? updates. bind-path!
uses (host-new "Object") for intermediate namespace nodes so dotted
paths like MyApp.chat bind correctly. Fix _hs_make_rpc_proxy call
wrapper to strip the nil this-arg. Land tests 4+16: namespaced sockets
work, with timeout parses and uses the configured timeout. 5/16 total.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add hs-tokenize-template: scans " as single STRING token, ${ ... }
as dollar+brace+inner-tokens (inner tokenized with hs-tokenize), and
} as brace-close. Update hs-tokens-of to call hs-tokenize-template
when :template keyword arg is passed. Unlocks tests 1 and 15.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add \r \b \f \v and \xNN escape handling to read-string. Use
char-from-code for non-SX-literal chars. Throw "Unterminated string"
on EOF inside a string literal. Throw "Invalid hexadecimal escape: \x"
on bad \xNN. Add hs-hex-digit? and hs-hex-val helpers. Unlocks
tests 2, 6, 13, 14 once generator lands.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add hs-eof-sentinel, hs-op-type, hs-raw->api-token, hs-tokens-of,
hs-stream-token, hs-stream-consume, hs-stream-has-more, and the
three token accessors (hs-token-type, hs-token-value, hs-token-op?).
No test delta yet — API-only, generator comes in step 6.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`1 in [1, 2, 3]` must return (list 1) not true. Root cause: in? compiled
to hs-contains? which returns boolean for scalar items. Fix: new hs-in?
returns filtered list; new in-bool? operator for is/am-in comparison
contexts so those still return boolean. Parser generates in-bool? for
`X is in Y` / `X am in Y`; plain `in` keeps in? → list return.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Mark cluster 22 done (+1): can refer to function in init blocks
- Scoreboard: merged 1280→1302 (+22 from stale rows 22/29/32/33/34/35)
- Fix stale rows: clusters 29 partial, 32 done, 33 partial+4, 34 partial+7, 35 done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove guard wrapper from hs-win-call emit (direct call is sufficient now)
- def command also registers fn on window[name] so hs-win-call finds it
- Generator: fix \"-escaped quotes in hs-compile string literal (was splitting "here" into three SX nodes)
- Hand-rolled deftest for 'can refer to function in init blocks' now passes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add host-call-fn FFI primitive to test runner (calls SX lambdas or JS fns)
- Add hs-win-call runtime helper: looks up fn by name in window globals
- Compiler call case: emit guard-wrapped hs-win-call for bare (ref ...) calls
- Compiler method-call else: same guard pattern for non-dot method calls
- Compiler do case: hoist define forms before init/other forms (def hoisting)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three orthogonal fixes that pick up tests now unblocked by earlier
cluster-34 (count filters) and cluster-35 (hs-method-call fallback) work:
(1) parser.sx parse-hide-cmd / parse-show-cmd — added `on` to the keyword
list that signals an implicit-`me` target. Without this, `on click 1
hide on click 2 show` silently parsed as `(hide nil)` because parse-expr
greedily started consuming `on` and returned nil. With the bail-out,
hide/show default to me when the next token is `on` (a sibling feature).
(2) runtime.sx hs-method-call fallback — when method isn't a built-in
collection op, look up obj[method] via host-get; if it's an SX-callable
(lambda) use apply, but if it's a JS-native function (e.g. cookies.clear
on the cookies Proxy) dispatch via `(apply host-call (cons obj (cons
method args)))` so the JS native receives the args correctly. SX
callable? returns false for JS-native function values, hence the split.
(3) generator hs-cleanup! — wrapped body in begin (fn body evaluates
only the last expression) and reset two pieces of mutable global runtime
state between tests: hs-set-default-hide-strategy! nil and
hs-set-log-all! false. The prior `can set default to custom strategy`
test (cluster 11) was leaking _hs-default-hide-strategy to subsequent
tests, breaking `hide element then show element retains original
display` because hs-hide-one! resolved its "display" strategy through
the leaked override.
Also added cluster-33 hand-roll for `basic clear cookie values work`
(uses the new method-call fallback to dispatch cookies.clear via
host-call).
hs-upstream-hide: 15/16 → 16/16. hs-upstream-expressions/cookies: 3/5
→ 4/5. Smoke 0-195 unchanged at 172/195.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>