#!/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.types import NIL parse_all = mod.sx_parse # Use tree-walk evaluator for interpreting .sx test files. # CEK is now the default, but test runners need tree-walk so that # transpiled HO forms (ho_map, etc.) don't re-enter CEK mid-evaluation. eval_expr = mod._tree_walk_eval_expr trampoline = mod._tree_walk_trampoline mod.eval_expr = eval_expr mod.trampoline = 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)