sx: step 10 — compiler command + as converter registries
Add `_hs-command-registry` and `_hs-converter-registry` dicts plus `hs-register-command!` / `hs-register-converter!` to `lib/hyperscript/compiler.sx`. Inside `hs-to-sx`, before the existing `cond` over head symbols, check both registries: an `as` form whose type-name has a registered converter dispatches to that converter; any list head whose name (`(str head)`) is in the command registry dispatches to that compile-fn. On registry miss, the original ~180 hardcoded branches handle the form. Each registered fn receives a ctx dict (built per call) exposing `:hs-to-sx` for recursion plus the AST fields the dispatch needs (`:ast :head` for commands; `:ast :value-ast :type-name` for converters). Mirrors Step 9's parser feature registry shape. Smoke tested: register custom command + converter, both dispatch; built-in `(as x \"Int\")` still produces `(hs-coerce x \"Int\")`. Mirror `shared/static/wasm/sx/hs-compiler.sx` copied byte-identical. OCaml: 4545/1339, JS: 2591/2465 — both match baseline, zero regressions. Second piece of plans/designs/hs-plugin-system.md (Step 11 next). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,22 @@
|
||||
;; (hs-to-sx (hs-compile "on click add .active to me"))
|
||||
;; → (hs-on me "click" (fn (event) (dom-add-class me "active")))
|
||||
|
||||
;; ── Compiler plugin registries ────────────────────────────────────
|
||||
;; Plugins call (hs-register-command! "head" compile-fn) and
|
||||
;; (hs-register-converter! "TypeName" convert-fn) at load time. Both
|
||||
;; compile-fn and convert-fn receive a ctx dict (built per call inside
|
||||
;; hs-to-sx) exposing :hs-to-sx for recursion plus the AST node fields
|
||||
;; the dispatch needs. Compile-fn returns an SX expression.
|
||||
(begin
|
||||
(define _hs-command-registry {})
|
||||
(define _hs-converter-registry {})
|
||||
(define
|
||||
hs-register-command!
|
||||
(fn (name compile-fn) (dict-set! _hs-command-registry name compile-fn)))
|
||||
(define
|
||||
hs-register-converter!
|
||||
(fn (name convert-fn) (dict-set! _hs-converter-registry name convert-fn))))
|
||||
|
||||
(define
|
||||
hs-to-sx
|
||||
(let
|
||||
@@ -952,6 +968,22 @@
|
||||
(true
|
||||
(let
|
||||
((head (first ast)))
|
||||
(let
|
||||
((reg-cmd-fn (dict-get _hs-command-registry (str head)))
|
||||
(reg-conv-fn
|
||||
(and
|
||||
(= head (quote as))
|
||||
(dict-get _hs-converter-registry (nth ast 2)))))
|
||||
(cond
|
||||
(reg-conv-fn
|
||||
(reg-conv-fn
|
||||
{:hs-to-sx hs-to-sx
|
||||
:ast ast
|
||||
:value-ast (nth ast 1)
|
||||
:type-name (nth ast 2)}))
|
||||
(reg-cmd-fn
|
||||
(reg-cmd-fn {:hs-to-sx hs-to-sx :ast ast :head head}))
|
||||
(true
|
||||
(cond
|
||||
((= head (quote __bind-from-detail__))
|
||||
(let
|
||||
@@ -2667,7 +2699,7 @@
|
||||
(quote begin)
|
||||
(list (quote set!) (quote it) (quote __hs-js))
|
||||
(quote __hs-js))))))
|
||||
(true ast)))))))))
|
||||
(true ast))))))))))))
|
||||
|
||||
;; ── Convenience: source → SX ─────────────────────────────────
|
||||
(define
|
||||
|
||||
@@ -7,6 +7,22 @@
|
||||
;; (hs-to-sx (hs-compile "on click add .active to me"))
|
||||
;; → (hs-on me "click" (fn (event) (dom-add-class me "active")))
|
||||
|
||||
;; ── Compiler plugin registries ────────────────────────────────────
|
||||
;; Plugins call (hs-register-command! "head" compile-fn) and
|
||||
;; (hs-register-converter! "TypeName" convert-fn) at load time. Both
|
||||
;; compile-fn and convert-fn receive a ctx dict (built per call inside
|
||||
;; hs-to-sx) exposing :hs-to-sx for recursion plus the AST node fields
|
||||
;; the dispatch needs. Compile-fn returns an SX expression.
|
||||
(begin
|
||||
(define _hs-command-registry {})
|
||||
(define _hs-converter-registry {})
|
||||
(define
|
||||
hs-register-command!
|
||||
(fn (name compile-fn) (dict-set! _hs-command-registry name compile-fn)))
|
||||
(define
|
||||
hs-register-converter!
|
||||
(fn (name convert-fn) (dict-set! _hs-converter-registry name convert-fn))))
|
||||
|
||||
(define
|
||||
hs-to-sx
|
||||
(let
|
||||
@@ -48,6 +64,15 @@
|
||||
prop
|
||||
value))
|
||||
(list (quote hs-query-all) (nth base-ast 1))))
|
||||
((and (list? base-ast) (= (first base-ast) (quote query)))
|
||||
(list
|
||||
(quote dom-set-prop)
|
||||
(list
|
||||
(quote hs-named-target)
|
||||
(nth base-ast 1)
|
||||
(list (quote hs-query-first) (nth base-ast 1)))
|
||||
prop
|
||||
value))
|
||||
((and (list? base-ast) (= (first base-ast) dot-sym) (let ((inner (nth base-ast 1))) (and (list? inner) (= (first inner) (quote query)) (let ((s (nth inner 1))) (and (string? s) (> (len s) 0) (= (substring s 0 1) "."))))))
|
||||
(let
|
||||
((inner (nth base-ast 1))
|
||||
@@ -221,7 +246,8 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?)
|
||||
elsewhere?
|
||||
or-sources)
|
||||
(cond
|
||||
((<= (len items) 1)
|
||||
(let
|
||||
@@ -279,7 +305,27 @@
|
||||
having-info
|
||||
(get having-info "threshold")
|
||||
nil))))
|
||||
(true on-call))))))))))))
|
||||
(true
|
||||
(if
|
||||
or-sources
|
||||
(cons
|
||||
(quote do)
|
||||
(cons
|
||||
on-call
|
||||
(map
|
||||
(fn
|
||||
(pair)
|
||||
(list
|
||||
(quote hs-on)
|
||||
(if
|
||||
(nth pair 1)
|
||||
(hs-to-sx
|
||||
(nth pair 1))
|
||||
(quote me))
|
||||
(first pair)
|
||||
handler))
|
||||
or-sources)))
|
||||
on-call)))))))))))))
|
||||
((= (first items) :from)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -291,7 +337,8 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :filter)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -303,7 +350,8 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :every)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -315,7 +363,8 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :catch)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -327,7 +376,8 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :finally)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -339,7 +389,8 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :having)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -351,7 +402,8 @@
|
||||
(nth items 1)
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :of-filter)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -363,7 +415,8 @@
|
||||
having-info
|
||||
(nth items 1)
|
||||
count-filter-info
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :count-filter)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -375,7 +428,8 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
(nth items 1)
|
||||
elsewhere?))
|
||||
elsewhere?
|
||||
or-sources))
|
||||
((= (first items) :elsewhere)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
@@ -387,6 +441,20 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
(nth items 1)
|
||||
or-sources))
|
||||
((= (first items) :or-sources)
|
||||
(scan-on
|
||||
(rest (rest items))
|
||||
source
|
||||
filter
|
||||
every?
|
||||
catch-info
|
||||
finally-info
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?
|
||||
(nth items 1)))
|
||||
(true
|
||||
(scan-on
|
||||
@@ -399,8 +467,9 @@
|
||||
having-info
|
||||
of-filter-info
|
||||
count-filter-info
|
||||
elsewhere?)))))
|
||||
(scan-on (rest parts) nil nil false nil nil nil nil nil false)))))
|
||||
elsewhere?
|
||||
or-sources)))))
|
||||
(scan-on (rest parts) nil nil false nil nil nil nil nil false nil)))))
|
||||
(define
|
||||
emit-send
|
||||
(fn
|
||||
@@ -899,6 +968,22 @@
|
||||
(true
|
||||
(let
|
||||
((head (first ast)))
|
||||
(let
|
||||
((reg-cmd-fn (dict-get _hs-command-registry (str head)))
|
||||
(reg-conv-fn
|
||||
(and
|
||||
(= head (quote as))
|
||||
(dict-get _hs-converter-registry (nth ast 2)))))
|
||||
(cond
|
||||
(reg-conv-fn
|
||||
(reg-conv-fn
|
||||
{:hs-to-sx hs-to-sx
|
||||
:ast ast
|
||||
:value-ast (nth ast 1)
|
||||
:type-name (nth ast 2)}))
|
||||
(reg-cmd-fn
|
||||
(reg-cmd-fn {:hs-to-sx hs-to-sx :ast ast :head head}))
|
||||
(true
|
||||
(cond
|
||||
((= head (quote __bind-from-detail__))
|
||||
(let
|
||||
@@ -2614,7 +2699,7 @@
|
||||
(quote begin)
|
||||
(list (quote set!) (quote it) (quote __hs-js))
|
||||
(quote __hs-js))))))
|
||||
(true ast)))))))))
|
||||
(true ast))))))))))))
|
||||
|
||||
;; ── Convenience: source → SX ─────────────────────────────────
|
||||
(define
|
||||
|
||||
Reference in New Issue
Block a user