HS: parenthesized commands and features (+1 test)
Three parser additions so scripts like `(on click (log me) (trigger foo))` parse into a single feature with both commands in its body: 1. parse-feat: new cond branch for `paren-open` — advance, recurse parse-feat, consume `paren-close`. Allows a feature like `(on click ...)` to be grouped in parens. 2. parse-cmd: two new cond branches — on `paren-close` return nil (so cl-collect terminates at an outer group close), and on `paren-open` advance / recurse / close. Allows single parenthesized commands like `(log me)`. 3. cl-collect: previously only recursed when the next token was a recognised command keyword (`cmd-kw?`), so after `(log me)` the sibling `(trigger foo)` would end the feature body and re-surface as a top-level feature. Extended the recursion predicate to also fire when the next token is `paren-open`. Suite hs-upstream-core/parser: 9/14 -> 10/14. Smoke 0-195: 165/195 -> 166/195.
This commit is contained in:
@@ -2347,6 +2347,14 @@
|
||||
(let
|
||||
((typ (tp-type)) (val (tp-val)))
|
||||
(cond
|
||||
((= typ "paren-close") nil)
|
||||
((= typ "paren-open")
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((inner (parse-cmd)))
|
||||
(if (= (tp-type) "paren-close") (adv!) nil)
|
||||
inner)))
|
||||
((and (= typ "keyword") (or (= val "catch") (= val "finally") (= val "end") (= val "else") (= val "otherwise")))
|
||||
nil)
|
||||
((and (= typ "keyword") (= val "add"))
|
||||
@@ -2519,7 +2527,7 @@
|
||||
(list (quote if) (list (quote no) cnd) cmd))))))
|
||||
((match-kw "then")
|
||||
(cl-collect (append acc2 (list (quote __then__)))))
|
||||
((and (not (at-end?)) (= (tp-type) "keyword") (cmd-kw? (tp-val)))
|
||||
((or (and (not (at-end?)) (= (tp-type) "keyword") (cmd-kw? (tp-val))) (= (tp-type) "paren-open"))
|
||||
(cl-collect acc2))
|
||||
(true acc2)))))))
|
||||
(let
|
||||
@@ -2655,6 +2663,13 @@
|
||||
(let
|
||||
((val (tp-val)))
|
||||
(cond
|
||||
((= (tp-type) "paren-open")
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((inner (parse-feat)))
|
||||
(if (= (tp-type) "paren-close") (adv!) nil)
|
||||
inner)))
|
||||
((= val "on") (do (adv!) (parse-on-feat)))
|
||||
((= val "init") (do (adv!) (parse-init-feat)))
|
||||
((= val "def") (do (adv!) (parse-def-feat)))
|
||||
|
||||
@@ -4,10 +4,10 @@ Live tally for `plans/hs-conformance-to-100.md`. Update after every cluster comm
|
||||
|
||||
```
|
||||
Baseline: 1213/1496 (81.1%)
|
||||
Merged: 1259/1496 (84.2%) delta +46
|
||||
Merged: 1260/1496 (84.2%) delta +47
|
||||
Worktree: all landed
|
||||
Target: 1496/1496 (100.0%)
|
||||
Remaining: ~237 tests
|
||||
Remaining: ~236 tests
|
||||
```
|
||||
|
||||
## Cluster ledger
|
||||
@@ -45,7 +45,7 @@ Remaining: ~237 tests
|
||||
| 22 | window global fn fallback | blocked | — | — |
|
||||
| 23 | `me symbol works in from expressions` | done | +1 | 0d38a75b |
|
||||
| 24 | `properly interpolates values 2` | done | +1 | cb37259d |
|
||||
| 25 | parenthesized commands and features | pending | (+1 est) | — |
|
||||
| 25 | parenthesized commands and features | done | +1 | SHA-PENDING |
|
||||
|
||||
### Bucket C — feature stubs (observer mocks)
|
||||
|
||||
@@ -86,7 +86,7 @@ Defer until A–D drain. Estimated ~25 recoverable tests.
|
||||
| Bucket | Done | Partial | In-prog | Pending | Blocked | Design-done | Total |
|
||||
|--------|-----:|--------:|--------:|--------:|--------:|------------:|------:|
|
||||
| A | 12 | 4 | 0 | 0 | 1 | — | 17 |
|
||||
| B | 4 | 0 | 0 | 2 | 1 | — | 7 |
|
||||
| B | 5 | 0 | 0 | 1 | 1 | — | 7 |
|
||||
| C | 3 | 0 | 0 | 2 | 0 | — | 5 |
|
||||
| D | 0 | 0 | 0 | 5 | 0 | — | 5 |
|
||||
| E | 0 | 0 | 0 | 0 | 0 | 5 | 5 |
|
||||
|
||||
@@ -99,7 +99,7 @@ Orchestrator cherry-picks worktree commits onto `architecture` one at a time; re
|
||||
|
||||
24. **[done (+1)] `properly interpolates values 2`** — URL interpolation regression (1 test). Likely template string + property access. Expected: +1.
|
||||
|
||||
25. **[pending] `can support parenthesized commands and features`** — `parser` (1 test, Expected `clicked`). Parser needs to accept `(cmd...)` grouping in more contexts. Expected: +1.
|
||||
25. **[done (+1)] `can support parenthesized commands and features`** — `parser` (1 test, Expected `clicked`). Parser needs to accept `(cmd...)` grouping in more contexts. Expected: +1.
|
||||
|
||||
### Bucket C: feature stubs (DOM observer mocks)
|
||||
|
||||
@@ -177,6 +177,9 @@ Many tests are `SKIP (untranslated)` because `tests/playwright/generate-sx-tests
|
||||
|
||||
(Reverse chronological — newest at top.)
|
||||
|
||||
### 2026-04-24 — cluster 25 parenthesized commands and features
|
||||
- **SHA-PENDING** — `HS: parenthesized commands and features (+1 test)`. Parser-only fix in `lib/hyperscript/parser.sx`. Three additions: (a) `parse-feat` gets a new cond branch — on `paren-open`, advance, recurse `parse-feat`, consume `paren-close`; lets features like `(on click ...)` be grouped. (b) `parse-cmd` gets two new cond branches — on `paren-close` return nil (so `cl-collect` terminates when the outer paren group ends), and on `paren-open` advance+recurse+close (parenthesized single commands like `(log me)`). (c) The key missing piece: `cl-collect` previously only recursed when the next token was a recognised command keyword (`cmd-kw?`), so after the first `(log me)` the next `(trigger foo)` would end the body. Extended the recursion predicate to also fire when the next token is `paren-open`. Result: `on click (log me) (trigger foo)` now emits both commands inside the handler body, not the second as a sibling top-level feature. Suite hs-upstream-core/parser: 9/14 → 10/14. Smoke 0-195: 165/195 → 166/195.
|
||||
|
||||
### 2026-04-24 — cluster 20 repeat property for-loops + where (worktree re-apply)
|
||||
- **c932ad59** — `HS: repeat property for-loops + where (+3 tests)`. Worktree agent `a7c6dca2…` produced `c4241d57`; straight cherry-pick conflicted on runtime.sx with cluster 30's log-all block and cluster 27's intersection-attach helper, so logical diff was replayed surgically via sx-tree. Parser: `obj-collect` now `append`s pairs (not `cons`), preserving source order. Compiler: `emit-for` detects `coll-where` wrapping, binds the filter lambda to the for-loop variable name (not default `it`), and wraps symbol collections with `cek-try` instead of the broken `hs-safe-call` (uninitialised CEK call-ref in WASM). `array-index` emits `(hs-index …)` not `(nth …)`. Runtime: new polymorphic `hs-index` (dict/list/string/host dispatch); `hs-put-at!` default branch delegates to `hs-put!` when target is a DOM element; `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. Suite hs-upstream-repeat: 25/30 → 28/30 (remaining 2 are the `repeat forever` hangs we knowingly skip). Smoke 0-195 unchanged at 165.
|
||||
|
||||
|
||||
@@ -2347,6 +2347,14 @@
|
||||
(let
|
||||
((typ (tp-type)) (val (tp-val)))
|
||||
(cond
|
||||
((= typ "paren-close") nil)
|
||||
((= typ "paren-open")
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((inner (parse-cmd)))
|
||||
(if (= (tp-type) "paren-close") (adv!) nil)
|
||||
inner)))
|
||||
((and (= typ "keyword") (or (= val "catch") (= val "finally") (= val "end") (= val "else") (= val "otherwise")))
|
||||
nil)
|
||||
((and (= typ "keyword") (= val "add"))
|
||||
@@ -2519,7 +2527,7 @@
|
||||
(list (quote if) (list (quote no) cnd) cmd))))))
|
||||
((match-kw "then")
|
||||
(cl-collect (append acc2 (list (quote __then__)))))
|
||||
((and (not (at-end?)) (= (tp-type) "keyword") (cmd-kw? (tp-val)))
|
||||
((or (and (not (at-end?)) (= (tp-type) "keyword") (cmd-kw? (tp-val))) (= (tp-type) "paren-open"))
|
||||
(cl-collect acc2))
|
||||
(true acc2)))))))
|
||||
(let
|
||||
@@ -2655,6 +2663,13 @@
|
||||
(let
|
||||
((val (tp-val)))
|
||||
(cond
|
||||
((= (tp-type) "paren-open")
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((inner (parse-feat)))
|
||||
(if (= (tp-type) "paren-close") (adv!) nil)
|
||||
inner)))
|
||||
((= val "on") (do (adv!) (parse-on-feat)))
|
||||
((= val "init") (do (adv!) (parse-init-feat)))
|
||||
((= val "def") (do (adv!) (parse-def-feat)))
|
||||
|
||||
Reference in New Issue
Block a user