HS runtime + generator: make, Values, toggle styles, scoped storage, array ops, fetch coercion, scripts in PW bodies

Runtime (lib/hyperscript/ + shared/static/wasm/sx/hs-*.sx):
- make: parser accepts `<tag.class#id/>` selectors and `from <expr>,…`; compiler
  emits via scoped-set so `called <name>` persists; `called $X` lands on
  window; runtime dispatches element vs host-new constructor by type.
- Values: `x as Values` walks form inputs/selects/textareas, producing
  {name: value | [value,…]}; duplicates promote to array; multi-select and
  checkbox/radio handled.
- toggle *display/*visibility/*opacity: paired with sensible inline defaults
  in the mock DOM so toggle flips block/visible/1 ↔ none/hidden/0.
- add/remove/put at array: emit-set paths route list mutations back through
  the scoped binding; add hs-put-at! / hs-splice-at! / hs-dict-without.
- remove OBJ.KEY / KEY of OBJ: rebuild dict via hs-dict-without and reassign,
  since SX dicts are copy-on-read across the bridge.
- dom-set-data: use (host-new "Object") rather than (dict) so element-local
  storage actually persists between reads.
- fetch: hs-fetch normalizes JSON/Object/Text/Response format aliases;
  compiler sets `the-result` when wrapping a fetch in the `let ((it …))`
  chain, and __get-cmd shares one evaluation via __hs-g.

Mock DOM (tests/hs-run-filtered.js):
- parseHTMLFragments accepts void elements (<input>, <br>, …);
- setAttribute tracks name/type/checked/selected/multiple;
- select.options populated on appendChild;
- insertAdjacentHTML parses fragments and inserts real El children into the
  parent so HS-activated handlers attach.

Generator (tests/playwright/generate-sx-tests.py):
- process_hs_val strips `//` / `--` line comments before newline→then
  collapse, and strips spurious `then` before else/end/catch/finally.
- parse_dev_body interleaves window-setup ops and DOM resets between
  actions/assertions; pre-html setups still emit up front.
- generate_test_pw compiles any `<script type=text/hyperscript>` (flattened
  across JS string-concat) under guard, exposing def blocks.
- Ordered ops for `run()`-style tests check window.obj.prop via new
  _js_window_expr_to_sx; add DOM-constructing evaluate + _hyperscript
  pattern for `as Values` tests (result.key[i].toBe(…)).
- js_val_to_sx handles backticks and escapes embedded quotes.

Net delta across suites:
- if 16→18, make 0→8, toggle 12→21, add 9→10, remove 11→16, put 29→31,
  fetch 11→15, repeat 14→26, expressions/asExpression 20→25, set 27→28,
  core/scoping 12→14, when 39→39 (no regression).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 16:08:07 +00:00
parent b90aa54dd0
commit 5b100cac17
10 changed files with 1833 additions and 762 deletions

View File

@@ -353,16 +353,41 @@
emit-make
(fn
(ast)
(if
(= (len ast) 3)
(list
(quote let)
(list
(list
(make-symbol (nth ast 2))
(list (quote hs-make) (nth ast 1))))
(make-symbol (nth ast 2)))
(list (quote hs-make) (nth ast 1)))))
(let
((type-name (nth ast 1))
(called (if (>= (len ast) 3) (nth ast 2) nil))
(args (if (>= (len ast) 4) (nth ast 3) nil))
(kind (if (>= (len ast) 5) (nth ast 4) (quote auto))))
(let
((make-call (cond ((nil? args) (list (quote hs-make) type-name)) (true (cons (quote hs-make) (cons type-name (map hs-to-sx args)))))))
(cond
((and called (> (len called) 1) (= (substring called 0 1) "$"))
(list
(quote let)
(list (list (quote __hs-mk) make-call))
(list
(quote do)
(list
(quote host-set!)
(list (quote host-global) "window")
called
(quote __hs-mk))
(list (quote set!) (quote it) (quote __hs-mk))
(quote __hs-mk))))
(called
(list
(quote do)
(list (quote set!) (make-symbol called) make-call)
(list (quote set!) (quote it) (make-symbol called))
(make-symbol called)))
(true
(list
(quote let)
(list (list (quote __hs-mk) make-call))
(list
(quote do)
(list (quote set!) (quote it) (quote __hs-mk))
(quote __hs-mk)))))))))
(define
emit-inc
(fn
@@ -1182,13 +1207,38 @@
(if (nil? raw-tgt) (quote me) (hs-to-sx raw-tgt))
(nth ast 1)))))
((= head (quote remove-element))
(list (quote dom-remove) (hs-to-sx (nth ast 1))))
(let
((tgt (nth ast 1)))
(cond
((and (list? tgt) (= (first tgt) (quote array-index)))
(let
((coll (nth tgt 1)) (idx (hs-to-sx (nth tgt 2))))
(emit-set
coll
(list (quote hs-splice-at!) (hs-to-sx coll) idx))))
((and (list? tgt) (= (first tgt) dot-sym))
(let
((obj (nth tgt 1)) (prop (nth tgt 2)))
(emit-set
obj
(list (quote hs-dict-without) (hs-to-sx obj) prop))))
((and (list? tgt) (= (first tgt) (quote of)))
(let
((prop-ast (nth tgt 1)) (obj-ast (nth tgt 2)))
(let
((prop (cond ((string? prop-ast) prop-ast) ((and (list? prop-ast) (= (first prop-ast) (quote ref))) (nth prop-ast 1)) (true (hs-to-sx prop-ast)))))
(emit-set
obj-ast
(list
(quote hs-dict-without)
(hs-to-sx obj-ast)
prop)))))
(true (list (quote dom-remove) (hs-to-sx tgt))))))
((= head (quote add-value))
(let
((val (hs-to-sx (nth ast 1))) (tgt (nth ast 2)))
(list
(quote set!)
(hs-to-sx tgt)
(emit-set
tgt
(list (quote hs-add-to!) val (hs-to-sx tgt)))))
((= head (quote add-attr))
(let
@@ -1201,9 +1251,8 @@
((= head (quote remove-value))
(let
((val (hs-to-sx (nth ast 1))) (tgt (nth ast 2)))
(list
(quote set!)
(hs-to-sx tgt)
(emit-set
tgt
(list (quote hs-remove-from!) val (hs-to-sx tgt)))))
((= head (quote empty-target))
(let
@@ -1348,11 +1397,16 @@
((= head (quote set!))
(emit-set (nth ast 1) (hs-to-sx (nth ast 2))))
((= head (quote put!))
(list
(quote hs-put!)
(hs-to-sx (nth ast 1))
(nth ast 2)
(hs-to-sx (nth ast 3))))
(let
((val (hs-to-sx (nth ast 1)))
(pos (nth ast 2))
(raw-tgt (nth ast 3)))
(cond
((and (or (= pos "end") (= pos "start")) (list? raw-tgt) (or (= (first raw-tgt) (quote local)) (= (first raw-tgt) (quote ref))))
(emit-set
raw-tgt
(list (quote hs-put-at!) val pos (hs-to-sx raw-tgt))))
(true (list (quote hs-put!) val pos (hs-to-sx raw-tgt))))))
((= head (quote if))
(if
(> (len ast) 3)
@@ -1387,10 +1441,24 @@
(reduce
(fn
(body cmd)
(list
(quote let)
(list (list (quote it) cmd))
body))
(if
(and
(list? cmd)
(= (first cmd) (quote hs-fetch)))
(list
(quote let)
(list (list (quote it) cmd))
(list
(quote begin)
(list
(quote set!)
(quote the-result)
(quote it))
body))
(list
(quote let)
(list (list (quote it) cmd))
body)))
(nth compiled (- (len compiled) 1))
(rest (reverse compiled)))
(cons (quote do) compiled))))
@@ -1512,10 +1580,13 @@
(let
((val (hs-to-sx (nth ast 1))))
(list
(quote begin)
(list (quote set!) (quote the-result) val)
(list (quote set!) (quote it) val)
val)))
(quote let)
(list (list (quote __hs-g) val))
(list
(quote begin)
(list (quote set!) (quote the-result) (quote __hs-g))
(list (quote set!) (quote it) (quote __hs-g))
(quote __hs-g)))))
((= head (quote append!))
(let
((tgt (hs-to-sx (nth ast 2)))