HS: return via raise/guard, def param fix, script block extraction
- Compiler: return compiles to (raise (list "hs-return" value))
- Compiler: def wraps body in guard to catch hs-return exceptions
- Compiler: def params extract name from (ref name) nodes
- Test generator: extract <script type="text/hyperscript"> blocks
and compile def functions as setup before tests
- Test generator: add eval-hs-with-me for {me: N} opts
The return mechanism enables repeat-forever with early exit via return.
Direct SX guard/raise works (returns correct value), but the compiled
HS repeat-forever thunk body needs further debugging for full coverage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1035,7 +1035,15 @@
|
|||||||
((fn-expr (hs-to-sx (nth ast 1)))
|
((fn-expr (hs-to-sx (nth ast 1)))
|
||||||
(args (map hs-to-sx (nth ast 2))))
|
(args (map hs-to-sx (nth ast 2))))
|
||||||
(cons fn-expr args)))
|
(cons fn-expr args)))
|
||||||
((= head (quote return)) (hs-to-sx (nth ast 1)))
|
((= head (quote return))
|
||||||
|
(let
|
||||||
|
((val (nth ast 1)))
|
||||||
|
(if
|
||||||
|
(nil? val)
|
||||||
|
(list (quote raise) (list (quote list) "hs-return" nil))
|
||||||
|
(list
|
||||||
|
(quote raise)
|
||||||
|
(list (quote list) "hs-return" (hs-to-sx val))))))
|
||||||
((= head (quote throw))
|
((= head (quote throw))
|
||||||
(list (quote raise) (hs-to-sx (nth ast 1))))
|
(list (quote raise) (hs-to-sx (nth ast 1))))
|
||||||
((= head (quote settle))
|
((= head (quote settle))
|
||||||
@@ -1106,13 +1114,41 @@
|
|||||||
(quote hs-init)
|
(quote hs-init)
|
||||||
(list (quote fn) (list) (hs-to-sx (nth ast 1)))))
|
(list (quote fn) (list) (hs-to-sx (nth ast 1)))))
|
||||||
((= head (quote def))
|
((= head (quote def))
|
||||||
(list
|
(let
|
||||||
(quote define)
|
((body (hs-to-sx (nth ast 3)))
|
||||||
(make-symbol (nth ast 1))
|
(params
|
||||||
|
(map
|
||||||
|
(fn
|
||||||
|
(p)
|
||||||
|
(if
|
||||||
|
(and (list? p) (= (first p) (quote ref)))
|
||||||
|
(make-symbol (nth p 1))
|
||||||
|
(make-symbol p)))
|
||||||
|
(nth ast 2))))
|
||||||
(list
|
(list
|
||||||
(quote fn)
|
(quote define)
|
||||||
(map make-symbol (nth ast 2))
|
(make-symbol (nth ast 1))
|
||||||
(hs-to-sx (nth ast 3)))))
|
(list
|
||||||
|
(quote fn)
|
||||||
|
params
|
||||||
|
(list
|
||||||
|
(quote guard)
|
||||||
|
(list
|
||||||
|
(quote _e)
|
||||||
|
(list
|
||||||
|
(quote true)
|
||||||
|
(list
|
||||||
|
(quote if)
|
||||||
|
(list
|
||||||
|
(quote and)
|
||||||
|
(list (quote list?) (quote _e))
|
||||||
|
(list
|
||||||
|
(quote =)
|
||||||
|
(list (quote first) (quote _e))
|
||||||
|
"hs-return"))
|
||||||
|
(list (quote nth) (quote _e) 1)
|
||||||
|
(list (quote raise) (quote _e)))))
|
||||||
|
body)))))
|
||||||
((= head (quote behavior)) (emit-behavior ast))
|
((= head (quote behavior)) (emit-behavior ast))
|
||||||
((= head (quote sx-eval))
|
((= head (quote sx-eval))
|
||||||
(let
|
(let
|
||||||
|
|||||||
@@ -1826,12 +1826,10 @@
|
|||||||
))
|
))
|
||||||
(deftest "repeat forever works"
|
(deftest "repeat forever works"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def repeatForeverWithReturn() set retVal to 0 repeat forever set retVal to retVal + 1 if retVal == 5 then return retVal end end end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def repeatForeverWithReturn() set retVal to 0 repeat forever set retVal to retVal + 1 if retVal == 5 then return retVal end end end")
|
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-set-attr _el-d1 "_" "on click put repeatForeverWithReturn() into my.innerHTML")
|
(dom-set-attr _el-d1 "_" "on click put repeatForeverWithReturn() into my.innerHTML")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-d1)
|
(hs-activate! _el-d1)
|
||||||
(dom-dispatch _el-d1 "click" nil)
|
(dom-dispatch _el-d1 "click" nil)
|
||||||
@@ -1839,12 +1837,10 @@
|
|||||||
))
|
))
|
||||||
(deftest "repeat forever works w/o keyword"
|
(deftest "repeat forever works w/o keyword"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def repeatForeverWithReturn() set retVal to 0 repeat set retVal to retVal + 1 if retVal == 5 then return retVal end end end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def repeatForeverWithReturn() set retVal to 0 repeat set retVal to retVal + 1 if retVal == 5 then return retVal end end end")
|
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-set-attr _el-d1 "_" "on click put repeatForeverWithReturn() into my.innerHTML")
|
(dom-set-attr _el-d1 "_" "on click put repeatForeverWithReturn() into my.innerHTML")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-d1)
|
(hs-activate! _el-d1)
|
||||||
(dom-dispatch _el-d1 "click" nil)
|
(dom-dispatch _el-d1 "click" nil)
|
||||||
@@ -1879,12 +1875,10 @@
|
|||||||
))
|
))
|
||||||
(deftest "while keyword works"
|
(deftest "while keyword works"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def repeatWhileTest() set retVal to 0 repeat while retVal < 5 set retVal to retVal + 1 end return retVal end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def repeatWhileTest() set retVal to 0 repeat while retVal < 5 set retVal to retVal + 1 end return retVal end")
|
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-set-attr _el-d1 "_" "on click put repeatWhileTest() into my.innerHTML")
|
(dom-set-attr _el-d1 "_" "on click put repeatWhileTest() into my.innerHTML")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-d1)
|
(hs-activate! _el-d1)
|
||||||
(dom-dispatch _el-d1 "click" nil)
|
(dom-dispatch _el-d1 "click" nil)
|
||||||
@@ -1892,12 +1886,10 @@
|
|||||||
))
|
))
|
||||||
(deftest "until keyword works"
|
(deftest "until keyword works"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def repeatUntilTest() set retVal to 0 repeat until retVal == 5 set retVal to retVal + 1 end return retVal end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def repeatUntilTest() set retVal to 0 repeat until retVal == 5 set retVal to retVal + 1 end return retVal end")
|
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-set-attr _el-d1 "_" "on click put repeatUntilTest() into my.innerHTML")
|
(dom-set-attr _el-d1 "_" "on click put repeatUntilTest() into my.innerHTML")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-d1)
|
(hs-activate! _el-d1)
|
||||||
(dom-dispatch _el-d1 "click" nil)
|
(dom-dispatch _el-d1 "click" nil)
|
||||||
@@ -1905,23 +1897,19 @@
|
|||||||
))
|
))
|
||||||
(deftest "until event keyword works"
|
(deftest "until event keyword works"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-untilTest (dom-create-element "div")) (_el-script (dom-create-element "script")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def repeatUntilTest() repeat until event click from #untilTest wait 2ms end return 42 end")))
|
||||||
|
(let ((_el-untilTest (dom-create-element "div")))
|
||||||
(dom-set-attr _el-untilTest "id" "untilTest")
|
(dom-set-attr _el-untilTest "id" "untilTest")
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def repeatUntilTest() repeat until event click from #untilTest wait 2ms end return 42 end")
|
|
||||||
(dom-append (dom-body) _el-untilTest)
|
(dom-append (dom-body) _el-untilTest)
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-dispatch _el-untilTest "click" nil)
|
(dom-dispatch _el-untilTest "click" nil)
|
||||||
;; SKIP check: skip value.should.equal(42)
|
;; SKIP check: skip value.should.equal(42)
|
||||||
))
|
))
|
||||||
(deftest "only executes the init expression once"
|
(deftest "only executes the init expression once"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def getArray() set window.called to (window.called or 0) + 1 return [1, 2, 3] end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def getArray() set window.called to (window.called or 0) + 1 return [1, 2, 3] end")
|
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-set-attr _el-d1 "_" "on click for x in getArray() put x into my.innerHTML end")
|
(dom-set-attr _el-d1 "_" "on click for x in getArray() put x into my.innerHTML end")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-d1)
|
(hs-activate! _el-d1)
|
||||||
(dom-dispatch _el-d1 "click" nil)
|
(dom-dispatch _el-d1 "click" nil)
|
||||||
@@ -1930,12 +1918,10 @@
|
|||||||
))
|
))
|
||||||
(deftest "can nest loops"
|
(deftest "can nest loops"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def sprayInto(elt) for x in [1, 2, 3] for y in [1, 2, 3] put x * y at end of elt end end end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def sprayInto(elt) for x in [1, 2, 3] for y in [1, 2, 3] put x * y at end of elt end end end")
|
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-set-attr _el-d1 "_" "on click call sprayInto(me)")
|
(dom-set-attr _el-d1 "_" "on click call sprayInto(me)")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-d1)
|
(hs-activate! _el-d1)
|
||||||
(dom-dispatch _el-d1 "click" nil)
|
(dom-dispatch _el-d1 "click" nil)
|
||||||
@@ -3669,11 +3655,9 @@
|
|||||||
))
|
))
|
||||||
(deftest "can be in a top level script tag"
|
(deftest "can be in a top level script tag"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-loadedDemo (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "on load put \"Loaded\" into #loadedDemo.innerHTML")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-loadedDemo (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "on load put \"Loaded\" into #loadedDemo.innerHTML")
|
|
||||||
(dom-set-attr _el-loadedDemo "id" "loadedDemo")
|
(dom-set-attr _el-loadedDemo "id" "loadedDemo")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-loadedDemo)
|
(dom-append (dom-body) _el-loadedDemo)
|
||||||
;; SKIP check: skip byId("loadedDemo").innerText.should.equal("Loaded")
|
;; SKIP check: skip byId("loadedDemo").innerText.should.equal("Loaded")
|
||||||
))
|
))
|
||||||
@@ -4043,11 +4027,9 @@
|
|||||||
))
|
))
|
||||||
(deftest "can catch exceptions thrown in hyperscript functions"
|
(deftest "can catch exceptions thrown in hyperscript functions"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-button (dom-create-element "button")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def throwBar() throw 'bar' end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-button (dom-create-element "button")))
|
||||||
(dom-set-inner-html _el-script "def throwBar() throw 'bar' end")
|
|
||||||
(dom-set-attr _el-button "_" "on click throwBar() catch e put e into me")
|
(dom-set-attr _el-button "_" "on click throwBar() catch e put e into me")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-button)
|
(dom-append (dom-body) _el-button)
|
||||||
(hs-activate! _el-button)
|
(hs-activate! _el-button)
|
||||||
(dom-dispatch _el-button "click" nil)
|
(dom-dispatch _el-button "click" nil)
|
||||||
@@ -4259,205 +4241,119 @@
|
|||||||
(assert= (dom-inner-html _el-div) "42")
|
(assert= (dom-inner-html _el-div) "42")
|
||||||
))
|
))
|
||||||
(deftest "can define an init block in a script"
|
(deftest "can define an init block in a script"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "init set window.foo to 42 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.foo.should.equal(42)
|
|
||||||
))
|
|
||||||
(deftest "can initialize immediately"
|
(deftest "can initialize immediately"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "init set window.foo to 10 init immediately set window.bar to window.foo")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.foo.should.equal(10)
|
|
||||||
))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
;; ── def (27 tests) ──
|
;; ── def (27 tests) ──
|
||||||
(defsuite "hs-upstream-def"
|
(defsuite "hs-upstream-def"
|
||||||
(deftest "can define a basic no arg function"
|
(deftest "can define a basic no arg function"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def foo() add .called to #d1 end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def foo() add .called to #d1 end")
|
|
||||||
(dom-set-attr _el-div "_" "on click call foo()")
|
(dom-set-attr _el-div "_" "on click call foo()")
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
(dom-dispatch _el-script "click" nil)
|
(dom-dispatch _el-div "click" nil)
|
||||||
(assert (dom-has-class? _el-div "called"))
|
(assert (dom-has-class? _el-div "called"))
|
||||||
))
|
))
|
||||||
(deftest "can define a basic one arg function"
|
(deftest "can define a basic one arg function"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def foo(str) put str into #d1.innerHTML end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def foo(str) put str into #d1.innerHTML end")
|
|
||||||
(dom-set-attr _el-div "_" "on click call foo(\"called\")")
|
(dom-set-attr _el-div "_" "on click call foo(\"called\")")
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
(dom-dispatch _el-script "click" nil)
|
(dom-dispatch _el-div "click" nil)
|
||||||
(assert= (dom-inner-html _el-div) "called")
|
(assert= (dom-inner-html _el-div) "called")
|
||||||
))
|
))
|
||||||
(deftest "functions can be namespaced"
|
(deftest "functions can be namespaced"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def utils.foo() add .called to #d1 end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def utils.foo() add .called to #d1 end")
|
|
||||||
(dom-set-attr _el-div "_" "on click call utils.foo()")
|
(dom-set-attr _el-div "_" "on click call utils.foo()")
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
(dom-dispatch _el-script "click" nil)
|
(dom-dispatch _el-div "click" nil)
|
||||||
(assert (dom-has-class? _el-div "called"))
|
(assert (dom-has-class? _el-div "called"))
|
||||||
))
|
))
|
||||||
(deftest "is called synchronously"
|
(deftest "is called synchronously"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def foo() log meend")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def foo() log meend")
|
|
||||||
(dom-set-attr _el-div "_" "on click call foo() then add .called to #d1")
|
(dom-set-attr _el-div "_" "on click call foo() then add .called to #d1")
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
(dom-dispatch _el-script "click" nil)
|
(dom-dispatch _el-div "click" nil)
|
||||||
(assert (dom-has-class? _el-div "called"))
|
(assert (dom-has-class? _el-div "called"))
|
||||||
))
|
))
|
||||||
(deftest "can call asynchronously"
|
(deftest "can call asynchronously"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 1ms log meend")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def foo() wait 1ms log meend")
|
|
||||||
(dom-set-attr _el-div "_" "on click call foo() then add .called to #d1")
|
(dom-set-attr _el-div "_" "on click call foo() then add .called to #d1")
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
(dom-dispatch _el-script "click" nil)
|
(dom-dispatch _el-div "click" nil)
|
||||||
(assert (dom-has-class? _el-div "called"))
|
(assert (dom-has-class? _el-div "called"))
|
||||||
))
|
))
|
||||||
(deftest "can return a value synchronously"
|
(deftest "can return a value synchronously"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def foo() return \"foo\"end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def foo() return \"foo\"end")
|
|
||||||
(dom-set-attr _el-div "_" "on click call foo() then put it into #d1.innerText")
|
(dom-set-attr _el-div "_" "on click call foo() then put it into #d1.innerText")
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
(dom-dispatch _el-script "click" nil)
|
(dom-dispatch _el-div "click" nil)
|
||||||
;; SKIP check: skip div.innerText.should.equal("")
|
;; SKIP check: skip div.innerText.should.equal("")
|
||||||
;; SKIP check: skip div.innerText.should.equal("foo")
|
;; SKIP check: skip div.innerText.should.equal("foo")
|
||||||
))
|
))
|
||||||
(deftest "can exit"
|
(deftest "can exit"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() exit end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
))
|
|
||||||
(deftest "can return a value asynchronously"
|
(deftest "can return a value asynchronously"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-script (dom-create-element "script")) (_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
(eval-expr-cek (hs-to-sx (hs-compile "def foo() wait 1ms return \"foo\"end")))
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")))
|
||||||
(dom-set-inner-html _el-script "def foo() wait 1ms return \"foo\"end")
|
|
||||||
(dom-set-attr _el-div "_" "on click call foo() then put it into #d1.innerText")
|
(dom-set-attr _el-div "_" "on click call foo() then put it into #d1.innerText")
|
||||||
(dom-set-attr _el-d1 "id" "d1")
|
(dom-set-attr _el-d1 "id" "d1")
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(dom-append (dom-body) _el-d1)
|
(dom-append (dom-body) _el-d1)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
(dom-dispatch _el-script "click" nil)
|
(dom-dispatch _el-div "click" nil)
|
||||||
;; SKIP check: skip div.innerText.should.equal("")
|
;; SKIP check: skip div.innerText.should.equal("")
|
||||||
;; SKIP check: skip div.innerText.should.equal("foo")
|
;; SKIP check: skip div.innerText.should.equal("foo")
|
||||||
))
|
))
|
||||||
(deftest "can interop with javascript"
|
(deftest "can interop with javascript"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() return \"foo\"end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip foo().should.equal("foo")
|
|
||||||
))
|
|
||||||
(deftest "can interop with javascript asynchronously"
|
(deftest "can interop with javascript asynchronously"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() wait 1ms return \"foo\"end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip val.should.equal("foo")
|
|
||||||
))
|
|
||||||
(deftest "can catch exceptions"
|
(deftest "can catch exceptions"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() throw \"bar\"catch e set window.bar to e end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal("bar")
|
|
||||||
))
|
|
||||||
(deftest "can rethrow in catch blocks"
|
(deftest "can rethrow in catch blocks"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() throw \"bar\"catch e throw e end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip true.should.equal(false)
|
|
||||||
;; SKIP check: skip e.should.equal("bar")
|
|
||||||
))
|
|
||||||
(deftest "can return in catch blocks"
|
(deftest "can return in catch blocks"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() throw \"bar\"catch e return 42 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip foo().should.equal(42)
|
|
||||||
))
|
|
||||||
(deftest "can catch async exceptions"
|
(deftest "can catch async exceptions"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def doh() wait 10ms throw \"bar\"end def foo() call doh()catch e set window.bar to e end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal("bar")
|
|
||||||
))
|
|
||||||
(deftest "can catch nested async exceptions"
|
(deftest "can catch nested async exceptions"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def doh() wait 10ms throw \"bar\"end def foo() call doh()catch e set window.bar to e end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal("bar")
|
|
||||||
))
|
|
||||||
(deftest "can rethrow in async catch blocks"
|
(deftest "can rethrow in async catch blocks"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() throw \"bar\"catch e wait 10ms throw e end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip reason.should.equal("bar")
|
|
||||||
))
|
|
||||||
(deftest "can return in async catch blocks"
|
(deftest "can return in async catch blocks"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() throw \"bar\"catch e wait 10ms return 42 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip val.should.equal(42)
|
|
||||||
))
|
|
||||||
(deftest "can install a function on an element and use in children w/ no leak"
|
(deftest "can install a function on an element and use in children w/ no leak"
|
||||||
(hs-cleanup!)
|
(hs-cleanup!)
|
||||||
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
(let ((_el-div (dom-create-element "div")) (_el-d1 (dom-create-element "div")) (_el-d2 (dom-create-element "div")) (_el-d3 (dom-create-element "div")))
|
||||||
@@ -4507,59 +4403,19 @@
|
|||||||
;; SKIP check: skip div.innerText.should.equal("42")
|
;; SKIP check: skip div.innerText.should.equal("42")
|
||||||
))
|
))
|
||||||
(deftest "finally blocks run normally"
|
(deftest "finally blocks run normally"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() set window.bar to 10finally set window.bar to 20 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal(20)
|
|
||||||
))
|
|
||||||
(deftest "finally blocks run when an exception occurs"
|
(deftest "finally blocks run when an exception occurs"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() set window.bar to 10 throw \"foo\"finally set window.bar to 20 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal(20)
|
|
||||||
))
|
|
||||||
(deftest "finally blocks run when an exception expr occurs"
|
(deftest "finally blocks run when an exception expr occurs"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() set window.bar to 10 call throwsAsyncException()finally set window.bar to 20 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal(20)
|
|
||||||
))
|
|
||||||
(deftest "async finally blocks run normally"
|
(deftest "async finally blocks run normally"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() wait a tick then set window.bar to 10finally set window.bar to 20 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal(20)
|
|
||||||
))
|
|
||||||
(deftest "async finally blocks run when an exception occurs"
|
(deftest "async finally blocks run when an exception occurs"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() wait a tick then set window.bar to 10 throw \"foo\"finally set window.bar to 20 end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
;; SKIP check: skip window.bar.should.equal(20)
|
|
||||||
))
|
|
||||||
(deftest "exit stops execution mid-function"
|
(deftest "exit stops execution mid-function"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() set x to 1 then exit then set x to 2 then return x end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
))
|
|
||||||
(deftest "can return without a value"
|
(deftest "can return without a value"
|
||||||
(hs-cleanup!)
|
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||||
(let ((_el-script (dom-create-element "script")))
|
|
||||||
(dom-set-attr _el-script "type" "text/hyperscript")
|
|
||||||
(dom-set-inner-html _el-script "def foo() return end")
|
|
||||||
(dom-append (dom-body) _el-script)
|
|
||||||
))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
;; ── askAnswer (5 tests) ──
|
;; ── askAnswer (5 tests) ──
|
||||||
|
|||||||
@@ -25,11 +25,25 @@ with open(INPUT) as f:
|
|||||||
|
|
||||||
# ── HTML parsing ──────────────────────────────────────────────────
|
# ── HTML parsing ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def extract_hs_scripts(html):
|
||||||
|
"""Extract <script type='text/hyperscript'>...</script> content blocks."""
|
||||||
|
scripts = []
|
||||||
|
for m in re.finditer(
|
||||||
|
r"<script\s+type=['\"]text/hyperscript['\"]>(.*?)</script>",
|
||||||
|
html, re.DOTALL
|
||||||
|
):
|
||||||
|
scripts.append(m.group(1).strip())
|
||||||
|
return scripts
|
||||||
|
|
||||||
|
|
||||||
def parse_html(html):
|
def parse_html(html):
|
||||||
"""Parse HTML into list of element dicts with parent-child relationships.
|
"""Parse HTML into list of element dicts with parent-child relationships.
|
||||||
Uses Python's html.parser for reliability with same-tag siblings."""
|
Uses Python's html.parser for reliability with same-tag siblings."""
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
|
# Remove script tags before parsing elements (they're handled separately)
|
||||||
|
html = re.sub(r"<script\s+type=['\"]text/hyperscript['\"]>.*?</script>", '', html, flags=re.DOTALL)
|
||||||
|
|
||||||
# Remove | separators
|
# Remove | separators
|
||||||
html = html.replace(' | ', '')
|
html = html.replace(' | ', '')
|
||||||
|
|
||||||
@@ -588,10 +602,20 @@ def generate_test_chai(test, elements, var_names, idx):
|
|||||||
actions = parse_action(test['action'], ref)
|
actions = parse_action(test['action'], ref)
|
||||||
checks = parse_checks(test['check'])
|
checks = parse_checks(test['check'])
|
||||||
|
|
||||||
|
# Extract <script type="text/hyperscript"> blocks
|
||||||
|
hs_scripts = extract_hs_scripts(test.get('html', ''))
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
lines.append(f' (deftest "{test["name"]}"')
|
lines.append(f' (deftest "{test["name"]}"')
|
||||||
lines.append(' (hs-cleanup!)')
|
lines.append(' (hs-cleanup!)')
|
||||||
|
|
||||||
|
# Compile HS script blocks as setup (def functions etc.)
|
||||||
|
for script in hs_scripts:
|
||||||
|
# Clean whitespace
|
||||||
|
clean = ' '.join(script.split())
|
||||||
|
escaped = clean.replace('\\', '\\\\').replace('"', '\\"')
|
||||||
|
lines.append(f' (eval-expr-cek (hs-to-sx (hs-compile "{escaped}")))')
|
||||||
|
|
||||||
bindings = [f'({var_names[i]} (dom-create-element "{el["tag"]}"))' for i, el in enumerate(elements)]
|
bindings = [f'({var_names[i]} (dom-create-element "{el["tag"]}"))' for i, el in enumerate(elements)]
|
||||||
lines.append(f' (let ({" ".join(bindings)})')
|
lines.append(f' (let ({" ".join(bindings)})')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user