Decouple core evaluator from web platform, extract libraries

The core evaluator (spec/evaluator.sx) is now the irreducible computational
core with zero web, rendering, or type-system knowledge. 2531 → 2313 lines.

- Add extensible special form registry (*custom-special-forms* + register-special-form!)
- Add render dispatch hooks (*render-check* / *render-fn*) replacing hardcoded render-active?/is-render-expr?/render-expr
- Extract freeze scopes → spec/freeze.sx (library, not core)
- Extract content addressing → spec/content.sx (library, not core)
- Move sf-deftype/sf-defeffect → spec/types.sx (self-registering)
- Move sf-defstyle → web/forms.sx (self-registering with all web forms)
- Move web tests (defpage, streaming) → web/tests/test-forms.sx
- Add is-else-clause? helper (replaces 5 inline patterns)
- Make escape-html/escape-attr library functions in render.sx (pure SX, not platform-provided)
- Add foundations plan: Step 3.5 (data representations), Step 3.7 (verified components), OCaml for Step 4d
- Update all three bootstrappers (JS 957/957, Python 744/744, OCaml 952/952)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-16 08:37:50 +00:00
parent 5ab3ecb7e0
commit 06666ac8c4
21 changed files with 886 additions and 603 deletions

View File

@@ -1,9 +1,9 @@
;; ==========================================================================
;; forms.sx — Server-side definition forms
;; forms.sx — Web-platform definition forms
;;
;; Platform-specific special forms for declaring handlers, pages, queries,
;; and actions. These parse &key parameter lists and create typed definition
;; objects that the server runtime uses for routing and execution.
;; Platform-specific special forms for declaring styles, handlers, pages,
;; queries, and actions. These are NOT part of the core evaluator — they
;; register themselves via register-special-form! at load time.
;;
;; When SX moves to isomorphic execution, these forms will have different
;; platform bindings on client vs server. The spec stays the same — only
@@ -276,3 +276,26 @@
(fn (data)
(and (= (type-of data) "list")
(every? (fn (item) (= (type-of item) "dict")) data))))
;; --------------------------------------------------------------------------
;; defstyle — bind name to evaluated style expression
;; --------------------------------------------------------------------------
(define sf-defstyle
(fn ((args :as list) (env :as dict))
(let ((name-sym (first args))
(value (trampoline (eval-expr (nth args 1) env))))
(env-bind! env (symbol-name name-sym) value)
value)))
;; --------------------------------------------------------------------------
;; Registration — make these available as special forms in the evaluator
;; --------------------------------------------------------------------------
(register-special-form! "defstyle" sf-defstyle)
(register-special-form! "defhandler" sf-defhandler)
(register-special-form! "defpage" sf-defpage)
(register-special-form! "defquery" sf-defquery)
(register-special-form! "defaction" sf-defaction)