Three-phase foundations implementation:
Phase A — Activate dormant shift/reset continuations with 24 SX-native tests
covering basic semantics, predicates, stored continuations, nested reset,
scope interaction, and TCO.
Phase B — Bridge compile-time effect system to runtime: boundary_parser extracts
46 effect annotations, platform provides populate_effect_annotations() and
check_component_effects() for static analysis. 6 new type tests.
Phase C — Explicit CEK machine (frames.sx + cek.sx): evaluation state as data
({control, env, kont, phase, value}), 21 frame types, two-phase step function
(step-eval/step-continue), native shift/reset via frame capture. Bootstrapper
integration: --spec-modules cek transpiles to Python with iterative cek_run.
43 interpreted + 49 transpiled tests passing.
Bug fixes:
- inspect() shadowed by `import inspect` in PLATFORM_ASYNC_PY — renamed to
`import inspect as _inspect`
- dynamic-wind missing platform functions (call_thunk, push_wind!, pop_wind!) —
added with try/finally error safety via dynamic_wind_call
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
102 lines
2.7 KiB
Python
102 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Run test-continuations.sx using the bootstrapped evaluator with continuations enabled."""
|
|
from __future__ import annotations
|
|
import os, sys, subprocess, tempfile
|
|
|
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
_PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..", ".."))
|
|
sys.path.insert(0, _PROJECT)
|
|
|
|
# Bootstrap a fresh sx_ref with continuations enabled
|
|
print("Bootstrapping with --extensions continuations ...")
|
|
result = subprocess.run(
|
|
[sys.executable, os.path.join(_HERE, "bootstrap_py.py"),
|
|
"--extensions", "continuations"],
|
|
capture_output=True, text=True, cwd=_PROJECT,
|
|
)
|
|
if result.returncode != 0:
|
|
print("Bootstrap FAILED:")
|
|
print(result.stderr)
|
|
sys.exit(1)
|
|
|
|
# Write to temp file and import
|
|
tmp = tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False, dir=_HERE)
|
|
tmp.write(result.stdout)
|
|
tmp.close()
|
|
|
|
try:
|
|
import importlib.util
|
|
spec = importlib.util.spec_from_file_location("sx_ref_cont", tmp.name)
|
|
mod = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(mod)
|
|
finally:
|
|
os.unlink(tmp.name)
|
|
|
|
from shared.sx.parser import parse_all
|
|
from shared.sx.types import NIL
|
|
|
|
eval_expr = mod.eval_expr
|
|
trampoline = mod.trampoline
|
|
env = mod.make_env()
|
|
|
|
# Platform test functions
|
|
_suite_stack: list[str] = []
|
|
_pass_count = 0
|
|
_fail_count = 0
|
|
|
|
def _try_call(thunk):
|
|
try:
|
|
trampoline(eval_expr([thunk], env))
|
|
return {"ok": True}
|
|
except Exception as e:
|
|
return {"ok": False, "error": str(e)}
|
|
|
|
def _report_pass(name):
|
|
global _pass_count
|
|
_pass_count += 1
|
|
ctx = " > ".join(_suite_stack)
|
|
print(f" PASS: {ctx} > {name}")
|
|
return NIL
|
|
|
|
def _report_fail(name, error):
|
|
global _fail_count
|
|
_fail_count += 1
|
|
ctx = " > ".join(_suite_stack)
|
|
print(f" FAIL: {ctx} > {name}: {error}")
|
|
return NIL
|
|
|
|
def _push_suite(name):
|
|
_suite_stack.append(name)
|
|
print(f"{' ' * (len(_suite_stack)-1)}Suite: {name}")
|
|
return NIL
|
|
|
|
def _pop_suite():
|
|
if _suite_stack:
|
|
_suite_stack.pop()
|
|
return NIL
|
|
|
|
env["try-call"] = _try_call
|
|
env["report-pass"] = _report_pass
|
|
env["report-fail"] = _report_fail
|
|
env["push-suite"] = _push_suite
|
|
env["pop-suite"] = _pop_suite
|
|
|
|
# Load test framework
|
|
with open(os.path.join(_HERE, "test-framework.sx")) as f:
|
|
for expr in parse_all(f.read()):
|
|
trampoline(eval_expr(expr, env))
|
|
|
|
# Run tests
|
|
print("=" * 60)
|
|
print("Running test-continuations.sx")
|
|
print("=" * 60)
|
|
|
|
with open(os.path.join(_HERE, "test-continuations.sx")) as f:
|
|
for expr in parse_all(f.read()):
|
|
trampoline(eval_expr(expr, env))
|
|
|
|
print("=" * 60)
|
|
print(f"Results: {_pass_count} passed, {_fail_count} failed")
|
|
print("=" * 60)
|
|
sys.exit(1 if _fail_count > 0 else 0)
|