Subordinate module to mirgen. Implements the block and scope management required for translating the AST's high-level control-flow constructs to the MIR's goto-based ones. Injecting mnkDestroy operations is also implemented here, integrated with the scope management.
Types
Block = object id*: Option[LabelId] ## the block's label. Initialized on-demand, meaning that 'none' ## indicates that the block is unused case kind*: BlockKind of bkBlock: label*: PSym ## the symbol of the block's label. nil if it's an internal block of bkScope: numRegistered: int ## number of entities registered for the scope in the to-destroy list of bkTryFinally: selector*: Option[Value] ## the variable to store the destination index in exits*: seq[int] ## a set of all original target block indices of bkFinally: selectorVar*: Value ## the selector storing the dispatcher's target index excState*: int ## the selector value representing the "finally entered via exception" ## state of bkTryExcept, bkExcept: nil
- Information about a block-like structure. This not only includes |NimSkull| blocks, but also try, finally, etc. Source Edit
BlockCtx = object blocks: seq[Block] ## stack of enclosing try, finally, etc. blocks toDestroy: seq[tuple[entity: Value, label: Option[LabelId]]] ## all locals/globals/temporaries that need destruction, together ## with the label of the finally that the destroy operation is part ## of. Only the items where the `label` changes have an initialized ## label currScope: int ## block index of the current scope
- Per-procedure block-related state. Source Edit
Procs
proc blockExit(c; graph: ModuleGraph; env: var MirEnv; bu; targetBlock: int) {. ...raises: [KeyError, Exception], tags: [ReadDirEffect, RootEffect].}
- Emits a goto jumping to the targetBlock, together with the necessary scope and exception cleanup logic. If the jump crosses a try/finally, the finally is jumped to instead. Source Edit
proc closeBlock(c; bu): bool {....raises: [], tags: [].}
- Finishes the current block. If required for the block (because it is a block and broken out of), emits a join and returns true, false otherwise. Source Edit
proc closeScope(c; bu; nextScope: int; hasStructuredExit: bool) {....raises: [], tags: [].}
-
Pops the scope from the stack and emits the scope exit actions. hasStructuredExit tells whether structured control-flow reaches the end of the scope, affecting how the exit looks like.
next is the index of the scope index returns by the previous startScope call.
Source Edit proc closest(c: BlockCtx): int {....raises: [], tags: [].}
- Returns the index of the closest block. Source Edit
proc findBlock(c: BlockCtx; label: PSym): int {....raises: [], tags: [].}
- Returns the index of the block with label label. Source Edit
proc isInFinally(c: BlockCtx): bool {....raises: [], tags: [].}
- Source Edit
proc raiseExit(c; bu) {....raises: [], tags: [].}
- Emits the jump target for a jump to the nearest enclosing exception handler. Source Edit
func register(c; loc: Value) {....raises: [], tags: [].}
- Registers loc for destruction at the end of the current scope. Destruction happens in the reverse order the locations are registered in. Source Edit
proc startScope(c): int {....raises: [], tags: [].}
- Starts a new scope and returns the index of the previous one. Source Edit