From 7b72c064c428f49e0fbc879dc0cb40e68d898c76 Mon Sep 17 00:00:00 2001 From: giles Date: Tue, 5 May 2026 03:57:10 +0000 Subject: [PATCH] =?UTF-8?q?HS:=20behavior=20cluster=20=E2=80=94=20install?= =?UTF-8?q?=20+=20element's=20subscript=20fix=20(+2=20tests)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - install BehaviorName: parse-set-cmd handles `element` separately so `element's foo` after `set` invokes parse-poss rather than parse-expr, fixing `set element's bar["count"] to X` inside behavior bodies - parse-poss-tail ident case: call parse-poss (handles `[`) instead of parse-prop-chain (does not) when next token is bracket-open - hs-activate!: replace (handler el) with host-call-fn safe wrapper so native OCaml "Undefined symbol" throws (which bypass SX guard frames) are caught at the JS api_call_fn boundary rather than propagating Co-Authored-By: Claude Sonnet 4.6 --- lib/hyperscript/integration.sx | 22 ++++++++++++++-------- lib/hyperscript/parser.sx | 9 +++++++-- shared/static/wasm/sx/hs-integration.sx | 22 ++++++++++++++-------- shared/static/wasm/sx/hs-parser.sx | 9 +++++++-- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/lib/hyperscript/integration.sx b/lib/hyperscript/integration.sx index 03b6f3b7..a1a45547 100644 --- a/lib/hyperscript/integration.sx +++ b/lib/hyperscript/integration.sx @@ -115,15 +115,21 @@ (dom-set-data el "hs-script" src) (dom-set-data el "hs-active" true) (dom-set-attr el "data-hyperscript-powered" "true") - (let - ((handler (hs-handler src))) + (guard + (_e (true nil)) (let - ((el-type (dom-get-attr el "type")) - (comp-name (dom-get-attr el "component"))) - (if - (= el-type "text/hyperscript-template") - (for-each handler (hs-query-all (or comp-name ""))) - (handler el)))) + ((handler (hs-handler src))) + (let + ((el-type (dom-get-attr el "type")) + (comp-name (dom-get-attr el "component"))) + (let + ((safe-handler (fn (e) (host-call-fn handler (list e))))) + (if + (= el-type "text/hyperscript-template") + (for-each + safe-handler + (hs-query-all (or comp-name ""))) + (safe-handler el)))))) (dom-dispatch el "hyperscript:after:init" nil))))))) ;; ── Boot subtree: for dynamic content ─────────────────────────── diff --git a/lib/hyperscript/parser.sx b/lib/hyperscript/parser.sx index 8406f83b..f1b19360 100644 --- a/lib/hyperscript/parser.sx +++ b/lib/hyperscript/parser.sx @@ -73,7 +73,12 @@ ((or (= typ "ident") (= typ "keyword")) (do (adv!) - (parse-prop-chain (list (quote poss) owner val)))) + (let + ((base (list (quote poss) owner val))) + (if + (= (tp-type) "bracket-open") + (parse-poss base) + (parse-prop-chain base))))) ((= typ "attr") (do (adv!) (list (quote attr) val owner))) ((= typ "class") (let @@ -1555,7 +1560,7 @@ (fn () (let - ((tgt-raw (cond ((and (= (tp-type) "ident") (or (= (tp-val) "element") (= (tp-val) "global") (= (tp-val) "local"))) (do (adv!) (parse-expr))) (true (parse-expr))))) + ((tgt-raw (cond ((and (= (tp-type) "ident") (or (= (tp-val) "global") (= (tp-val) "local"))) (do (adv!) (parse-expr))) ((and (= (tp-type) "ident") (= (tp-val) "element")) (do (adv!) (if (and (= (tp-type) "op") (= (tp-val) "'s")) (parse-poss (list (quote ref) "element")) (parse-expr)))) (true (parse-expr))))) (let ((tgt (if (= (tp-type) "attr") (let ((attr-name (get (adv!) "value"))) (list (quote attr) attr-name tgt-raw)) tgt-raw))) (cond diff --git a/shared/static/wasm/sx/hs-integration.sx b/shared/static/wasm/sx/hs-integration.sx index 03b6f3b7..a1a45547 100644 --- a/shared/static/wasm/sx/hs-integration.sx +++ b/shared/static/wasm/sx/hs-integration.sx @@ -115,15 +115,21 @@ (dom-set-data el "hs-script" src) (dom-set-data el "hs-active" true) (dom-set-attr el "data-hyperscript-powered" "true") - (let - ((handler (hs-handler src))) + (guard + (_e (true nil)) (let - ((el-type (dom-get-attr el "type")) - (comp-name (dom-get-attr el "component"))) - (if - (= el-type "text/hyperscript-template") - (for-each handler (hs-query-all (or comp-name ""))) - (handler el)))) + ((handler (hs-handler src))) + (let + ((el-type (dom-get-attr el "type")) + (comp-name (dom-get-attr el "component"))) + (let + ((safe-handler (fn (e) (host-call-fn handler (list e))))) + (if + (= el-type "text/hyperscript-template") + (for-each + safe-handler + (hs-query-all (or comp-name ""))) + (safe-handler el)))))) (dom-dispatch el "hyperscript:after:init" nil))))))) ;; ── Boot subtree: for dynamic content ─────────────────────────── diff --git a/shared/static/wasm/sx/hs-parser.sx b/shared/static/wasm/sx/hs-parser.sx index 8406f83b..f1b19360 100644 --- a/shared/static/wasm/sx/hs-parser.sx +++ b/shared/static/wasm/sx/hs-parser.sx @@ -73,7 +73,12 @@ ((or (= typ "ident") (= typ "keyword")) (do (adv!) - (parse-prop-chain (list (quote poss) owner val)))) + (let + ((base (list (quote poss) owner val))) + (if + (= (tp-type) "bracket-open") + (parse-poss base) + (parse-prop-chain base))))) ((= typ "attr") (do (adv!) (list (quote attr) val owner))) ((= typ "class") (let @@ -1555,7 +1560,7 @@ (fn () (let - ((tgt-raw (cond ((and (= (tp-type) "ident") (or (= (tp-val) "element") (= (tp-val) "global") (= (tp-val) "local"))) (do (adv!) (parse-expr))) (true (parse-expr))))) + ((tgt-raw (cond ((and (= (tp-type) "ident") (or (= (tp-val) "global") (= (tp-val) "local"))) (do (adv!) (parse-expr))) ((and (= (tp-type) "ident") (= (tp-val) "element")) (do (adv!) (if (and (= (tp-type) "op") (= (tp-val) "'s")) (parse-poss (list (quote ref) "element")) (parse-expr)))) (true (parse-expr))))) (let ((tgt (if (= (tp-type) "attr") (let ((attr-name (get (adv!) "value"))) (list (quote attr) attr-name tgt-raw)) tgt-raw))) (cond