Aser server-affinity component expansion + readline buffer fix

adapter-sx.sx: aser-expand-component expands :affinity :server components
inline during SX wire format serialization. Binds keyword args via
eval-expr, children via aser (handles HTML tags), then asers the body.

ocaml_bridge.py: 10MB readline buffer for large spec responses.
nav-data.sx: evaluator.sx filename fix.

Page rendering stays on Python _eval_slot for now — full OCaml rendering
needs the page shell IO (headers, CSRF, CSS) migrated to OCaml IO bridge.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 20:46:33 +00:00
parent 1c91680e63
commit 171c18d3be
4 changed files with 82 additions and 7 deletions

View File

@@ -71,9 +71,13 @@
(= name "<>")
(aser-fragment args env)
;; Component call — serialize WITHOUT expanding
;; Component call — expand server-affinity, serialize others
(starts-with? name "~")
(aser-call name args env)
(let ((comp (if (env-has? env name) (env-get env name) nil)))
(if (and comp (component? comp)
(= (component-affinity comp) "server"))
(aser-expand-component comp args env)
(aser-call name args env)))
;; Lake — serialize (server-morphable slot)
(= name "lake")
@@ -213,6 +217,53 @@
(str "(" (join " " parts) ")")))))
;; --------------------------------------------------------------------------
;; Server-affinity component expansion
;; --------------------------------------------------------------------------
;;
;; When a component has :affinity :server, the aser expands it inline:
;; bind keyword args + children, then aser the body.
;; This is the aser equivalent of render-to-html's component expansion.
(define aser-expand-component :effects [render]
(fn ((comp :as any) (args :as list) (env :as dict))
(let ((params (component-params comp))
(local (env-merge env (component-closure comp)))
(i 0)
(skip false)
(children (list)))
;; Parse keyword args and positional children from args
;; Keyword values are eval'd (they're data). Children are NOT eval'd
;; (they may contain HTML tags that only the aser can handle).
(for-each
(fn (arg)
(if skip
(do (set! skip false) (set! i (inc i)))
(if (and (= (type-of arg) "keyword")
(< (inc i) (len args)))
;; Keyword arg: bind name = eval'd next arg
(do
(env-bind! local (keyword-name arg)
(trampoline (eval-expr (nth args (inc i)) env)))
(set! skip true)
(set! i (inc i)))
;; Positional child: keep as unevaluated AST for aser
(do
(append! children arg)
(set! i (inc i))))))
args)
;; Bind &rest children — aser each child first, then bind the result
(when (component-has-children comp)
(let ((asered-children
(map (fn (c) (aser c env)) children)))
(env-bind! local "children"
(if (= (len asered-children) 1)
(first asered-children)
asered-children))))
;; Aser the body in the merged env
(aser (component-body comp) local))))
;; --------------------------------------------------------------------------
;; Form classification
;; --------------------------------------------------------------------------