Implement explicit CEK machine, continuations, effect signatures, fix dynamic-wind and inspect shadowing
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>
This commit is contained in:
@@ -283,6 +283,58 @@ def parse_boundary_sx() -> tuple[frozenset[str], dict[str, frozenset[str]]]:
|
||||
return frozenset(all_io), frozen_helpers
|
||||
|
||||
|
||||
def parse_boundary_effects() -> dict[str, list[str]]:
|
||||
"""Parse boundary.sx and return effect annotations for all declared primitives.
|
||||
|
||||
Returns a dict mapping primitive name to its declared effects list.
|
||||
E.g. {"current-user": ["io"], "reset!": ["mutation"], "signal": []}.
|
||||
|
||||
Only includes primitives that have an explicit :effects declaration.
|
||||
Pure primitives from primitives.sx are not included (they have no effects).
|
||||
"""
|
||||
source = _read_file("boundary.sx")
|
||||
exprs = parse_all(source)
|
||||
result: dict[str, list[str]] = {}
|
||||
|
||||
_DECL_FORMS = {
|
||||
"define-io-primitive", "declare-signal-primitive",
|
||||
"declare-spread-primitive",
|
||||
}
|
||||
|
||||
for expr in exprs:
|
||||
if not isinstance(expr, list) or len(expr) < 2:
|
||||
continue
|
||||
head = expr[0]
|
||||
if not isinstance(head, Symbol) or head.name not in _DECL_FORMS:
|
||||
continue
|
||||
|
||||
name = expr[1]
|
||||
if not isinstance(name, str):
|
||||
continue
|
||||
|
||||
effects_val = _extract_keyword_arg(expr, "effects")
|
||||
if effects_val is None:
|
||||
# IO primitives default to [io] if no explicit :effects
|
||||
if head.name == "define-io-primitive":
|
||||
result[name] = ["io"]
|
||||
continue
|
||||
|
||||
if isinstance(effects_val, list):
|
||||
effect_names = []
|
||||
for item in effects_val:
|
||||
if isinstance(item, Symbol):
|
||||
effect_names.append(item.name)
|
||||
elif isinstance(item, str):
|
||||
effect_names.append(item)
|
||||
result[name] = effect_names
|
||||
else:
|
||||
# Might be a single symbol
|
||||
if isinstance(effects_val, Symbol):
|
||||
result[name] = [effects_val.name]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def parse_boundary_types() -> frozenset[str]:
|
||||
"""Parse boundary.sx and return the declared boundary type names."""
|
||||
source = _read_file("boundary.sx")
|
||||
|
||||
Reference in New Issue
Block a user