Complete Python eval removal: epoch protocol, scope consolidation, JIT fixes
Route all rendering through OCaml bridge — render_to_html no longer uses Python async_eval. Fix register_components to parse &key params and &rest children from defcomp forms. Remove all dead sx_ref.py imports. Epoch protocol (prevents pipe desync): - Every command prefixed with (epoch N), all responses tagged with epoch - Both sides discard stale-epoch messages — desync structurally impossible - OCaml main loop discards stale io-responses between commands Consolidate scope primitives into sx_scope.ml: - Single source of truth for scope-push!/pop!/peek, collect!/collected, emit!/emitted, context, and 12 other scope operations - Removes duplicate registrations from sx_server.ml (including bugs where scope-emit! and clear-collected! were registered twice with different impls) - Bind scope prims into env so JIT VM finds them via OP_GLOBAL_GET JIT VM fixes: - Trampoline thunks before passing args to CALL_PRIM - as_list resolves thunks via _sx_trampoline_fn - len handles all value types (Bool, Number, RawHTML, SxExpr, Spread, etc.) Other fixes: - ~cssx/tw signature: (tokens) → (&key tokens) to match callers - Minimal Python evaluator in html.py for sync sx() Jinja function - Python scope primitive stubs (thread-local) for non-OCaml paths - Reader macro resolution via OcamlSync instead of sx_ref.py Tests: 1114 OCaml, 1078 JS, 35 Python regression, 6/6 Playwright SSR Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,10 +38,11 @@ def _resolve_sx_reader_macro(name: str):
|
||||
If a file like z3.sx defines (define z3-translate ...), then #z3 is
|
||||
automatically available as a reader macro without any Python registration.
|
||||
Looks for {name}-translate as a Lambda in the component env.
|
||||
|
||||
Uses the synchronous OCaml bridge (ocaml_sync) when available.
|
||||
"""
|
||||
try:
|
||||
from .jinja_bridge import get_component_env
|
||||
from .ref.sx_ref import trampoline as _trampoline, call_lambda as _call_lambda
|
||||
from .types import Lambda
|
||||
except ImportError:
|
||||
return None
|
||||
@@ -49,10 +50,18 @@ def _resolve_sx_reader_macro(name: str):
|
||||
fn = env.get(f"{name}-translate")
|
||||
if fn is None or not isinstance(fn, Lambda):
|
||||
return None
|
||||
# Return a Python callable that invokes the SX lambda
|
||||
def _sx_handler(expr):
|
||||
return _trampoline(_call_lambda(fn, [expr], env))
|
||||
return _sx_handler
|
||||
# Use sync OCaml bridge to invoke the lambda
|
||||
try:
|
||||
from .ocaml_sync import OcamlSync
|
||||
_sync = OcamlSync()
|
||||
_sync.start()
|
||||
def _sx_handler(expr):
|
||||
from .parser import serialize as _ser
|
||||
result = _sync.eval(f"({name}-translate {_ser(expr)})")
|
||||
return parse(result) if result else expr
|
||||
return _sx_handler
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user