Wire deps.sx into both bootstrappers, rebootstrap Python + JS

deps.sx is now a spec module that both bootstrap_py.py and bootstrap_js.py
can include via --spec-modules deps. Platform functions (component-deps,
component-set-deps!, component-css-classes, env-components, regex-find-all,
scan-css-classes) implemented natively in both Python and JS.

- Fix deps.sx: env-get-or → env-get, extract nested define to top-level
- bootstrap_py.py: SPEC_MODULES, PLATFORM_DEPS_PY, mangle entries, CLI arg
- bootstrap_js.py: SPEC_MODULES, PLATFORM_DEPS_JS, mangle entries, CLI arg
- Regenerate sx_ref.py and sx-ref.js with deps module
- deps.py: thin dispatcher (SX_USE_REF=1 → bootstrapped, else fallback)
- scan_components_from_sx now returns ~prefixed names (consistent with spec)

Verified: 541 Python tests pass, JS deps tested with Node.js, both code
paths (fallback + bootstrapped) produce identical results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 11:55:32 +00:00
parent 6739343a06
commit 4c97b03dda
7 changed files with 692 additions and 84 deletions

View File

@@ -8,19 +8,21 @@
;; All functions are pure — no IO, no platform-specific operations.
;; Each host bootstraps this to native code alongside eval.sx/render.sx.
;;
;; Platform interface (provided by host):
;; From eval.sx platform (already provided by every host):
;; (type-of x) → type string
;; (symbol-name s) → string name of symbol
;; (component-body c) → unevaluated AST of component body
;; (component-name c) → string name (without ~)
;;
;; Already available from eval.sx platform:
;; (type-of x), (symbol-name s)
;;
;; New platform functions for deps:
;; (component-body c) → component body AST
;; (component-name c) → component name string
;; (macro-body m) → macro body AST
;; (env-get env k) → value or nil
;;
;; New platform functions for deps (each host implements):
;; (component-deps c) → cached deps list (may be empty)
;; (component-set-deps! c d)→ cache deps on component
;; (component-css-classes c)→ pre-scanned CSS class list
;; (env-components env) → list of component/macro names in env
;; (regex-find-all pat src) → list of capture group 1 matches
;; (scan-css-classes src) → list of CSS class strings from source
;; ==========================================================================
@@ -66,24 +68,26 @@
;; Given a component name and an environment, compute all components
;; that it can transitively render. Handles cycles via seen-set.
(define transitive-deps-walk
(fn (n seen env)
(when (not (contains? seen n))
(append! seen n)
(let ((val (env-get env n)))
(cond
(= (type-of val) "component")
(for-each (fn (ref) (transitive-deps-walk ref seen env))
(scan-refs (component-body val)))
(= (type-of val) "macro")
(for-each (fn (ref) (transitive-deps-walk ref seen env))
(scan-refs (macro-body val)))
:else nil)))))
(define transitive-deps
(fn (name env)
(let ((seen (list))
(key (if (starts-with? name "~") name (str "~" name))))
(define walk
(fn (n)
(when (not (contains? seen n))
(append! seen n)
(let ((val (env-get-or env n nil)))
(cond
(= (type-of val) "component")
(for-each walk (scan-refs (component-body val)))
(= (type-of val) "macro")
(for-each walk (scan-refs (macro-body val)))
:else nil)))))
(walk key)
(transitive-deps-walk key seen env)
(filter (fn (x) (not (= x key))) seen))))
@@ -101,7 +105,7 @@
(fn (env)
(for-each
(fn (name)
(let ((val (env-get-or env name nil)))
(let ((val (env-get env name)))
(when (= (type-of val) "component")
(component-set-deps! val (transitive-deps name env)))))
(env-components env))))
@@ -138,7 +142,7 @@
(fn (name)
(when (not (contains? all-needed name))
(append! all-needed name))
(let ((val (env-get-or env name nil)))
(let ((val (env-get env name)))
(let ((deps (if (and (= (type-of val) "component")
(not (empty? (component-deps val))))
(component-deps val)
@@ -185,7 +189,7 @@
;; Collect classes from needed components
(for-each
(fn (name)
(let ((val (env-get-or env name nil)))
(let ((val (env-get env name)))
(when (= (type-of val) "component")
(for-each
(fn (cls)
@@ -211,7 +215,7 @@
;; From eval.sx (already provided):
;; (type-of x) → type string
;; (symbol-name s) → string name of symbol
;; (env-get-or env k d) → value or default
;; (env-get env k) → value or nil
;;
;; New for deps.sx (each host implements):
;; (component-body c) → AST body of component