compile/call/cc

Symbol: compile/call/cc

Syntax: (call/cc FN)

Use-case: Undelimited call-with-current-continuation (Scheme-like). Captures the current continuation at the call site, wraps it in a Continuation object, and immediately calls FN with that continuation as its sole argument. When the continuation is invoked with a value, control returns to the point just after the compile/call/cc form with that value. If FN returns normally without invoking the continuation, the return value of FN becomes the value of the form.

The continuation packs its arguments the way return does: (k) resumes with None, (k v) with v, (k a b) with the tuple (a, b), and a call with keywords, (k a x: 1), with a values instance over all of them.

Behaviour: Emits PUSH_CC (opens a CC block), compiles FN, emits CAPTURE_CC (captures the continuation and pushes it), emits CALL 1 (calls FN with the continuation), then POP_CC (closes the CC block on normal return). The continuation may be invoked from within the same eval context (direct apply) or from Python code in a frame above the owning eval loop (upwards apply via KoskariContinuationApply). Cross-context invocation from a different eval context triggers the segmented-transfer path.

Invoking the continuation leaves every extent between the call site and the capture point: the finally: of a try, the __exit__ of a with and the after thunk of a dyn-wind all run, innermost first, before the continuation’s body resumes.

Errors: A with or dyn-wind inside the captured region is captured with it, and its __exit__ or after thunk runs on transfer as above. A capture taken from inside one of their calls while it runs, the body of __enter__ or __exit__ or a before or after thunk, is refused, as is a capture that would cross a generator: KoskariPromptUnreachable, with the boundary attribute naming what refused (enter, exit, before, after or generator) and operation set to call/cc. The same applies to let/cc and capture/cc. See Error codes.

Examples:

;; Capture and immediately invoke: returns 42
(call/cc
  (lambda [k]
    (k 42)))

;; Escape continuation: short-circuit a computation
(call/cc
  (lambda [escape]
    (begin
      (do-setup)
      (escape "early-exit")
      (do-cleanup))))