Delete evaluator.py shim: all imports go directly to bootstrapped sx_ref.py

EvalError moved to types.py. All 27 files updated to import eval_expr,
trampoline, call_lambda, etc. directly from shared.sx.ref.sx_ref instead
of through the evaluator.py indirection layer. 320/320 spec tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 11:15:48 +00:00
parent 4c4806c8dd
commit 29c90a625b
27 changed files with 65 additions and 158 deletions

View File

@@ -31,11 +31,8 @@ from .parser import (
parse_all, parse_all,
serialize, serialize,
) )
from .evaluator import ( from .types import EvalError
EvalError, from .ref.sx_ref import evaluate, make_env
evaluate,
make_env,
)
from .primitives import ( from .primitives import (
all_primitives, all_primitives,

View File

@@ -53,7 +53,8 @@ from .types import Component, Island, Keyword, Lambda, Macro, NIL, Symbol
_expand_components: contextvars.ContextVar[bool] = contextvars.ContextVar( _expand_components: contextvars.ContextVar[bool] = contextvars.ContextVar(
"_expand_components", default=False "_expand_components", default=False
) )
from .evaluator import _expand_macro, EvalError from .ref.sx_ref import expand_macro as _expand_macro
from .types import EvalError
from .primitives import _PRIMITIVES from .primitives import _PRIMITIVES
from .primitives_io import IO_PRIMITIVES, RequestContext, execute_io from .primitives_io import IO_PRIMITIVES, RequestContext, execute_io
from .parser import SxExpr, serialize from .parser import SxExpr, serialize
@@ -420,23 +421,23 @@ async def _asf_define(expr, env, ctx):
async def _asf_defcomp(expr, env, ctx): async def _asf_defcomp(expr, env, ctx):
from .evaluator import _sf_defcomp from .ref.sx_ref import sf_defcomp
return _sf_defcomp(expr, env) return sf_defcomp(expr[1:], env)
async def _asf_defstyle(expr, env, ctx): async def _asf_defstyle(expr, env, ctx):
from .evaluator import _sf_defstyle from .ref.sx_ref import sf_defstyle
return _sf_defstyle(expr, env) return sf_defstyle(expr[1:], env)
async def _asf_defmacro(expr, env, ctx): async def _asf_defmacro(expr, env, ctx):
from .evaluator import _sf_defmacro from .ref.sx_ref import sf_defmacro
return _sf_defmacro(expr, env) return sf_defmacro(expr[1:], env)
async def _asf_defhandler(expr, env, ctx): async def _asf_defhandler(expr, env, ctx):
from .evaluator import _sf_defhandler from .ref.sx_ref import sf_defhandler
return _sf_defhandler(expr, env) return sf_defhandler(expr[1:], env)
async def _asf_begin(expr, env, ctx): async def _asf_begin(expr, env, ctx):
@@ -599,7 +600,7 @@ async def _asf_reset(expr, env, ctx):
_ASYNC_RESET_RESUME.append(value if value is not None else NIL) _ASYNC_RESET_RESUME.append(value if value is not None else NIL)
try: try:
# Sync re-evaluation; the async caller will trampoline # Sync re-evaluation; the async caller will trampoline
from .evaluator import _eval as sync_eval, _trampoline from .ref.sx_ref import eval_expr as sync_eval, trampoline as _trampoline
return _trampoline(sync_eval(body, env)) return _trampoline(sync_eval(body, env))
finally: finally:
_ASYNC_RESET_RESUME.pop() _ASYNC_RESET_RESUME.pop()

View File

@@ -1,94 +0,0 @@
"""
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)

View File

@@ -70,10 +70,7 @@ def load_handler_file(filepath: str, service_name: str) -> list[HandlerDef]:
"""Parse an .sx file, evaluate it, and register any HandlerDef values.""" """Parse an .sx file, evaluate it, and register any HandlerDef values."""
from .parser import parse_all from .parser import parse_all
import os import os
if os.environ.get("SX_USE_REF") == "1": from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
else:
from .evaluator import _eval as _raw_eval, _trampoline
_eval = lambda expr, env: _trampoline(_raw_eval(expr, env)) _eval = lambda expr, env: _trampoline(_raw_eval(expr, env))
from .jinja_bridge import get_component_env from .jinja_bridge import get_component_env

View File

@@ -28,7 +28,7 @@ import contextvars
from typing import Any from typing import Any
from .types import Component, Island, Keyword, Lambda, Macro, NIL, Symbol from .types import Component, Island, Keyword, Lambda, Macro, NIL, Symbol
from .evaluator import _eval as _raw_eval, _call_component as _raw_call_component, _expand_macro, _trampoline from .ref.sx_ref import eval_expr as _raw_eval, call_component as _raw_call_component, expand_macro as _expand_macro, trampoline as _trampoline
def _eval(expr, env): def _eval(expr, env):
"""Evaluate and unwrap thunks — all html.py _eval calls are non-tail.""" """Evaluate and unwrap thunks — all html.py _eval calls are non-tail."""

View File

@@ -229,10 +229,7 @@ def register_components(sx_source: str) -> None:
(div :class "..." (div :class "..." title))))) (div :class "..." (div :class "..." title)))))
''') ''')
""" """
if _os.environ.get("SX_USE_REF") == "1": from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
else:
from .evaluator import _eval as _raw_eval, _trampoline
_eval = lambda expr, env: _trampoline(_raw_eval(expr, env)) _eval = lambda expr, env: _trampoline(_raw_eval(expr, env))
from .parser import parse_all from .parser import parse_all
from .css_registry import scan_classes_from_sx from .css_registry import scan_classes_from_sx

View File

@@ -127,7 +127,7 @@ def get_page_helpers(service: str) -> dict[str, Any]:
def load_page_file(filepath: str, service_name: str) -> list[PageDef]: def load_page_file(filepath: str, service_name: str) -> list[PageDef]:
"""Parse an .sx file, evaluate it, and register any PageDef values.""" """Parse an .sx file, evaluate it, and register any PageDef values."""
from .parser import parse_all from .parser import parse_all
from .evaluator import _eval as _raw_eval, _trampoline from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
_eval = lambda expr, env: _trampoline(_raw_eval(expr, env)) _eval = lambda expr, env: _trampoline(_raw_eval(expr, env))
from .jinja_bridge import get_component_env from .jinja_bridge import get_component_env

View File

@@ -41,7 +41,7 @@ def _resolve_sx_reader_macro(name: str):
""" """
try: try:
from .jinja_bridge import get_component_env from .jinja_bridge import get_component_env
from .evaluator import _trampoline, _call_lambda from .ref.sx_ref import trampoline as _trampoline, call_lambda as _call_lambda
from .types import Lambda from .types import Lambda
except ImportError: except ImportError:
return None return None

View File

@@ -78,7 +78,7 @@ def clear(service: str | None = None) -> None:
def load_query_file(filepath: str, service_name: str) -> list[QueryDef]: def load_query_file(filepath: str, service_name: str) -> list[QueryDef]:
"""Parse an .sx file and register any defquery definitions.""" """Parse an .sx file and register any defquery definitions."""
from .parser import parse_all from .parser import parse_all
from .evaluator import _eval as _raw_eval, _trampoline from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
_eval = lambda expr, env: _trampoline(_raw_eval(expr, env)) _eval = lambda expr, env: _trampoline(_raw_eval(expr, env))
from .jinja_bridge import get_component_env from .jinja_bridge import get_component_env
@@ -103,7 +103,7 @@ def load_query_file(filepath: str, service_name: str) -> list[QueryDef]:
def load_action_file(filepath: str, service_name: str) -> list[ActionDef]: def load_action_file(filepath: str, service_name: str) -> list[ActionDef]:
"""Parse an .sx file and register any defaction definitions.""" """Parse an .sx file and register any defaction definitions."""
from .parser import parse_all from .parser import parse_all
from .evaluator import _eval as _raw_eval, _trampoline from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
_eval = lambda expr, env: _trampoline(_raw_eval(expr, env)) _eval = lambda expr, env: _trampoline(_raw_eval(expr, env))
from .jinja_bridge import get_component_env from .jinja_bridge import get_component_env

View File

@@ -143,7 +143,7 @@ def _emit_py(suites: list[dict], preamble: list) -> str:
lines.append('') lines.append('')
lines.append('import pytest') lines.append('import pytest')
lines.append('from shared.sx.parser import parse_all') lines.append('from shared.sx.parser import parse_all')
lines.append('from shared.sx.evaluator import _eval, _trampoline') lines.append('from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline')
lines.append('') lines.append('')
lines.append('') lines.append('')
lines.append(f"_PREAMBLE = '''{preamble_escaped}'''") lines.append(f"_PREAMBLE = '''{preamble_escaped}'''")

View File

@@ -600,7 +600,7 @@ def sx_expr_source(x):
try: try:
from shared.sx.evaluator import EvalError from shared.sx.types import EvalError
except ImportError: except ImportError:
class EvalError(Exception): class EvalError(Exception):
pass pass

View File

@@ -39,7 +39,7 @@ def _get_z3_env() -> dict[str, Any]:
return _z3_env return _z3_env
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.evaluator import make_env, _eval, _trampoline from shared.sx.ref.sx_ref import make_env, eval_expr as _eval, trampoline as _trampoline
env = make_env() env = make_env()
z3_path = os.path.join(os.path.dirname(__file__), "z3.sx") z3_path = os.path.join(os.path.dirname(__file__), "z3.sx")
@@ -60,7 +60,7 @@ def z3_translate(expr: Any) -> str:
Delegates to z3-translate defined in z3.sx. Delegates to z3-translate defined in z3.sx.
""" """
from shared.sx.evaluator import _trampoline, _call_lambda from shared.sx.ref.sx_ref import trampoline as _trampoline, call_lambda as _call_lambda
env = _get_z3_env() env = _get_z3_env()
return _trampoline(_call_lambda(env["z3-translate"], [expr], env)) return _trampoline(_call_lambda(env["z3-translate"], [expr], env))
@@ -72,7 +72,7 @@ def z3_translate_file(source: str) -> str:
Delegates to z3-translate-file defined in z3.sx. Delegates to z3-translate-file defined in z3.sx.
""" """
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.evaluator import _trampoline, _call_lambda from shared.sx.ref.sx_ref import trampoline as _trampoline, call_lambda as _call_lambda
env = _get_z3_env() env = _get_z3_env()
exprs = parse_all(source) exprs = parse_all(source)

View File

@@ -49,7 +49,7 @@ def load_js_sx() -> dict:
exprs = parse_all(source) exprs = parse_all(source)
from shared.sx.evaluator import evaluate, make_env from shared.sx.ref.sx_ref import evaluate, make_env
env = make_env() env = make_env()
for expr in exprs: for expr in exprs:
@@ -74,7 +74,7 @@ def compile_ref_to_js(
spec_modules: List of spec modules (deps, router, signals). None = auto. spec_modules: List of spec modules (deps, router, signals). None = auto.
""" """
from datetime import datetime, timezone from datetime import datetime, timezone
from shared.sx.evaluator import evaluate from shared.sx.ref.sx_ref import evaluate
ref_dir = _HERE ref_dir = _HERE
env = load_js_sx() env = load_js_sx()

View File

@@ -38,7 +38,7 @@ def load_py_sx(evaluator_env: dict) -> dict:
exprs = parse_all(source) exprs = parse_all(source)
# Import the evaluator # Import the evaluator
from shared.sx.evaluator import evaluate, make_env from shared.sx.ref.sx_ref import evaluate, make_env
env = make_env() env = make_env()
for expr in exprs: for expr in exprs:
@@ -60,7 +60,7 @@ def extract_defines(source: str) -> list[tuple[str, list]]:
def main(): def main():
from shared.sx.evaluator import evaluate from shared.sx.ref.sx_ref import evaluate
# Load py.sx into evaluator # Load py.sx into evaluator
env = load_py_sx({}) env = load_py_sx({})

View File

@@ -559,7 +559,7 @@ def sx_expr_source(x):
try: try:
from shared.sx.evaluator import EvalError from shared.sx.types import EvalError
except ImportError: except ImportError:
class EvalError(Exception): class EvalError(Exception):
pass pass

View File

@@ -31,7 +31,7 @@ import asyncio
from typing import Any from typing import Any
from .types import Component, Keyword, Lambda, NIL, Symbol from .types import Component, Keyword, Lambda, NIL, Symbol
from .evaluator import _eval as _raw_eval, _trampoline from .ref.sx_ref import eval_expr as _raw_eval, trampoline as _trampoline
def _eval(expr, env): def _eval(expr, env):
"""Evaluate and unwrap thunks — all resolver.py _eval calls are non-tail.""" """Evaluate and unwrap thunks — all resolver.py _eval calls are non-tail."""

View File

@@ -20,7 +20,7 @@ _PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..", ".."))
sys.path.insert(0, _PROJECT) sys.path.insert(0, _PROJECT)
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.evaluator import _eval, _trampoline, _call_lambda from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline, call_lambda as _call_lambda
from shared.sx.types import Symbol, Keyword, Lambda, NIL, Component, Island from shared.sx.types import Symbol, Keyword, Lambda, NIL, Component, Island
# --- Test state --- # --- Test state ---

View File

@@ -21,7 +21,7 @@ class TestJsSxTranslation:
def _translate(self, sx_source: str) -> str: def _translate(self, sx_source: str) -> str:
"""Translate a single SX expression to JS using js.sx.""" """Translate a single SX expression to JS using js.sx."""
from shared.sx.evaluator import evaluate from shared.sx.ref.sx_ref import evaluate
env = load_js_sx() env = load_js_sx()
expr = parse(sx_source) expr = parse(sx_source)
env["_def_expr"] = expr env["_def_expr"] = expr

View File

@@ -18,7 +18,7 @@ from shared.sx.deps import (
def make_env(*sx_sources: str) -> dict: def make_env(*sx_sources: str) -> dict:
"""Parse and evaluate component definitions into an env dict.""" """Parse and evaluate component definitions into an env dict."""
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
env: dict = {} env: dict = {}
for source in sx_sources: for source in sx_sources:
exprs = parse_all(source) exprs = parse_all(source)

View File

@@ -23,7 +23,7 @@ from shared.sx.deps import (
def make_env(*sx_sources: str) -> dict: def make_env(*sx_sources: str) -> dict:
"""Parse and evaluate component definitions into an env dict.""" """Parse and evaluate component definitions into an env dict."""
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
env: dict = {} env: dict = {}
for source in sx_sources: for source in sx_sources:
exprs = parse_all(source) exprs = parse_all(source)

View File

@@ -20,7 +20,7 @@ from shared.sx.deps import (
def make_env(*sx_sources: str) -> dict: def make_env(*sx_sources: str) -> dict:
"""Parse and evaluate component definitions into an env dict.""" """Parse and evaluate component definitions into an env dict."""
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
env: dict = {} env: dict = {}
for source in sx_sources: for source in sx_sources:
exprs = parse_all(source) exprs = parse_all(source)
@@ -282,7 +282,7 @@ class TestIoRoutingLogic:
""" """
def _eval(self, src, env): def _eval(self, src, env):
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
result = None result = None
for expr in parse_all(src): for expr in parse_all(src):
result = _trampoline(_eval(expr, env)) result = _trampoline(_eval(expr, env))

View File

@@ -156,7 +156,7 @@ class TestDataPageDeps:
def test_deps_computed_for_data_page(self): def test_deps_computed_for_data_page(self):
from shared.sx.deps import components_needed from shared.sx.deps import components_needed
from shared.sx.parser import parse_all as pa from shared.sx.parser import parse_all as pa
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
# Define a component # Define a component
env = {} env = {}
@@ -172,7 +172,7 @@ class TestDataPageDeps:
def test_deps_transitive_for_data_page(self): def test_deps_transitive_for_data_page(self):
from shared.sx.deps import components_needed from shared.sx.deps import components_needed
from shared.sx.parser import parse_all as pa from shared.sx.parser import parse_all as pa
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
env = {} env = {}
source = """ source = """
@@ -205,7 +205,7 @@ class TestDataPipelineSimulation:
def test_full_pipeline(self): def test_full_pipeline(self):
from shared.sx.parser import parse_all as pa from shared.sx.parser import parse_all as pa
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
# 1. Define a component that uses only pure primitives # 1. Define a component that uses only pure primitives
env = {} env = {}
@@ -236,7 +236,7 @@ class TestDataPipelineSimulation:
def test_pipeline_with_list_data(self): def test_pipeline_with_list_data(self):
from shared.sx.parser import parse_all as pa from shared.sx.parser import parse_all as pa
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
env = {} env = {}
for expr in pa(''' for expr in pa('''
@@ -262,7 +262,7 @@ class TestDataPipelineSimulation:
def test_pipeline_data_isolation(self): def test_pipeline_data_isolation(self):
"""Different data for the same content produces different results.""" """Different data for the same content produces different results."""
from shared.sx.parser import parse_all as pa from shared.sx.parser import parse_all as pa
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
env = {} env = {}
for expr in pa('(defcomp ~page (&key title count) (str title ": " count))'): for expr in pa('(defcomp ~page (&key title count) (str title ": " count))'):
@@ -298,7 +298,7 @@ class TestDataCache:
def _make_env(self, current_time_ms=1000): def _make_env(self, current_time_ms=1000):
"""Create an env with cache functions and a controllable now-ms.""" """Create an env with cache functions and a controllable now-ms."""
from shared.sx.parser import parse_all as pa from shared.sx.parser import parse_all as pa
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
env = {} env = {}
# Mock now-ms as a callable that returns current_time_ms # Mock now-ms as a callable that returns current_time_ms
@@ -344,7 +344,7 @@ class TestDataCache:
def _eval(self, src, env): def _eval(self, src, env):
from shared.sx.parser import parse_all as pa from shared.sx.parser import parse_all as pa
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
result = None result = None
for expr in pa(src): for expr in pa(src):
result = _trampoline(_eval(expr, env)) result = _trampoline(_eval(expr, env))

View File

@@ -18,7 +18,7 @@ from shared.sx.types import Symbol, Keyword, Lambda, Component, Macro, NIL
def hw_eval(text, env=None): def hw_eval(text, env=None):
"""Evaluate via hand-written evaluator.py.""" """Evaluate via hand-written evaluator.py."""
from shared.sx.evaluator import evaluate as _evaluate, EvalError from shared.sx.ref.sx_ref import evaluate as _evaluate
if env is None: if env is None:
env = {} env = {}
return _evaluate(parse(text), env) return _evaluate(parse(text), env)
@@ -50,7 +50,7 @@ def ref_render(text, env=None):
def hw_eval_multi(text, env=None): def hw_eval_multi(text, env=None):
"""Evaluate multiple expressions (e.g. defines then call).""" """Evaluate multiple expressions (e.g. defines then call)."""
from shared.sx.evaluator import evaluate as _evaluate from shared.sx.ref.sx_ref import evaluate as _evaluate
if env is None: if env is None:
env = {} env = {}
result = None result = None
@@ -736,7 +736,7 @@ class TestParityDeps:
class TestParityErrors: class TestParityErrors:
def test_undefined_symbol(self): def test_undefined_symbol(self):
from shared.sx.evaluator import EvalError as HwError from shared.sx.types import EvalError as HwError
from shared.sx.ref.sx_ref import EvalError as RefError from shared.sx.ref.sx_ref import EvalError as RefError
with pytest.raises(HwError): with pytest.raises(HwError):
hw_eval("undefined_var") hw_eval("undefined_var")

View File

@@ -12,7 +12,7 @@ import pytest
from shared.sx.parser import parse, parse_all from shared.sx.parser import parse, parse_all
from shared.sx.html import render as py_render from shared.sx.html import render as py_render
from shared.sx.evaluator import evaluate from shared.sx.ref.sx_ref import evaluate
SX_JS = Path(__file__).resolve().parents[2] / "static" / "scripts" / "sx.js" SX_JS = Path(__file__).resolve().parents[2] / "static" / "scripts" / "sx.js"
SX_TEST_JS = Path(__file__).resolve().parents[2] / "static" / "scripts" / "sx-test.js" SX_TEST_JS = Path(__file__).resolve().parents[2] / "static" / "scripts" / "sx-test.js"

View File

@@ -7,7 +7,7 @@ from __future__ import annotations
import pytest import pytest
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
_PREAMBLE = '''(define assert-equal (fn (expected actual) (assert (equal? expected actual) (str "Expected " (str expected) " but got " (str actual))))) _PREAMBLE = '''(define assert-equal (fn (expected actual) (assert (equal? expected actual) (str "Expected " (str expected) " but got " (str actual)))))

View File

@@ -375,6 +375,15 @@ class _ShiftSignal(BaseException):
self.env = env self.env = env
# ---------------------------------------------------------------------------
# EvalError
# ---------------------------------------------------------------------------
class EvalError(Exception):
"""Error during expression evaluation."""
pass
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Type alias # Type alias
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

View File

@@ -314,7 +314,7 @@ def _self_hosting_data(ref_dir: str) -> dict:
import os import os
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.types import Symbol from shared.sx.types import Symbol
from shared.sx.evaluator import evaluate, make_env from shared.sx.ref.sx_ref import evaluate, make_env
from shared.sx.ref.bootstrap_py import extract_defines, compile_ref_to_py, PyEmitter from shared.sx.ref.bootstrap_py import extract_defines, compile_ref_to_py, PyEmitter
try: try:
@@ -387,7 +387,7 @@ def _js_self_hosting_data(ref_dir: str) -> dict:
"""Run js.sx live: load into evaluator, translate all spec defines.""" """Run js.sx live: load into evaluator, translate all spec defines."""
import os import os
from shared.sx.types import Symbol from shared.sx.types import Symbol
from shared.sx.evaluator import evaluate from shared.sx.ref.sx_ref import evaluate
from shared.sx.ref.run_js_sx import load_js_sx from shared.sx.ref.run_js_sx import load_js_sx
from shared.sx.ref.platform_js import extract_defines from shared.sx.ref.platform_js import extract_defines
@@ -661,7 +661,7 @@ def _run_spec_tests() -> dict:
import os import os
import time import time
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref") ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref")
if not os.path.isdir(ref_dir): if not os.path.isdir(ref_dir):
@@ -735,7 +735,7 @@ def _run_modular_tests(spec_name: str) -> dict:
import os import os
import time import time
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.evaluator import _eval, _trampoline from shared.sx.ref.sx_ref import eval_expr as _eval, trampoline as _trampoline
from shared.sx.types import Symbol, Keyword, Lambda, NIL from shared.sx.types import Symbol, Keyword, Lambda, NIL
ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref") ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref")
@@ -817,7 +817,7 @@ def _run_modular_tests(spec_name: str) -> dict:
def _call_sx(fn, args, caller_env): def _call_sx(fn, args, caller_env):
if isinstance(fn, Lambda): if isinstance(fn, Lambda):
from shared.sx.evaluator import _call_lambda from shared.sx.ref.sx_ref import call_lambda as _call_lambda
return _trampoline(_call_lambda(fn, list(args), caller_env)) return _trampoline(_call_lambda(fn, list(args), caller_env))
return fn(*args) return fn(*args)
@@ -1165,9 +1165,9 @@ def _prove_data() -> dict:
""" """
import time import time
from shared.sx.parser import parse_all from shared.sx.parser import parse_all
from shared.sx.evaluator import evaluate from shared.sx.ref.sx_ref import evaluate
from shared.sx.primitives import all_primitives from shared.sx.primitives import all_primitives
from shared.sx.evaluator import _trampoline, _call_lambda from shared.sx.ref.sx_ref import trampoline as _trampoline, call_lambda as _call_lambda
env = all_primitives() env = all_primitives()