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:
2026-03-11 23:22:34 +00:00
parent 0f9b449315
commit 2f42e8826c
16 changed files with 274 additions and 259 deletions

View File

@@ -11,7 +11,7 @@
;; ==========================================================================
(define render-to-sx
(define render-to-sx :effects [render]
(fn (expr (env :as dict))
(let ((result (aser expr env)))
;; aser-call already returns serialized SX strings;
@@ -20,7 +20,7 @@
result
(serialize result)))))
(define aser
(define aser :effects [render]
(fn ((expr :as any) (env :as dict))
;; Evaluate for SX wire format — serialize rendering forms,
;; evaluate control flow and function calls.
@@ -51,7 +51,7 @@
:else expr)))
(define aser-list
(define aser-list :effects [render]
(fn ((expr :as list) (env :as dict))
(let ((head (first expr))
(args (rest expr)))
@@ -103,7 +103,7 @@
:else (error (str "Not callable: " (inspect f)))))))))))
(define aser-fragment
(define aser-fragment :effects [render]
(fn ((children :as list) (env :as dict))
;; Serialize (<> child1 child2 ...) to sx source string
;; Must flatten list results (e.g. from map/filter) to avoid nested parens
@@ -125,7 +125,7 @@
(str "(<> " (join " " parts) ")")))))
(define aser-call
(define aser-call :effects [render]
(fn ((name :as string) (args :as list) (env :as dict))
;; Serialize (name :key val child ...) — evaluate args but keep as sx
;; Uses for-each + mutable state (not reduce) so bootstrapper emits for-loops
@@ -177,11 +177,11 @@
(list "map" "map-indexed" "filter" "reduce"
"some" "every?" "for-each"))
(define special-form?
(define special-form? :effects []
(fn ((name :as string))
(contains? SPECIAL_FORM_NAMES name)))
(define ho-form?
(define ho-form? :effects []
(fn ((name :as string))
(contains? HO_FORM_NAMES name)))
@@ -194,7 +194,7 @@
;; through aser (serializing tags/components instead of rendering HTML).
;; Definition forms evaluate for side effects and return nil.
(define aser-special
(define aser-special :effects [render]
(fn ((name :as string) (expr :as list) (env :as dict))
(let ((args (rest expr)))
(cond
@@ -315,7 +315,7 @@
;; Helper: case dispatch for aser mode
(define eval-case-aser
(define eval-case-aser :effects [render]
(fn (match-val (clauses :as list) (env :as dict))
(if (< (len clauses) 2)
nil