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:
@@ -302,9 +302,45 @@ class StyleValue:
|
||||
return self.class_name
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Continuation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class Continuation:
|
||||
"""A captured delimited continuation (shift/reset).
|
||||
|
||||
Callable with one argument — provides the value that the shift
|
||||
expression "returns" within the delimited context.
|
||||
"""
|
||||
__slots__ = ("fn",)
|
||||
|
||||
def __init__(self, fn):
|
||||
self.fn = fn
|
||||
|
||||
def __call__(self, value=NIL):
|
||||
return self.fn(value)
|
||||
|
||||
def __repr__(self):
|
||||
return "<continuation>"
|
||||
|
||||
|
||||
class _ShiftSignal(BaseException):
|
||||
"""Raised by shift to unwind to the nearest reset.
|
||||
|
||||
Inherits from BaseException (not Exception) to avoid being caught
|
||||
by generic except clauses in user code.
|
||||
"""
|
||||
__slots__ = ("k_name", "body", "env")
|
||||
|
||||
def __init__(self, k_name, body, env):
|
||||
self.k_name = k_name
|
||||
self.body = body
|
||||
self.env = env
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Type alias
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# An s-expression value after evaluation
|
||||
SExp = int | float | str | bool | Symbol | Keyword | Lambda | Macro | Component | HandlerDef | RelationDef | PageDef | QueryDef | ActionDef | StyleValue | list | dict | _Nil | None
|
||||
SExp = int | float | str | bool | Symbol | Keyword | Lambda | Macro | Component | Continuation | HandlerDef | RelationDef | PageDef | QueryDef | ActionDef | StyleValue | list | dict | _Nil | None
|
||||
|
||||
Reference in New Issue
Block a user