All signal operations (computed, effect, batch, etc.) now dispatch function calls through cek-call, which routes SX lambdas via cek-run and native callables via apply. This replaces the invoke shim. Key changes: - cek.sx: add cek-call (defined before reactive-shift-deref), replace invoke in subscriber disposal and ReactiveResetFrame handler - signals.sx: replace all 11 invoke calls with cek-call - js.sx: fix octal escape in js-quote-string (char-from-code 0) - platform_js.py: fix JS append to match Python (list concat semantics), add Continuation type guard in PLATFORM_CEK_JS, add scheduleIdle safety check, module ordering (cek before signals) - platform_py.py: fix ident-char regex (remove [ ] from valid chars), module ordering (cek before signals) - run_js_sx.py: emit PLATFORM_CEK_JS before transpiled spec files - page-functions.sx: add cek and provide page functions for SX URLs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
107 lines
2.9 KiB
Python
107 lines
2.9 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.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)
|