Update reference SX spec to match sx.js macros branch (CSSX, dict literals, new primitives)

- eval.sx: Add defstyle, defkeyframes, defhandler special forms; add ho-for-each
- parser.sx: Add dict {...} literal parsing and quasiquote/unquote sugar
- primitives.sx: Add parse-datetime, split-ids, css, merge-styles primitives
- render.sx: Add StyleValue handling, SVG filter elements, definition forms in render, fix render-to-html to handle HTML tags directly
- bootstrap_js.py: Add StyleValue type, buildKeyframes, isEvery platform helper, new primitives (format-date, parse-datetime, split-ids, css, merge-styles), dict/quasiquote parser, expose render functions as primitives
- sx-ref.js: Regenerated — 132/132 tests passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 10:17:28 +00:00
parent 4a3a510a23
commit a9526c4fa1
6 changed files with 406 additions and 29 deletions

View File

@@ -44,10 +44,15 @@
;; Media
"img" "video" "audio" "source" "picture" "canvas" "iframe"
;; SVG
"svg" "path" "circle" "rect" "line" "polyline" "polygon" "text"
"g" "defs" "use" "clipPath" "mask" "pattern" "linearGradient"
"radialGradient" "stop" "filter" "feGaussianBlur" "feOffset"
"feBlend" "feColorMatrix" "feComposite" "feMerge" "feMergeNode"
"svg" "math" "path" "circle" "ellipse" "rect" "line" "polyline" "polygon"
"text" "tspan" "g" "defs" "use" "clipPath" "mask" "pattern"
"linearGradient" "radialGradient" "stop" "filter"
"feGaussianBlur" "feOffset" "feBlend" "feColorMatrix" "feComposite"
"feMerge" "feMergeNode" "feTurbulence"
"feComponentTransfer" "feFuncR" "feFuncG" "feFuncB" "feFuncA"
"feDisplacementMap" "feFlood" "feImage" "feMorphology"
"feSpecularLighting" "feDiffuseLighting"
"fePointLight" "feSpotLight" "feDistantLight"
"animate" "animateTransform" "foreignObject"
;; Other
"template" "slot" "dialog" "menu"))
@@ -57,9 +62,10 @@
"link" "meta" "param" "source" "track" "wbr"))
(define BOOLEAN_ATTRS
(list "disabled" "checked" "selected" "readonly" "required" "hidden"
"autofocus" "autoplay" "controls" "loop" "muted" "defer" "async"
"novalidate" "formnovalidate" "multiple" "open" "allowfullscreen"))
(list "async" "autofocus" "autoplay" "checked" "controls" "default"
"defer" "disabled" "formnovalidate" "hidden" "inert" "ismap"
"loop" "multiple" "muted" "nomodule" "novalidate" "open"
"playsinline" "readonly" "required" "reversed" "selected"))
;; --------------------------------------------------------------------------
@@ -68,8 +74,20 @@
(define render-to-html
(fn (expr env)
(let ((result (trampoline (eval-expr expr env))))
(render-value-to-html result env))))
(case (type-of expr)
;; Literals — render directly
"nil" ""
"string" (escape-html expr)
"number" (str expr)
"boolean" (if expr "true" "false")
;; List — dispatch to render-list which handles HTML tags, special forms, etc.
"list" (if (empty? expr) "" (render-list-to-html expr env))
;; Symbol — evaluate then render
"symbol" (render-value-to-html (trampoline (eval-expr expr env)) env)
;; Keyword — render as text
"keyword" (escape-html (keyword-name expr))
;; Everything else — evaluate first
:else (render-value-to-html (trampoline (eval-expr expr env)) env))))
(define render-value-to-html
(fn (val env)
@@ -80,6 +98,7 @@
"boolean" (if val "true" "false")
"list" (render-list-to-html val env)
"raw-html" (raw-html-content val)
"style-value" (style-value-class val)
:else (escape-html (str val)))))
(define render-list-to-html
@@ -114,6 +133,11 @@
env)
(error (str "Unknown component: " name))))
;; Definitions — evaluate for side effects, render nothing
(or (= name "define") (= name "defcomp") (= name "defmacro")
(= name "defstyle") (= name "defkeyframes") (= name "defhandler"))
(do (trampoline (eval-expr expr env)) "")
;; Macro expansion
(and (env-has? env name) (macro? (env-get env name)))
(render-to-html
@@ -182,6 +206,9 @@
""
;; Nil values — skip
(nil? val) ""
;; StyleValue on :style → emit as class
(and (= key "style") (style-value? val))
(str " class=\"" (style-value-class val) "\"")
;; Normal attr
:else (str " " key "=\"" (escape-attr (str val)) "\""))))
(keys attrs)))))
@@ -323,6 +350,10 @@
;; (set-attribute el k v) → void
;; (append-child parent c) → void
;;
;; StyleValue:
;; (style-value? x) → boolean (is x a StyleValue?)
;; (style-value-class sv) → string (CSS class name)
;;
;; Serialization:
;; (serialize val) → SX source string representation of val
;;