HS parser: fix number+comparison keyword collision, eval-hs uses hs-compile

Parser: skip unit suffix when next ident is a comparison keyword
(starts, ends, contains, matches, is, does, in, precedes, follows).
Fixes "123 starts with '12'" returning "123starts" instead of true.

eval-hs: use hs-compile directly instead of hs-to-sx-from-source with
"return " prefix, which was causing the parser to consume the comparison
as a string suffix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 11:29:01 +00:00
parent a93e5924df
commit 4f02f82f4e
377 changed files with 9517 additions and 8694 deletions

35
sx/sx/layouts/doc.sx Normal file
View File

@@ -0,0 +1,35 @@
(defcomp
(&key path &rest children)
:affinity :server
(let*
((nav-state (resolve-nav-path sx-nav-tree (or path "/")))
(trail (or (get nav-state "trail") (list)))
(trail-len (len trail))
(depth (+ trail-len 1)))
(<>
(div
:id "sx-nav"
(~tw :tokens "mb-6")
:sx-swap-oob "innerHTML"
(div
:id "logo-opacity"
:style (str
"opacity:"
(+ (* (/ 1 depth) 0.75) 0.25)
";"
"transition:opacity 0.3s;")
(~layouts/header :path (or path "/")))
(map-indexed
(fn
(i crumb)
(~layouts/nav-sibling-row
:node (get crumb "node")
:siblings (get crumb "siblings")
:is-leaf (= i (- trail-len 1))
:level (+ i 2)
:depth depth))
trail)
(when
(get nav-state "children")
(~layouts/nav-children :items (get nav-state "children"))))
(div :id "sx-content" (error-boundary children) (~tw/flush)))))

View File

@@ -0,0 +1 @@
(defcomp () nil)

View File

@@ -0,0 +1 @@
(defcomp () nil)

View File

@@ -0,0 +1 @@
(defcomp () nil)

56
sx/sx/layouts/header.sx Normal file
View File

@@ -0,0 +1,56 @@
(defisland
(&key path)
(let
((families (list "violet" "rose" "blue" "emerald" "amber" "cyan" "red" "teal" "pink" "indigo"))
(store
(if (client?) (def-store "header-color" (fn () {:idx (signal 0) :shade (signal 500)})) nil))
(idx (if store (get store "idx") (signal 0)))
(shade (if store (get store "shade") (signal 500)))
(current-family
(computed (fn () (nth families (mod (deref idx) (len families)))))))
(div
(~tw :tokens "block max-w-3xl mx-auto px-4 pt-8 pb-4 text-center")
(a
:href "/sx/"
:sx-get "/sx/"
:sx-target "#sx-content"
:sx-select "#sx-content"
:sx-swap "innerHTML"
:sx-push-url "true"
(~tw :tokens "block no-underline")
(lake
:id "logo"
(span
(~tw
:tokens "block mb-2 text-violet-699 text-4xl font-bold font-mono")
"(<sx>)")))
(p
(~tw :tokens "mb-1 text-stone-500 text-lg")
"The framework-free "
(span
(~tw :tokens "font-bold")
:style (str
"color:"
(colour (deref current-family) (deref shade))
";"
"cursor:pointer;transition:color 0.3s,font-weight 0.3s;")
:on-click (fn
(e)
(batch
(fn
()
(swap! idx inc)
(reset! shade (+ 400 (* (mod (* (deref idx) 137) 5) 50))))))
"reactive")
" hypermedium")
(lake
:id "copyright"
(p
(~tw :tokens "text-stone-400 text-xs")
"© Giles Bradshaw 2026"
(when
path
(span
(~tw :tokens "text-stone-300 text-xs")
:style "margin-left:0.5em;"
(str "· " path))))))))

View File

@@ -0,0 +1,21 @@
(defcomp
(&key items)
:affinity :server
(div
(~tw :tokens "max-w-3xl mx-auto px-4 py-3")
(div
(~tw :tokens "flex flex-wrap justify-center gap-2")
(map
(fn
(item)
(a
:href (get item "href")
:sx-get (get item "href")
:sx-target "#sx-content"
:sx-select "#sx-content"
:sx-swap "innerHTML"
:sx-push-url "true"
(~tw
:tokens "px-3 py-1.5 rounded border transition-colors text-violet-700 text-sm border-violet-200")
(get item "label")))
items))))

View File

@@ -0,0 +1,56 @@
(defcomp
(&key node siblings is-leaf level depth)
:affinity :server
(let*
((sibs (or siblings (list)))
(count (len sibs))
(row-opacity
(if
(and level depth (> depth 0))
(+ (* (/ level depth) 0.75) 0.25)
1)))
(when
(> count 0)
(let*
((idx (find-nav-index sibs node))
(prev-idx (mod (+ (- idx 1) count) count))
(next-idx (mod (+ idx 1) count))
(prev-node (nth sibs prev-idx))
(next-node (nth sibs next-idx)))
(div
(~tw
:tokens "w-full max-w-3xl mx-auto px-4 py-2 grid grid-cols-3 items-center")
:style (str "opacity:" row-opacity ";transition:opacity 0.3s;")
(a
:href (get prev-node "href")
:sx-get (get prev-node "href")
:sx-target "#sx-content"
:sx-select "#sx-content"
:sx-swap "innerHTML"
:sx-push-url "true"
(~tw :tokens "text-right min-w-0 truncate text-stone-500 text-sm")
(str "← " (get prev-node "label")))
(a
:href (get node "href")
:sx-get (get node "href")
:sx-target "#sx-content"
:sx-select "#sx-content"
:sx-swap "innerHTML"
:sx-push-url "true"
(~tw
:tokens (str
"text-center min-w-0 truncate px-1 "
(if
is-leaf
"text-violet-700 text-2xl font-bold"
"text-violet-700 text-lg font-semibold")))
(get node "label"))
(a
:href (get next-node "href")
:sx-get (get next-node "href")
:sx-target "#sx-content"
:sx-select "#sx-content"
:sx-swap "innerHTML"
:sx-push-url "true"
(~tw :tokens "text-left min-w-0 truncate text-stone-500 text-sm")
(str (get next-node "label") " →")))))))

View File

@@ -0,0 +1 @@
(defcomp () nil)

View File

@@ -0,0 +1 @@
(defcomp () nil)

View File

@@ -0,0 +1,3 @@
(defcomp
(&key content)
(~shared:layout/oob-sx :content content))