From cb37259d1005a0abc5e60c1dbab8691b06abbd7f Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 24 Apr 2026 09:42:19 +0000 Subject: [PATCH] HS-gen: string-aware line-comment stripping (+1 test) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit process_hs_val stripped `//…` line comments with a naïve regex, which devoured `https://yyy.xxxxxx.com/…` inside a backtick template — the 'properly interpolates values 2' fixture was landing with the HS source truncated at `https:`. New helper _strip_hs_line_comments walks char-by-char and only strips `//` / leading-whitespace `--` when not inside `'…'`, `"…"`, or backticks; respects `\\`-escapes inside strings. Suite hs-upstream-core/regressions: 11/16 → 12/16. Smoke 0-195: 163/195 → 164/195. --- plans/hs-conformance-scoreboard.md | 8 ++--- plans/hs-conformance-to-100.md | 5 ++- spec/tests/test-hyperscript-behavioral.sx | 4 +-- tests/playwright/generate-sx-tests.py | 43 +++++++++++++++++++++-- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/plans/hs-conformance-scoreboard.md b/plans/hs-conformance-scoreboard.md index eadff348..7ab1409c 100644 --- a/plans/hs-conformance-scoreboard.md +++ b/plans/hs-conformance-scoreboard.md @@ -4,10 +4,10 @@ Live tally for `plans/hs-conformance-to-100.md`. Update after every cluster comm ``` Baseline: 1213/1496 (81.1%) -Merged: 1248/1496 (83.4%) delta +35 +Merged: 1249/1496 (83.5%) delta +36 Worktree: all merged Target: 1496/1496 (100.0%) -Remaining: ~248 tests +Remaining: ~247 tests ``` ## Cluster ledger @@ -44,7 +44,7 @@ Remaining: ~248 tests | 21 | `possessiveExpression` property access via its | done | +1 | f0c41278 | | 22 | window global fn fallback | blocked | — | — | | 23 | `me symbol works in from expressions` | done | +1 | 0d38a75b | -| 24 | `properly interpolates values 2` | pending | (+1 est) | — | +| 24 | `properly interpolates values 2` | done | +1 | (pending) | | 25 | parenthesized commands and features | pending | (+1 est) | — | ### 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 | 2 | 0 | 0 | 4 | 1 | — | 7 | +| B | 3 | 0 | 0 | 3 | 1 | — | 7 | | C | 0 | 0 | 0 | 5 | 0 | — | 5 | | D | 0 | 0 | 0 | 5 | 0 | — | 5 | | E | 0 | 0 | 0 | 0 | 0 | 5 | 5 | diff --git a/plans/hs-conformance-to-100.md b/plans/hs-conformance-to-100.md index 367723a6..423960a9 100644 --- a/plans/hs-conformance-to-100.md +++ b/plans/hs-conformance-to-100.md @@ -82,7 +82,7 @@ Each cluster below is one commit. Order is rough — a loop agent may skip ahead 23. **[done (+1)] `me symbol works in from expressions`** — `regressions` (1 test, Expected `Foo`). Check `from` expression compilation. Expected: +1. -24. **[pending] `properly interpolates values 2`** — URL interpolation regression (1 test). Likely template string + property access. Expected: +1. +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. @@ -162,6 +162,9 @@ Many tests are `SKIP (untranslated)` because `tests/playwright/generate-sx-tests (Reverse chronological — newest at top.) +### 2026-04-24 — cluster 24 properly interpolates values 2 +- **COMMIT** — `HS-gen: string-aware line-comment stripping (+1 test)`. `process_hs_val` in `tests/playwright/generate-sx-tests.py` stripped `//…` line comments with a naïve regex, which devoured `https://yyy.xxxxxx.com/…` inside a backtick template — test 2074 was landing with the HS source truncated at `https:`. New helper `_strip_hs_line_comments` walks char-by-char and only strips `//` / leading-whitespace `--` when not inside `'…'`, `"…"`, or `` `…` ``; also respects `\\`-escapes inside strings. Regen produced full template intact. Suite hs-upstream-core/regressions: 11/16 → 12/16. Smoke 0-195: 163/195 → 164/195. + ### 2026-04-24 — cluster 23 me symbol works in from expressions - **0d38a75b** — `HS: closest parent traversal (+1 test)`. `parse-trav` now recognises `parent` as an ident modifier after the `closest` keyword: consumes it and re-invokes itself with kind `closest-parent`, so `closest parent
` produces AST `(closest-parent "div" (me))` instead of `(string-postfix (closest "*" (me)) "parent")` — the latter was the generic trailing-ident-as-unit rule swallowing `parent`. Compiler translates `(closest-parent sel target)` to `(dom-closest (host-get target "parentElement") sel)` so `me` (the element with the `_` attribute) is skipped and only strict ancestors match. Also added `closest-parent` to the `put X into ` inner-html shortcut alongside `next`/`previous`/`closest`. Suite hs-upstream-core/regressions: 10/16 → 11/16. Smoke 0-195: 162/195 → 163/195. diff --git a/spec/tests/test-hyperscript-behavioral.sx b/spec/tests/test-hyperscript-behavioral.sx index fdf7288f..74250305 100644 --- a/spec/tests/test-hyperscript-behavioral.sx +++ b/spec/tests/test-hyperscript-behavioral.sx @@ -2070,7 +2070,7 @@ (deftest "properly interpolates values 2" (hs-cleanup!) (let ((_el-button (dom-create-element "button"))) - (dom-set-attr _el-button "_" "on click set trackingcode to `AB123456789KK` then set pdfurl to `https:") + (dom-set-attr _el-button "_" "on click set trackingcode to `AB123456789KK` then set pdfurl to `https://yyy.xxxxxx.com/path/out/${trackingcode}.pdf` then put pdfurl into me") (dom-append (dom-body) _el-button) (hs-activate! _el-button) (dom-dispatch _el-button "click" nil) @@ -11019,7 +11019,7 @@ (deftest "handles set url regression properly" (hs-cleanup!) (let ((_el-div (dom-create-element "div"))) - (dom-set-attr _el-div "_" "on click set trackingcode to `foo` then set pdfurl to `https:") + (dom-set-attr _el-div "_" "on click set trackingcode to `foo` then set pdfurl to `https://yyy.xxxxxx.com/path/out/${trackingcode}.pdf` then put pdfurl into me") (dom-set-inner-html _el-div "lolwat") (dom-append (dom-body) _el-div) (hs-activate! _el-div) diff --git a/tests/playwright/generate-sx-tests.py b/tests/playwright/generate-sx-tests.py index 15aa36d0..9ecba83c 100644 --- a/tests/playwright/generate-sx-tests.py +++ b/tests/playwright/generate-sx-tests.py @@ -1177,6 +1177,45 @@ def parse_dev_body(body, elements, var_names): # ── Test generation ─────────────────────────────────────────────── +def _strip_hs_line_comments(s): + """Strip `//…` and `--…` line comments outside HS string literals. + + HS has three string delimiters: single quotes, double quotes, and + backticks (template strings). `https://…` inside a backtick must not + be treated as a comment. + """ + out = [] + i = 0 + n = len(s) + in_str = None # None | "'" | '"' | '`' + while i < n: + ch = s[i] + if in_str is None: + # Check for line-comment starters at depth 0. + if ch == '/' and i + 1 < n and s[i + 1] == '/': + # Skip to newline. + while i < n and s[i] != '\n': + i += 1 + continue + if ch == '-' and i + 1 < n and s[i + 1] == '-' and (i == 0 or s[i - 1].isspace()): + while i < n and s[i] != '\n': + i += 1 + continue + if ch in ("'", '"', '`'): + in_str = ch + out.append(ch) + i += 1 + else: + if ch == '\\' and i + 1 < n: + out.append(ch); out.append(s[i + 1]); i += 2 + continue + if ch == in_str: + in_str = None + out.append(ch) + i += 1 + return ''.join(out) + + def process_hs_val(hs_val): """Process a raw HS attribute value: collapse whitespace, insert 'then' separators.""" # Convert escaped newlines/tabs to real whitespace @@ -1187,8 +1226,8 @@ def process_hs_val(hs_val): hs_val = hs_val.replace('\x00QUOT\x00', '\\"') # Strip line comments BEFORE newline collapse — once newlines become `then`, # an unterminated `//` / ` --` comment would consume the rest of the input. - hs_val = re.sub(r'//[^\n]*', '', hs_val) - hs_val = re.sub(r'(^|\s)--[^\n]*', r'\1', hs_val) + # String-aware: `https://…` inside a backtick template must not be stripped. + hs_val = _strip_hs_line_comments(hs_val) cmd_kws = r'(?:set|put|get|add|remove|toggle|hide|show|if|repeat|for|wait|send|trigger|log|call|take|throw|return|append|tell|go|halt|settle|increment|decrement|fetch|make|install|measure|empty|reset|swap|default|morph|render|scroll|focus|select|pick|beep!)' hs_val = re.sub(r'\s{2,}(?=' + cmd_kws + r'\b)', ' then ', hs_val) hs_val = re.sub(r'\s*[\n\r]\s*', ' then ', hs_val)