From e4773ec3366c9f2565b629fb949bf4bce8de165b Mon Sep 17 00:00:00 2001 From: giles Date: Thu, 23 Apr 2026 11:37:12 +0000 Subject: [PATCH] =?UTF-8?q?HS:=20split=20type-check=20(predicate)=20from?= =?UTF-8?q?=20type-assert=20(`:`)=20=E2=80=94=20+5=20comparisonOperator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last commit's `hs-type-check` rewrite collapsed predicate and assertion into one runtime fn that always raised on mismatch. That fixed `: Type` but broke `is a Type` / `is not a Type` (which need a bool): null is a String expected true, got nil (raised) null is not a String expected false, got true (default boolean) Restored the split. Parser now emits `(type-assert ...)` for `:` and keeps `(type-check ...)` for `is a` / `is not a`. Runtime adds: - `hs-type-check` — predicate, never raises (nil passes) - `hs-type-check-strict` — predicate, false on nil - `hs-type-assert` — value or raises - `hs-type-assert-strict` — value or raises (also raises on nil) Compiler maps `type-assert` / `type-assert-strict` to the new runtime fns. comparisonOperator 74/83 → 79/83 (+5: `is a/an`, `is not a/an` four tests plus a fifth that depended on them). typecheck stays 2/5 (no regression). Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/hyperscript/compiler.sx | 10 ++++++ lib/hyperscript/parser.sx | 4 +-- lib/hyperscript/runtime.sx | 54 +++++++++++++++++++--------- shared/static/wasm/sx/hs-compiler.sx | 10 ++++++ shared/static/wasm/sx/hs-parser.sx | 4 +-- shared/static/wasm/sx/hs-runtime.sx | 54 +++++++++++++++++++--------- 6 files changed, 98 insertions(+), 38 deletions(-) diff --git a/lib/hyperscript/compiler.sx b/lib/hyperscript/compiler.sx index fc3ad1e8..a501316f 100644 --- a/lib/hyperscript/compiler.sx +++ b/lib/hyperscript/compiler.sx @@ -1703,6 +1703,16 @@ (quote hs-type-check-strict) (hs-to-sx (nth ast 1)) (nth ast 2))) + ((= head (quote type-assert)) + (list + (quote hs-type-assert) + (hs-to-sx (nth ast 1)) + (nth ast 2))) + ((= head (quote type-assert-strict)) + (list + (quote hs-type-assert-strict) + (hs-to-sx (nth ast 1)) + (nth ast 2))) ((= head (quote strict-eq)) (list (quote hs-strict-eq) diff --git a/lib/hyperscript/parser.sx b/lib/hyperscript/parser.sx index 3d88a560..901c7b2a 100644 --- a/lib/hyperscript/parser.sx +++ b/lib/hyperscript/parser.sx @@ -678,8 +678,8 @@ (when strict (adv!)) (if strict - (list (quote type-check-strict) left type-name) - (list (quote type-check) left type-name))))))) + (list (quote type-assert-strict) left type-name) + (list (quote type-assert) left type-name))))))) ((and (= typ "keyword") (= val "of")) (do (adv!) diff --git a/lib/hyperscript/runtime.sx b/lib/hyperscript/runtime.sx index fd276cd1..d4d433f0 100644 --- a/lib/hyperscript/runtime.sx +++ b/lib/hyperscript/runtime.sx @@ -769,28 +769,48 @@ (dom-set-style target prop (str to-val)) (when duration (hs-settle target)))) -(define - hs-type-check - (fn - (value type-name) - (if - (nil? value) - value - (let - ((matches (cond ((= type-name "Number") (number? value)) ((= type-name "String") (string? value)) ((= type-name "Boolean") (or (= value true) (= value false))) ((= type-name "Array") (list? value)) ((= type-name "Object") (dict? value)) ((= type-name "Element") (= (host-typeof value) "element")) ((= type-name "Node") (or (= (host-typeof value) "element") (= (host-typeof value) "text"))) (true (= (host-typeof value) (downcase type-name)))))) - (if - matches - value - (raise (str "Typecheck failed! expected " type-name))))))) +(begin + (define + hs-type-check + (fn + (value type-name) + (if + (nil? value) + true + (cond + ((= type-name "Number") (number? value)) + ((= type-name "String") (string? value)) + ((= type-name "Boolean") (or (= value true) (= value false))) + ((= type-name "Array") (list? value)) + ((= type-name "Object") (dict? value)) + ((= type-name "Element") (= (host-typeof value) "element")) + ((= type-name "Node") + (or + (= (host-typeof value) "element") + (= (host-typeof value) "text"))) + (true (= (host-typeof value) (downcase type-name))))))) + (define + hs-type-assert + (fn + (value type-name) + (if + (hs-type-check value type-name) + value + (raise (str "Typecheck failed! expected " type-name))))) + (define + hs-type-assert-strict + (fn + (value type-name) + (if + (nil? value) + (raise (str "Typecheck failed! expected " type-name " but got nil")) + (hs-type-assert value type-name))))) (define hs-type-check-strict (fn (value type-name) - (if - (nil? value) - (raise (str "Typecheck failed! expected " type-name " but got nil")) - (hs-type-check value type-name)))) + (if (nil? value) false (hs-type-check value type-name)))) (define hs-strict-eq diff --git a/shared/static/wasm/sx/hs-compiler.sx b/shared/static/wasm/sx/hs-compiler.sx index fc3ad1e8..a501316f 100644 --- a/shared/static/wasm/sx/hs-compiler.sx +++ b/shared/static/wasm/sx/hs-compiler.sx @@ -1703,6 +1703,16 @@ (quote hs-type-check-strict) (hs-to-sx (nth ast 1)) (nth ast 2))) + ((= head (quote type-assert)) + (list + (quote hs-type-assert) + (hs-to-sx (nth ast 1)) + (nth ast 2))) + ((= head (quote type-assert-strict)) + (list + (quote hs-type-assert-strict) + (hs-to-sx (nth ast 1)) + (nth ast 2))) ((= head (quote strict-eq)) (list (quote hs-strict-eq) diff --git a/shared/static/wasm/sx/hs-parser.sx b/shared/static/wasm/sx/hs-parser.sx index 3d88a560..901c7b2a 100644 --- a/shared/static/wasm/sx/hs-parser.sx +++ b/shared/static/wasm/sx/hs-parser.sx @@ -678,8 +678,8 @@ (when strict (adv!)) (if strict - (list (quote type-check-strict) left type-name) - (list (quote type-check) left type-name))))))) + (list (quote type-assert-strict) left type-name) + (list (quote type-assert) left type-name))))))) ((and (= typ "keyword") (= val "of")) (do (adv!) diff --git a/shared/static/wasm/sx/hs-runtime.sx b/shared/static/wasm/sx/hs-runtime.sx index fd276cd1..d4d433f0 100644 --- a/shared/static/wasm/sx/hs-runtime.sx +++ b/shared/static/wasm/sx/hs-runtime.sx @@ -769,28 +769,48 @@ (dom-set-style target prop (str to-val)) (when duration (hs-settle target)))) -(define - hs-type-check - (fn - (value type-name) - (if - (nil? value) - value - (let - ((matches (cond ((= type-name "Number") (number? value)) ((= type-name "String") (string? value)) ((= type-name "Boolean") (or (= value true) (= value false))) ((= type-name "Array") (list? value)) ((= type-name "Object") (dict? value)) ((= type-name "Element") (= (host-typeof value) "element")) ((= type-name "Node") (or (= (host-typeof value) "element") (= (host-typeof value) "text"))) (true (= (host-typeof value) (downcase type-name)))))) - (if - matches - value - (raise (str "Typecheck failed! expected " type-name))))))) +(begin + (define + hs-type-check + (fn + (value type-name) + (if + (nil? value) + true + (cond + ((= type-name "Number") (number? value)) + ((= type-name "String") (string? value)) + ((= type-name "Boolean") (or (= value true) (= value false))) + ((= type-name "Array") (list? value)) + ((= type-name "Object") (dict? value)) + ((= type-name "Element") (= (host-typeof value) "element")) + ((= type-name "Node") + (or + (= (host-typeof value) "element") + (= (host-typeof value) "text"))) + (true (= (host-typeof value) (downcase type-name))))))) + (define + hs-type-assert + (fn + (value type-name) + (if + (hs-type-check value type-name) + value + (raise (str "Typecheck failed! expected " type-name))))) + (define + hs-type-assert-strict + (fn + (value type-name) + (if + (nil? value) + (raise (str "Typecheck failed! expected " type-name " but got nil")) + (hs-type-assert value type-name))))) (define hs-type-check-strict (fn (value type-name) - (if - (nil? value) - (raise (str "Typecheck failed! expected " type-name " but got nil")) - (hs-type-check value type-name)))) + (if (nil? value) false (hs-type-check value type-name)))) (define hs-strict-eq