HS: repeat property for-loops + where (+3 tests)

Re-applied from worktree-agent-a7c6dca2be5bbada0 (commit c4241d57)
onto HEAD that already has clusters 30, 26, 27 runtime changes —
straight cherry-pick conflicted on the cluster-30 log-all block
and cluster-27 intersection helper, so the logical diff was
replayed surgically.

Parser (parse-atom object-literal):
- obj-collect now `append`s pairs in source order instead of
  `cons`'ing, so `{foo:1, bar:2, baz:3}` reaches hs-make-object
  as `((foo 1) (bar 2) (baz 3))`.

Compiler (emit-for, array-index emission):
- emit-for detects `for x in COLL where COND` (parser wraps COLL
  as `(coll-where INNER COND)`) and rewrites the filter lambda
  to bind the for-loop variable name rather than the default
  `it`, so `where x.val > 10` sees the right binding. Also
  unwraps `coll-where` so filter targets the real inner coll.
- emit-for now wraps a symbol collection with `cek-try` (not the
  broken `hs-safe-call`, which has an uninitialised CEK call-ref
  in the WASM build) so `for prop in x` after `set x to {…}`
  iterates x's keys instead of nil.
- array-index emits `(hs-index obj key)` instead of
  `(nth obj key)`, which only worked on lists.

Runtime:
- New polymorphic `hs-index` dispatches to get / nth / host-get
  based on target type (dict / list / string / otherwise).
- `hs-put-at!` default branch now detects DOM elements via
  `hs-element?` and delegates to `hs-put!`, so `put X at end of
  elt` on a DOM node appends innerHTML instead of crashing.
- `hs-make-object` tracks insertion order in a hidden `_order`
  list; `hs-for-each` and `hs-coerce` (Keys / Entries / Map
  branches) prefer `_order` when present, filtering the marker
  out of output.

Suite hs-upstream-repeat: 25/30 → 28/30 (+3).
Smoke 0-195 unchanged at 165/195.
This commit is contained in:
2026-04-24 11:02:49 +00:00
parent 4cc2e82091
commit c932ad59e1
6 changed files with 216 additions and 114 deletions

View File

@@ -337,14 +337,33 @@
(ast)
(let
((var-name (nth ast 1))
(raw-coll (hs-to-sx (nth ast 2)))
(collection
(raw-coll-ast (nth ast 2))
(where-cond
(if
(and
(list? raw-coll-ast)
(= (first raw-coll-ast) (quote coll-where)))
(hs-to-sx (nth raw-coll-ast 2))
nil))
(inner-coll-ast
(if where-cond (nth raw-coll-ast 1) raw-coll-ast))
(raw-coll (hs-to-sx inner-coll-ast))
(safe-coll
(if
(symbol? raw-coll)
(list
(quote hs-safe-call)
(list (quote fn) (list) raw-coll))
(quote cek-try)
(list (quote fn) (list) raw-coll)
(list (quote fn) (list (quote _e)) nil))
raw-coll))
(collection
(if
where-cond
(list
(quote filter)
(list (quote fn) (list (make-symbol var-name)) where-cond)
safe-coll)
safe-coll))
(body (hs-to-sx (nth ast 3))))
(if
(and (> (len ast) 4) (= (nth ast 4) :index))
@@ -839,7 +858,7 @@
(list (quote hs-beep) (hs-to-sx (nth ast 1))))
((= head (quote array-index))
(list
(quote nth)
(quote hs-index)
(hs-to-sx (nth ast 1))
(hs-to-sx (nth ast 2))))
((= head (quote array-slice))