Files
rose-ash/shared/sx/evaluator.py
giles d8cddbd971 Replace hand-written evaluator with bootstrapped spec, emit flat Python
- evaluator.py: replace 1200 lines of hand-written eval with thin shim
  that re-exports from bootstrapped sx_ref.py
- bootstrap_py.py: emit all fn-bodied defines as `def` (not `lambda`),
  flatten tail-position if/cond/case/when to if/elif with returns,
  fix &rest handling in _emit_define_as_def
- platform_py.py: EvalError imports from evaluator.py so catches work
- __init__.py: remove SX_USE_REF conditional, always use bootstrapped
- tests/run.py: reset render_active after render tests for isolation
- Removes setrecursionlimit(5000) hack — no longer needed with flat code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 09:18:17 +00:00

95 lines
2.7 KiB
Python

"""
S-expression evaluator — thin shim over bootstrapped sx_ref.py.
All evaluation logic lives in the spec (shared/sx/ref/eval.sx) and is
bootstrapped to Python (shared/sx/ref/sx_ref.py). This module re-exports
the public API and internal helpers under their historical names so that
existing callers don't need updating.
Imports are lazy (inside functions/properties) to avoid circular imports
during bootstrapping: bootstrap_py.py → parser → __init__ → evaluator → sx_ref.
"""
from __future__ import annotations
def _ref():
"""Lazy import of the bootstrapped evaluator."""
from .ref import sx_ref
return sx_ref
# ---------------------------------------------------------------------------
# Public API — these are the most used, so we make them importable directly
# ---------------------------------------------------------------------------
class EvalError(Exception):
"""Error during expression evaluation.
Delegates to the bootstrapped EvalError at runtime but is defined here
so imports don't fail during bootstrapping.
"""
pass
def evaluate(expr, env=None):
return _ref().evaluate(expr, env)
def make_env(**kwargs):
return _ref().make_env(**kwargs)
# ---------------------------------------------------------------------------
# Internal helpers — used by html.py, async_eval.py, handlers.py, etc.
# ---------------------------------------------------------------------------
def _eval(expr, env):
return _ref().eval_expr(expr, env)
def _trampoline(val):
return _ref().trampoline(val)
def _call_lambda(fn, args, caller_env):
return _ref().call_lambda(fn, args, caller_env)
def _call_component(comp, raw_args, env):
return _ref().call_component(comp, raw_args, env)
def _expand_macro(macro, raw_args, env):
return _ref().expand_macro(macro, raw_args, env)
# ---------------------------------------------------------------------------
# Special-form wrappers: callers pass (expr, env) with expr[0] = head symbol.
# sx_ref.py special forms take (args, env) where args = expr[1:].
# ---------------------------------------------------------------------------
def _sf_defcomp(expr, env):
return _ref().sf_defcomp(expr[1:], env)
def _sf_defisland(expr, env):
return _ref().sf_defisland(expr[1:], env)
def _sf_defstyle(expr, env):
return _ref().sf_defstyle(expr[1:], env)
def _sf_defmacro(expr, env):
return _ref().sf_defmacro(expr[1:], env)
def _sf_defhandler(expr, env):
return _ref().sf_defhandler(expr[1:], env)
def _sf_defpage(expr, env):
return _ref().sf_defpage(expr[1:], env)
def _sf_defquery(expr, env):
return _ref().sf_defquery(expr[1:], env)
def _sf_defaction(expr, env):
return _ref().sf_defaction(expr[1:], env)