HS-gen: string-aware line-comment stripping (+1 test)

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.
This commit is contained in:
2026-04-24 09:42:19 +00:00
parent 094945d86a
commit cb37259d10
4 changed files with 51 additions and 9 deletions

View File

@@ -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 AD 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 |

View File

@@ -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 <sel> 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 <div/>` 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 <trav>` inner-html shortcut alongside `next`/`previous`/`closest`. Suite hs-upstream-core/regressions: 10/16 → 11/16. Smoke 0-195: 162/195 → 163/195.

View File

@@ -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)

View File

@@ -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)