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 scopeExits: seq[LabelId] ## unordered set of follow-up targets of bkTryFinally: doesntExit*: bool ## whether structured control-flow doesn't reach the end of the finally errorOnly*: bool ## whether only exceptional control-flow is intercepted exits*: seq[LabelId] ## unordered set of follow-up targets of bkTryExcept, bkFinally, 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; bu; targetBlock: int) {....raises: [], tags: [].}
- Emits the jump target description for a jump to targetBlock. 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 earlyExit(c; bu) {....raises: [], tags: [].}
- Emits the destroy operations for when structured control-flow reaches the current scope's end. All entities for which a destroy operation is emitted are unregistered already. Source Edit
proc findBlock(c: BlockCtx; label: PSym): int {....raises: [], tags: [].}
- Returns the index of the block with label label. Source Edit
proc raiseExit(c; bu) {....raises: [], tags: [].}
- Emits the jump target description 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