Add provide/context/emit!/emitted — render-time dynamic scope

Four new primitives for scoped downward value passing and upward
accumulation through the render tree. Specced in .sx, bootstrapped
to Python and JS across all adapters (eval, html, sx, dom, async).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 02:58:21 +00:00
parent 41097eeef9
commit ea2b71cfa3
14 changed files with 436 additions and 18 deletions

View File

@@ -174,7 +174,7 @@
"defhandler" "defpage" "defquery" "defaction" "defrelation"
"begin" "do" "quote" "quasiquote"
"->" "set!" "letrec" "dynamic-wind" "defisland"
"deftype" "defeffect"))
"deftype" "defeffect" "provide"))
(define HO_FORM_NAMES
(list "map" "map-indexed" "filter" "reduce"
@@ -312,6 +312,17 @@
(= name "deftype") (= name "defeffect"))
(do (trampoline (eval-expr expr env)) nil)
;; provide — render-time dynamic scope
(= name "provide")
(let ((prov-name (trampoline (eval-expr (first args) env)))
(prov-val (trampoline (eval-expr (nth args 1) env)))
(result nil))
(provide-push! prov-name prov-val)
(for-each (fn (body) (set! result (aser body env)))
(slice args 2))
(provide-pop! prov-name)
result)
;; Everything else — evaluate normally
:else
(trampoline (eval-expr expr env))))))