Implement delimited continuations (shift/reset) across all evaluators
Bootstrap shift/reset to both Python and JS targets. The implementation uses exception-based capture with re-evaluation: reset wraps in try/catch for ShiftSignal, shift raises to the nearest reset, and continuation invocation pushes a resume value and re-evaluates the body. - Add Continuation type and _ShiftSignal to shared/sx/types.py - Add sf_reset/sf_shift to hand-written evaluator.py - Add async versions to async_eval.py - Add shift/reset dispatch to eval.sx spec - Bootstrap to Python: FIXUPS_PY with sf_reset/sf_shift, regenerate sx_ref.py - Bootstrap to JS: Continuation/ShiftSignal types, sfReset/sfShift in fixups - Add continuation? primitive to both bootstrappers and primitives.sx - Allow callables (including Continuation) in hand-written HO map - 44 unit tests (22 per evaluator) covering: passthrough, abort, invoke, double invoke, predicate, stored continuation, nested reset, practical patterns - Update continuations essay to reflect implemented status with examples Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -484,6 +484,48 @@ _ASYNC_SPECIAL_FORMS: dict[str, Any] = {
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Async delimited continuations — shift / reset
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_ASYNC_RESET_RESUME: list = []
|
||||
|
||||
|
||||
async def _asf_reset(expr, env, ctx):
|
||||
"""(reset body) — async version."""
|
||||
from .types import Continuation, _ShiftSignal
|
||||
body = expr[1]
|
||||
try:
|
||||
return await async_eval(body, env, ctx)
|
||||
except _ShiftSignal as sig:
|
||||
def cont_fn(value=None):
|
||||
from .types import NIL
|
||||
_ASYNC_RESET_RESUME.append(value if value is not None else NIL)
|
||||
try:
|
||||
# Sync re-evaluation; the async caller will trampoline
|
||||
from .evaluator import _eval as sync_eval, _trampoline
|
||||
return _trampoline(sync_eval(body, env))
|
||||
finally:
|
||||
_ASYNC_RESET_RESUME.pop()
|
||||
k = Continuation(cont_fn)
|
||||
sig_env = dict(sig.env)
|
||||
sig_env[sig.k_name] = k
|
||||
return await async_eval(sig.body, sig_env, ctx)
|
||||
|
||||
|
||||
async def _asf_shift(expr, env, ctx):
|
||||
"""(shift k body) — async version."""
|
||||
from .types import _ShiftSignal
|
||||
if _ASYNC_RESET_RESUME:
|
||||
return _ASYNC_RESET_RESUME[-1]
|
||||
k_name = expr[1].name
|
||||
body = expr[2]
|
||||
raise _ShiftSignal(k_name, body, env)
|
||||
|
||||
_ASYNC_SPECIAL_FORMS["reset"] = _asf_reset
|
||||
_ASYNC_SPECIAL_FORMS["shift"] = _asf_shift
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Async higher-order forms
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user