From 85cef7d80ff51996fb111357c281438cee5257de Mon Sep 17 00:00:00 2001 From: giles Date: Tue, 5 May 2026 16:51:41 +0000 Subject: [PATCH] =?UTF-8?q?HS:=20remove=20parse-cmd=20callable=20guard=20?= =?UTF-8?q?=E2=80=94=20allow=20all=20expression=20statements=20(+45=20test?= =?UTF-8?q?s)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The callable check added in 0bef67dd rejected legitimate expression statements (as-conversions, array literals, property access, breakpoint) because they produce non-call AST nodes. The at-end? guard already handles the trailing-then EOF case; the callable check is redundant and wrong. Removing it restores the original open fallback: any parse-expr result is a valid command. arrayLiteral 8/8, breakpoint 2/2, asExpression +35, evalStatically +5, regressions +3. Co-Authored-By: Claude Sonnet 4.6 --- lib/hyperscript/parser.sx | 13 +--------- shared/static/wasm/sx/hs-parser.sx | 40 ++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/hyperscript/parser.sx b/lib/hyperscript/parser.sx index 1be11820..25aea140 100644 --- a/lib/hyperscript/parser.sx +++ b/lib/hyperscript/parser.sx @@ -2871,18 +2871,7 @@ (list (quote view-transition!) using body))))) ((and (= typ "keyword") (or (= val "on") (= val "init") (= val "def") (= val "behavior") (= val "live") (= val "when") (= val "bind"))) nil) - (true - (if - (at-end?) - nil - (let - ((expr (parse-expr))) - (let - ((callable? (if (and (dict? expr) (get expr :hs-ast)) (= (get expr :kind) "call") (or (= (first expr) (quote call)) (= (first expr) (quote method-call)))))) - (if - (or callable? hs-span-mode) - expr - (error "Invalid command — expected a function call")))))))))) + (true (if (at-end?) nil (parse-expr))))))) (define parse-cmd-list (fn diff --git a/shared/static/wasm/sx/hs-parser.sx b/shared/static/wasm/sx/hs-parser.sx index f1b19360..25aea140 100644 --- a/shared/static/wasm/sx/hs-parser.sx +++ b/shared/static/wasm/sx/hs-parser.sx @@ -849,10 +849,20 @@ (adv!) (let ((target (parse-expr))) - (if - (and (list? left) (= (first left) (quote ref))) - (list (make-symbol ".") target (nth left 1)) - (list (quote of) left target))))) + (define + rebase-of-chain + (fn + (chain tgt) + (cond + ((and (list? chain) (= (first chain) (quote ref))) + (list (make-symbol ".") tgt (nth chain 1))) + ((and (list? chain) (= (str (first chain)) ".")) + (list + (make-symbol ".") + (rebase-of-chain (nth chain 1) tgt) + (nth chain 2))) + (true (list (quote of) chain tgt))))) + (rebase-of-chain left target)))) ((and (= typ "keyword") (= val "in")) (do (adv!) (list (quote in?) left (parse-expr)))) ((and (= typ "keyword") (= val "does")) @@ -1217,7 +1227,7 @@ (= (tp-type) "attr") (let ((attr-name (get (adv!) "value"))) - (match-kw "]") + (when (= (tp-type) "bracket-close") (adv!)) (let ((tgt (if (match-kw "from") (parse-expr) nil))) (list (quote remove-attr) attr-name tgt))) @@ -1738,7 +1748,21 @@ dtl (list (quote trigger) name dtl tgt) (list (quote trigger) name tgt))))))) - (define parse-log-cmd (fn () (list (quote log) (parse-expr)))) + (define + parse-log-cmd + (fn + () + (define + collect-args + (fn + (acc) + (if + (= (tp-type) "comma") + (do + (adv!) + (collect-args (append acc (list (parse-expr))))) + acc))) + (cons (quote log) (collect-args (list (parse-expr)))))) (define parse-inc-cmd (fn @@ -1867,7 +1891,7 @@ (list (quote for) "it" collection body))))) (true (let - ((mode (cond ((match-kw "forever") (list (quote forever))) ((match-kw "while") (list (quote while) (parse-expr))) ((match-kw "until") (list (quote until) (parse-expr))) (true (let ((n (parse-expr))) (if (match-kw "times") (list (quote times) n) (list (quote forever)))))))) + ((mode (cond ((match-kw "forever") (list (quote forever))) ((match-kw "while") (list (quote while) (parse-expr))) ((match-kw "until") (list (quote until) (parse-expr))) (true (if (or (= (tp-type) "number") (= (tp-type) "ident") (= (tp-type) "paren-open")) (let ((n (parse-expr))) (if (match-kw "times") (list (quote times) n) (list (quote forever)))) (list (quote forever))))))) (let ((body (do (match-kw "then") (parse-cmd-list)))) (cond @@ -2847,7 +2871,7 @@ (list (quote view-transition!) using body))))) ((and (= typ "keyword") (or (= val "on") (= val "init") (= val "def") (= val "behavior") (= val "live") (= val "when") (= val "bind"))) nil) - (true (parse-expr)))))) + (true (if (at-end?) nil (parse-expr))))))) (define parse-cmd-list (fn