compile/shift
Symbol: compile/shift
Syntax: (shift K BODY ...)
Use-case: Capture the current delimited continuation up to the nearest
compile/reset prompt and bind it to K, then run BODY. K is a
DelimitedContinuation that cannot be called from Python (only from within a
Koskari eval loop via INVOKE_K or INVOKE_K_VAR).
Behaviour: Emits PUSH_SHIFT 0, declares K as a local variable, emits
VAR_STORE K (binds the captured delimited continuation), compiles body with
helper_begin, emits POP_SHIFT 0. K is a binding in the enclosing scope,
as a loop variable or a with name is: it stays bound after the form, it
rebinds an existing K, and a later shift in the slice that reuses the
name rebinds it again. A handler that invokes its continuation more than
once therefore takes a name no later shift in the slice uses, since each
shot runs the slice against the same scope. Calling K 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. The resumed slice is the body of K: a return
in it is the value of the (k ...) call, a raise in it propagates from
the (k ...) call site, and a break or continue in it reaches only a
loop opened inside the slice.
Errors: Capture can fail in two structurally different ways, each with its
own exception under the KoskariContinuationError category (see
Error codes):
KoskariPromptNotFound– no matching prompt anywhere on the dynamic chain:shift has no enclosing reset. Establish a delimiter withreset.KoskariPromptUnreachable– a matching prompt exists, but a node between the shift and the prompt denied the capture:shift cannot capture across a generator boundary. Adding aresetwill not help; restructure so the capture does not cross the boundary. The denying boundary is recorded on the exception’sboundaryattribute.
Both carry prompt_id (the delimiter id the capture was seeking) and
operation (the surface construct, shift). A library that establishes its
own delimiter can use prompt_id to recognize failures against it and
translate them into its own vocabulary, as koskari.solve does with
NoActiveSearch.
Examples:
;; Capture k; invoke immediately
(reset
(shift k
(k "value")))
;; Two shifts in one slice, each shot of k reaching j: distinct names,
;; since both bind in the same scope
(reset
(#tuple (shift k (#tuple (k 1) (k 2)))
(shift j (#tuple (j 10) (j 20)))))
;; => (((1, 10), (1, 20)), ((2, 10), (2, 20)))