Add :effects annotations to all spec files and update bootstrappers
Bootstrappers (bootstrap_py.py, js.sx) now skip :effects keyword in define forms, enabling effect annotations throughout the spec without changing generated output. Annotated 180+ functions across 14 spec files: - signals.sx: signal/deref [] pure, reset!/swap!/effect/batch [mutation] - engine.sx: parse-* [] pure, morph-*/swap-* [mutation io] - orchestration.sx: all [mutation io] (browser event binding) - adapter-html.sx: render-* [render] - adapter-dom.sx: render-* [render], reactive-* [render mutation] - adapter-sx.sx: aser-* [render] - adapter-async.sx: async-render-*/async-aser-* [render io] - parser.sx: all [] pure - render.sx: predicates [] pure, process-bindings [mutation] - boot.sx: all [mutation io] (browser init) - deps.sx: scan-*/transitive-* [] pure, compute-all-* [mutation] - router.sx: all [] pure (URL matching) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
;; Async HTML renderer
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render
|
||||
(define-async async-render :effects [render io]
|
||||
(fn (expr (env :as dict) ctx)
|
||||
(case (type-of expr)
|
||||
"nil" ""
|
||||
@@ -56,7 +56,7 @@
|
||||
:else (escape-html (str expr)))))
|
||||
|
||||
|
||||
(define-async async-render-list
|
||||
(define-async async-render-list :effects [render io]
|
||||
(fn (expr (env :as dict) ctx)
|
||||
(let ((head (first expr)))
|
||||
(if (not (= (type-of head) "symbol"))
|
||||
@@ -138,7 +138,7 @@
|
||||
;; async-render-raw — handle (raw! ...) in async context
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render-raw
|
||||
(define-async async-render-raw :effects [render io]
|
||||
(fn ((args :as list) (env :as dict) ctx)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
@@ -157,7 +157,7 @@
|
||||
;; async-render-element — render an HTML element with async arg evaluation
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render-element
|
||||
(define-async async-render-element :effects [render io]
|
||||
(fn ((tag :as string) (args :as list) (env :as dict) ctx)
|
||||
(let ((attrs (dict))
|
||||
(children (list)))
|
||||
@@ -185,7 +185,7 @@
|
||||
;; Uses for-each + mutable state instead of reduce, because the bootstrapper
|
||||
;; compiles inline for-each lambdas as for loops (which can contain await).
|
||||
|
||||
(define-async async-parse-element-args
|
||||
(define-async async-parse-element-args :effects [render io]
|
||||
(fn ((args :as list) (attrs :as dict) (children :as list) (env :as dict) ctx)
|
||||
(let ((skip false)
|
||||
(i 0))
|
||||
@@ -210,7 +210,7 @@
|
||||
;; async-render-component — expand and render a component asynchronously
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render-component
|
||||
(define-async async-render-component :effects [render io]
|
||||
(fn ((comp :as component) (args :as list) (env :as dict) ctx)
|
||||
(let ((kwargs (dict))
|
||||
(children (list)))
|
||||
@@ -232,7 +232,7 @@
|
||||
;; async-render-island — SSR render of reactive island with hydration markers
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render-island
|
||||
(define-async async-render-island :effects [render io]
|
||||
(fn ((island :as island) (args :as list) (env :as dict) ctx)
|
||||
(let ((kwargs (dict))
|
||||
(children (list)))
|
||||
@@ -261,7 +261,7 @@
|
||||
;; async-render-lambda — render lambda body in HTML context
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render-lambda
|
||||
(define-async async-render-lambda :effects [render io]
|
||||
(fn ((f :as lambda) (args :as list) (env :as dict) ctx)
|
||||
(let ((local (env-merge (lambda-closure f) env)))
|
||||
(for-each-indexed
|
||||
@@ -274,7 +274,7 @@
|
||||
;; async-parse-kw-args — parse keyword args and children with async eval
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-parse-kw-args
|
||||
(define-async async-parse-kw-args :effects [render io]
|
||||
(fn ((args :as list) (kwargs :as dict) (children :as list) (env :as dict) ctx)
|
||||
(let ((skip false)
|
||||
(i 0))
|
||||
@@ -300,7 +300,7 @@
|
||||
;; --------------------------------------------------------------------------
|
||||
;; Bootstrapper emits this as: [await async_render(x, env, ctx) for x in exprs]
|
||||
|
||||
(define-async async-map-render
|
||||
(define-async async-map-render :effects [render io]
|
||||
(fn ((exprs :as list) (env :as dict) ctx)
|
||||
(let ((results (list)))
|
||||
(for-each
|
||||
@@ -319,7 +319,7 @@
|
||||
"deftype" "defeffect"
|
||||
"map" "map-indexed" "filter" "for-each"))
|
||||
|
||||
(define async-render-form?
|
||||
(define async-render-form? :effects []
|
||||
(fn ((name :as string))
|
||||
(contains? ASYNC_RENDER_FORMS name)))
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
;; Uses cond-scheme? from eval.sx (the FIXED version with every? check)
|
||||
;; and eval-cond from render.sx for correct scheme/clojure classification.
|
||||
|
||||
(define-async dispatch-async-render-form
|
||||
(define-async dispatch-async-render-form :effects [render io]
|
||||
(fn ((name :as string) expr (env :as dict) ctx)
|
||||
(cond
|
||||
;; if
|
||||
@@ -407,7 +407,7 @@
|
||||
;; async-render-cond-scheme — scheme-style cond for render mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render-cond-scheme
|
||||
(define-async async-render-cond-scheme :effects [render io]
|
||||
(fn ((clauses :as list) (env :as dict) ctx)
|
||||
(if (empty? clauses)
|
||||
""
|
||||
@@ -429,7 +429,7 @@
|
||||
;; async-render-cond-clojure — clojure-style cond for render mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-render-cond-clojure
|
||||
(define-async async-render-cond-clojure :effects [render io]
|
||||
(fn ((clauses :as list) (env :as dict) ctx)
|
||||
(if (< (len clauses) 2)
|
||||
""
|
||||
@@ -449,7 +449,7 @@
|
||||
;; async-process-bindings — evaluate let-bindings asynchronously
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-process-bindings
|
||||
(define-async async-process-bindings :effects [render io]
|
||||
(fn (bindings (env :as dict) ctx)
|
||||
;; env-extend (not merge) — Env is not a dict subclass, so merge()
|
||||
;; returns an empty dict, losing all parent scope bindings.
|
||||
@@ -470,7 +470,7 @@
|
||||
local)))
|
||||
|
||||
|
||||
(define-async async-process-bindings-flat
|
||||
(define-async async-process-bindings-flat :effects [render io]
|
||||
(fn ((bindings :as list) (local :as dict) ctx)
|
||||
(let ((skip false)
|
||||
(i 0))
|
||||
@@ -495,7 +495,7 @@
|
||||
;; async-map-fn-render — map a lambda/callable over collection for render
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-map-fn-render
|
||||
(define-async async-map-fn-render :effects [render io]
|
||||
(fn (f (coll :as list) (env :as dict) ctx)
|
||||
(let ((results (list)))
|
||||
(for-each
|
||||
@@ -512,7 +512,7 @@
|
||||
;; async-map-indexed-fn-render — map-indexed variant for render
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-map-indexed-fn-render
|
||||
(define-async async-map-indexed-fn-render :effects [render io]
|
||||
(fn (f (coll :as list) (env :as dict) ctx)
|
||||
(let ((results (list))
|
||||
(i 0))
|
||||
@@ -531,7 +531,7 @@
|
||||
;; async-invoke — call a native callable, await if coroutine
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-invoke
|
||||
(define-async async-invoke :effects [io]
|
||||
(fn (f &rest args)
|
||||
(let ((r (apply f args)))
|
||||
(if (async-coroutine? r)
|
||||
@@ -543,7 +543,7 @@
|
||||
;; Async SX wire format (aser)
|
||||
;; ==========================================================================
|
||||
|
||||
(define-async async-aser
|
||||
(define-async async-aser :effects [render io]
|
||||
(fn (expr (env :as dict) ctx)
|
||||
(case (type-of expr)
|
||||
"number" expr
|
||||
@@ -573,7 +573,7 @@
|
||||
:else expr)))
|
||||
|
||||
|
||||
(define-async async-aser-dict
|
||||
(define-async async-aser-dict :effects [render io]
|
||||
(fn ((expr :as dict) (env :as dict) ctx)
|
||||
(let ((result (dict)))
|
||||
(for-each
|
||||
@@ -587,7 +587,7 @@
|
||||
;; async-aser-list — dispatch on list head for aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-list
|
||||
(define-async async-aser-list :effects [render io]
|
||||
(fn (expr (env :as dict) ctx)
|
||||
(let ((head (first expr))
|
||||
(args (rest expr)))
|
||||
@@ -666,7 +666,7 @@
|
||||
;; async-aser-eval-call — evaluate a function call fully in aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-eval-call
|
||||
(define-async async-aser-eval-call :effects [render io]
|
||||
(fn (head (args :as list) (env :as dict) ctx)
|
||||
(let ((f (async-eval head env ctx))
|
||||
(evaled-args (async-eval-args args env ctx)))
|
||||
@@ -694,7 +694,7 @@
|
||||
;; async-eval-args — evaluate a list of args asynchronously
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-eval-args
|
||||
(define-async async-eval-args :effects [io]
|
||||
(fn ((args :as list) (env :as dict) ctx)
|
||||
(let ((results (list)))
|
||||
(for-each
|
||||
@@ -707,7 +707,7 @@
|
||||
;; async-aser-map-list — aser each element of a list
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-map-list
|
||||
(define-async async-aser-map-list :effects [render io]
|
||||
(fn ((exprs :as list) (env :as dict) ctx)
|
||||
(let ((results (list)))
|
||||
(for-each
|
||||
@@ -720,7 +720,7 @@
|
||||
;; async-aser-fragment — serialize (<> child1 child2 ...) in aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-fragment
|
||||
(define-async async-aser-fragment :effects [render io]
|
||||
(fn ((children :as list) (env :as dict) ctx)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
@@ -744,7 +744,7 @@
|
||||
;; async-aser-component — expand component server-side in aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-component
|
||||
(define-async async-aser-component :effects [render io]
|
||||
(fn ((comp :as component) (args :as list) (env :as dict) ctx)
|
||||
(let ((kwargs (dict))
|
||||
(children (list)))
|
||||
@@ -776,7 +776,7 @@
|
||||
;; async-parse-aser-kw-args — parse keyword args for aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-parse-aser-kw-args
|
||||
(define-async async-parse-aser-kw-args :effects [render io]
|
||||
(fn ((args :as list) (kwargs :as dict) (children :as list) (env :as dict) ctx)
|
||||
(let ((skip false)
|
||||
(i 0))
|
||||
@@ -801,7 +801,7 @@
|
||||
;; async-aser-call — serialize an SX call (tag or component) in aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-call
|
||||
(define-async async-aser-call :effects [render io]
|
||||
(fn ((name :as string) (args :as list) (env :as dict) ctx)
|
||||
(let ((token (if (or (= name "svg") (= name "math"))
|
||||
(svg-context-set! true)
|
||||
@@ -860,7 +860,7 @@
|
||||
(define ASYNC_ASER_HO_NAMES
|
||||
(list "map" "map-indexed" "filter" "for-each"))
|
||||
|
||||
(define async-aser-form?
|
||||
(define async-aser-form? :effects []
|
||||
(fn ((name :as string))
|
||||
(or (contains? ASYNC_ASER_FORM_NAMES name)
|
||||
(contains? ASYNC_ASER_HO_NAMES name))))
|
||||
@@ -872,7 +872,7 @@
|
||||
;;
|
||||
;; Uses cond-scheme? from eval.sx (the FIXED version with every? check).
|
||||
|
||||
(define-async dispatch-async-aser-form
|
||||
(define-async dispatch-async-aser-form :effects [render io]
|
||||
(fn ((name :as string) expr (env :as dict) ctx)
|
||||
(let ((args (rest expr)))
|
||||
(cond
|
||||
@@ -1002,7 +1002,7 @@
|
||||
;; async-aser-cond-scheme — scheme-style cond for aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-cond-scheme
|
||||
(define-async async-aser-cond-scheme :effects [render io]
|
||||
(fn ((clauses :as list) (env :as dict) ctx)
|
||||
(if (empty? clauses)
|
||||
nil
|
||||
@@ -1024,7 +1024,7 @@
|
||||
;; async-aser-cond-clojure — clojure-style cond for aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-cond-clojure
|
||||
(define-async async-aser-cond-clojure :effects [render io]
|
||||
(fn ((clauses :as list) (env :as dict) ctx)
|
||||
(if (< (len clauses) 2)
|
||||
nil
|
||||
@@ -1044,7 +1044,7 @@
|
||||
;; async-aser-case-loop — case dispatch for aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-case-loop
|
||||
(define-async async-aser-case-loop :effects [render io]
|
||||
(fn (match-val (clauses :as list) (env :as dict) ctx)
|
||||
(if (< (len clauses) 2)
|
||||
nil
|
||||
@@ -1064,7 +1064,7 @@
|
||||
;; async-aser-thread-first — -> form in aser mode
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-thread-first
|
||||
(define-async async-aser-thread-first :effects [render io]
|
||||
(fn ((args :as list) (env :as dict) ctx)
|
||||
(let ((result (async-eval (first args) env ctx)))
|
||||
(for-each
|
||||
@@ -1084,7 +1084,7 @@
|
||||
;; async-invoke-or-lambda — invoke a callable or lambda with args
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-invoke-or-lambda
|
||||
(define-async async-invoke-or-lambda :effects [render io]
|
||||
(fn (f (args :as list) (env :as dict) ctx)
|
||||
(cond
|
||||
(and (callable? f) (not (lambda? f)) (not (component? f)))
|
||||
@@ -1106,7 +1106,7 @@
|
||||
;; Async aser HO forms (map, map-indexed, for-each)
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define-async async-aser-ho-map
|
||||
(define-async async-aser-ho-map :effects [render io]
|
||||
(fn ((args :as list) (env :as dict) ctx)
|
||||
(let ((f (async-eval (first args) env ctx))
|
||||
(coll (async-eval (nth args 1) env ctx))
|
||||
@@ -1122,7 +1122,7 @@
|
||||
results)))
|
||||
|
||||
|
||||
(define-async async-aser-ho-map-indexed
|
||||
(define-async async-aser-ho-map-indexed :effects [render io]
|
||||
(fn ((args :as list) (env :as dict) ctx)
|
||||
(let ((f (async-eval (first args) env ctx))
|
||||
(coll (async-eval (nth args 1) env ctx))
|
||||
@@ -1141,7 +1141,7 @@
|
||||
results)))
|
||||
|
||||
|
||||
(define-async async-aser-ho-for-each
|
||||
(define-async async-aser-ho-for-each :effects [render io]
|
||||
(fn ((args :as list) (env :as dict) ctx)
|
||||
(let ((f (async-eval (first args) env ctx))
|
||||
(coll (async-eval (nth args 1) env ctx))
|
||||
@@ -1172,7 +1172,7 @@
|
||||
;; (sx-expr? x) — check if SxExpr
|
||||
;; (set-expand-components!) — enable component expansion context var
|
||||
|
||||
(define-async async-eval-slot-inner
|
||||
(define-async async-eval-slot-inner :effects [render io]
|
||||
(fn (expr (env :as dict) ctx)
|
||||
;; NOTE: Uses statement-form let + set! to avoid expression-context
|
||||
;; let (IIFE lambdas) which can't contain await in Python.
|
||||
@@ -1198,7 +1198,7 @@
|
||||
(make-sx-expr (serialize result))))))))
|
||||
|
||||
|
||||
(define-async async-maybe-expand-result
|
||||
(define-async async-maybe-expand-result :effects [render io]
|
||||
(fn (result (env :as dict) ctx)
|
||||
;; If the aser result is a component call string like "(~foo ...)",
|
||||
;; re-parse and expand it. This handles indirect component references
|
||||
|
||||
Reference in New Issue
Block a user