boring utilities likely useful to multiple pieces of cps machinery
Types
Callback[C; R; P] = object fn*: P ## ## the bootstrap for continuation C rs*: proc (c: var C): R {.nimcall.} ## ## the result fetcher for continuation C
- Source Edit
Continuation = ref object of ContinuationObj
- Source Edit
ContinuationObj = object of RootObj fn*: proc (c: sink Continuation): Continuation {.nimcall.} ## ## The `fn` points to the next continuation leg. mom*: Continuation ## ## If this Continuation was invoked by another Continuation, ## the `mom` will hold that parent Continuation to form a ## linked-list approximating a stack. ex*: ref Exception ## The unhandled exception of the continuation. when cpsTraceDeque: frames*: Deque[TraceFrame] ## Tracing for all prior hooks when cpsStackFrames: stack*: TraceFrame ## Stack-like semantic record
- Source Edit
ContinuationProc[T] = proc (c: sink T): T {.nimcall.}
- Source Edit
Hook = enum Coop = "coop", ## returns control to the dispatcher Trace = "trace", ## executed at entry to each continuation leg Alloc = "alloc", ## performs allocation of a new continuation Dealloc = "dealloc", ## performs deallocation of a continuation Pass = "pass", ## transfers control-flow between continuations Boot = "boot", ## prepares a continuation for initial use Unwind = "unwind", ## controlled "bubble-up" for exception handling Head = "head", ## invoked when a new continuation has no parent Tail = "tail", ## invoked when a new continuation has a parent Stack = "stack" ## invoked to annotate stack semantics
- these are hook procedure names; the string value matches the name of the symbol we'll call to perform the hook. Source Edit
State {.pure.} = enum Running, ## The continuation is active and running and can be resumed Dismissed, ## The continuation is currently somewhere else Finished ## The continuation is finished and can no longer be resumed
- Representation of the state of a continuation. Source Edit
TraceFrame = object hook*: Hook ## the hook that provoked the trace entry fun*: string ## a short label for the notable symbol info*: LineInfo ## the source of the notable symbol
- a record of where the continuation has been Source Edit
Consts
cpsCallOperatorSupported = true
- Source Edit
cpsStackFrames {.booldefine, used.} = true
- Source Edit
cpsTraceDeque {.booldefine, used.} = true
- Source Edit
traceDequeSize {.intdefine, used.} = 4096
- Source Edit
Procs
proc bootstrapSymbol(n: NimNode): NormNode {....raises: [], tags: [], forbids: [].}
- find the return type of the bootstrap Source Edit
proc breakLabel(n: NormNode): NormNode {....raises: [], tags: [], forbids: [].}
- Return the break label of a break statement or a cpsBreak annotation Source Edit
proc copyOrVoid(n: NimNode): NimNode {....raises: [], tags: [], forbids: [].}
- if the node is empty, ident"void"; else, a copy of the node Source Edit
proc cpsCallbackTypeDef(tipe: NimNode; n: NimNode): NimNode {. ...raises: [Exception], tags: [RootEffect], forbids: [].}
- looks like cpsTransformProc but applies to proc typedefs; this is where we create our calling convention concept Source Edit
proc createCallback(sym: NimNode): NimNode {....raises: [Exception], tags: [RootEffect], forbids: [].}
- create a new Callback object construction Source Edit
proc emptyAsNil(n: NimNode): NimNode {....raises: [], tags: [], forbids: [].}
- normalize nil, nnkEmpty to nnkNilLit Source Edit
proc ensimilate(source, destination: NormNode): Call {....raises: [], tags: [], forbids: [].}
- perform a call to convert the destination to the source's type; the source can be any of a few usual suspects... Source Edit
proc filterPragma(ns: seq[PragmaAtom]; liftee: Name): NormNode {....raises: [], tags: [], forbids: [].}
- Source Edit
proc getContSym(n: NormNode): Name {....raises: [], tags: [], forbids: [].}
- Retrieve the continuation symbol from n, provided that n is a cpsCont. Source Edit
proc isCpsBlock(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- true if the block n contains a cps call anywhere at all; this is used to figure out if a block needs tailcall handling... Source Edit
proc isCpsBreak(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- Return whether a node is a {.cpsBreak.} annotation Source Edit
func isCpsContinue(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- Return whether a node is a {.cpsContinue.} annotation Source Edit
proc isCpsConvCall(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- true if this node holds a cps call that might be nested within one or more conversions. Source Edit
func isCpsPending(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- Return whether a node is a {.cpsPending.} annotation Source Edit
proc isCpsTerminate(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- Return whether n is a cpsTerminate annotation Source Edit
proc isScopeExit(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- Return whether the given node signify a CPS scope exit Source Edit
proc isVoodooCall(n: NormNode): bool {....raises: [], tags: [], forbids: [].}
- true if this is a call to a voodoo procedure Source Edit
proc makeErrorShim(n: NimNode): NimNode {....raises: [], tags: [], forbids: [].}
- Upgrades a procedure to serve as a CPS primitive, generating errors out of .cps. context and taking continuations as input. Source Edit
func matchCpsBreak(): NormMatcher {....raises: [], tags: [], forbids: [].}
- create a matcher matching cpsBreak with an empty label Source Edit
func matchCpsBreak(label: NormNode): NormMatcher {....raises: [], tags: [], forbids: [].}
- create a matcher matching cpsBreak with the given label and cpsBreak without any label Source Edit
func newCpsBreak(n: NormNode; label = newNilLit().NormNode): NormNode {. ...raises: [], tags: [], forbids: [].}
- Source Edit
func newCpsContinue(n: NormNode): NormNode {....raises: [], tags: [], forbids: [].}
- Source Edit
func newCpsPending(): PragmaStmt {....raises: [], tags: [], forbids: [].}
- Produce a {.cpsPending.} annotation Source Edit
proc newCpsTerminate(): NormNode {....raises: [], tags: [], forbids: [].}
- Source Edit
proc nilAsEmpty(n: NimNode): NimNode {....raises: [], tags: [], forbids: [].}
- normalize nil, nnkNilLit to nnkEmpty Source Edit
proc pragmaArgument(n: NormNode; s: string): NormNode {....raises: [], tags: [], forbids: [].}
- from foo() or proc foo() {.some: Pragma.}, retrieve Pragma Source Edit
proc recover[C, R, P](callback: Callback[C, R, P]; continuation: var C): R
-
Using a callback, recover the result of the given continuation. This is equivalent to running () on a continuation which was created with whelp against a procedure call.
If the continuation is in the running State, this operation will trampoline the continuation until it is finished. The result will then be recovered from the continuation environment.
It is a Defect to attempt to recover the result of a dismissed continuation.
Source Edit proc renderStackFrames(): seq[string] {.cpsVoodooCall, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc renderStackFrames(c: Continuation): seq[string] {....raises: [ValueError], tags: [], forbids: [].}
- Render a "stack" trace for the continuation as a sequence of lines. Source Edit
proc renderTraceDeque(): seq[string] {.cpsVoodooCall, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc renderTraceDeque(c: Continuation): seq[string] {....raises: [ValueError], tags: [], forbids: [].}
- Render a traceback for the continuation as a sequence of lines. Source Edit
proc stripPragma(n: NormNode; s: static[string]): NormNode
- filter a pragma with the matching name from various nodes Source Edit
proc stripPragma(n: PragmaStmt; s: static[string]): PragmaStmt
- filter a pragma with the matching name Source Edit
proc trampoline[T: Continuation](c: sink T): T
- This is the basic trampoline: it will run the continuation until the continuation is no longer in the Running state. Source Edit
func wrappedFinally(n, final: NormNode): NormNode {....raises: [], tags: [], forbids: [].}
- rewrite a try/except/finally into try/try-except/finally Source Edit
proc writeStackFrames() {.cpsVoodooCall, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc writeStackFrames(c: Continuation) {....raises: [ValueError, IOError], tags: [WriteIOEffect], forbids: [].}
- Write a "stack" trace for the continuation. Source Edit
proc writeTraceDeque() {.cpsVoodooCall, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc writeTraceDeque(c: Continuation) {....raises: [ValueError, IOError], tags: [WriteIOEffect], forbids: [].}
- Write a traceback for the continuation. Source Edit
Macros
macro cpsMagic(n: untyped): untyped
-
Applied to a procedure to generate a version which lacks the first argument and return value, which are those of a Continuation.
This new magical will compile correctly inside CPS procedures though it never takes a Continuation argument and produces no return value.
The target procedure of a cpsMagic pragma returns the Continuation to which control-flow should return; this is usually the same value passed into the procedure, but this is not required nor is it checked!
Source Edit macro trampolineIt[T: Continuation](supplied: T; body: untyped)
- This trampoline allows the user to interact with the continuation prior to each leg of its execution. The continuation will be exposed by a variable named it inside the body. Source Edit
Templates
template cpsBootstrap(whelp: typed) {.pragma.}
- the symbol for creating a continuation -- technically, a whelp() Source Edit
template cpsCallback() {.pragma.}
- this is a callback typedef Source Edit
template cpsCallbackShim(whelp: typed) {.pragma.}
- the symbol for creating a continuation which returns a continuation base Source Edit
template cpsContinue() {.pragma.}
- this is a continue statement in a cps block Source Edit
template cpsEnvironment(tipe: typed) {.pragma.}
- the environment type that composed the target Source Edit
template cpsHasException(cont, ex: typed) {.pragma.}
- the continuation has an exception stored in ex, with cont being the continuation symbol used. Source Edit
template cpsMagicCall() {.pragma.}
- a magic call Source Edit
template cpsMustJump() {.pragma.}
- cps calls and magic calls jump Source Edit
template cpsPending() {.pragma.}
- this is the last continuation Source Edit
template cpsReturnType(tipe: typed) {.pragma.}
- the return type of the continuation Source Edit
template cpsTerminate() {.pragma.}
- this is the end of this procedure Source Edit
template cpsVoodooCall() {.pragma.}
- a voodoo call Source Edit
template debugAnnotation(s: typed; n: NimNode; body: untyped) {.dirty.}
- Source Edit