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:
@@ -423,23 +423,39 @@ async def _asf_define(expr, env, ctx):
|
||||
|
||||
|
||||
async def _asf_defcomp(expr, env, ctx):
|
||||
from .ref.sx_ref import sf_defcomp
|
||||
return sf_defcomp(expr[1:], env)
|
||||
# Component definitions are handled by OCaml kernel at load time.
|
||||
# Python-side: just store a minimal Component in env for reference.
|
||||
from .types import Component
|
||||
name_sym = expr[1]
|
||||
name = name_sym.name if hasattr(name_sym, 'name') else str(name_sym)
|
||||
env[name] = Component(name=name.lstrip("~"), params=[], has_children=False,
|
||||
body=expr[-1], closure={})
|
||||
return NIL
|
||||
|
||||
|
||||
async def _asf_defstyle(expr, env, ctx):
|
||||
from .ref.sx_ref import sf_defstyle
|
||||
return sf_defstyle(expr[1:], env)
|
||||
# Style definitions handled by OCaml kernel.
|
||||
return NIL
|
||||
|
||||
|
||||
async def _asf_defmacro(expr, env, ctx):
|
||||
from .ref.sx_ref import sf_defmacro
|
||||
return sf_defmacro(expr[1:], env)
|
||||
# Macro definitions handled by OCaml kernel.
|
||||
from .types import Macro
|
||||
name_sym = expr[1]
|
||||
name = name_sym.name if hasattr(name_sym, 'name') else str(name_sym)
|
||||
params_form = expr[2] if len(expr) > 3 else []
|
||||
param_names = [p.name for p in params_form if isinstance(p, Symbol) and not p.name.startswith("&")]
|
||||
rest_param = None
|
||||
for i, p in enumerate(params_form):
|
||||
if isinstance(p, Symbol) and p.name == "&rest" and i + 1 < len(params_form):
|
||||
rest_param = params_form[i + 1].name if isinstance(params_form[i + 1], Symbol) else None
|
||||
env[name] = Macro(name=name, params=param_names, rest_param=rest_param, body=expr[-1])
|
||||
return NIL
|
||||
|
||||
|
||||
async def _asf_defhandler(expr, env, ctx):
|
||||
from .ref.sx_ref import sf_defhandler
|
||||
return sf_defhandler(expr[1:], env)
|
||||
# Handler definitions handled by OCaml kernel.
|
||||
return NIL
|
||||
|
||||
|
||||
async def _asf_begin(expr, env, ctx):
|
||||
@@ -601,9 +617,12 @@ async def _asf_reset(expr, env, ctx):
|
||||
from .types import NIL
|
||||
_ASYNC_RESET_RESUME.append(value if value is not None else NIL)
|
||||
try:
|
||||
# Sync re-evaluation; the async caller will trampoline
|
||||
from .ref.sx_ref import eval_expr as sync_eval, trampoline as _trampoline
|
||||
return _trampoline(sync_eval(body, env))
|
||||
# Continuations are handled by OCaml kernel.
|
||||
# Python-side cont_fn should not be called in normal operation.
|
||||
raise RuntimeError(
|
||||
"Python-side continuation invocation not supported — "
|
||||
"use OCaml bridge for shift/reset"
|
||||
)
|
||||
finally:
|
||||
_ASYNC_RESET_RESUME.pop()
|
||||
k = Continuation(cont_fn)
|
||||
|
||||
Reference in New Issue
Block a user