Implements the translation from AST to the MIR. The input AST is expected to have already been transformed by transf.
How It Works
In terms of operation, the input AST is traversed via recursion, with declarative constructs not relevant to the MIR being ignored.
None of the MIR operations that imply structured control-flow produce a value, so the input expression that do (if, case, block, and try) are translated into statements where the last expression in each clause is turned into an assignment to, depending on the context where they're used, either a temporary or existing lvalue expression. The latter are forwarded to the generation procedures via Destination.
For efficiency, MirBuilder's double-buffering functionality is used for emitting the trees. Statements are directly emitted into the final buffer (after all their operands were emitted), while expressions are first emitted into the staging buffer, with the callsite then deciding what to do with them.
When translating expressions, they're first translated to the proto-MIR, and then the proto-MIR expression is translated to the MIR. This allows the translation of expressions (besides calls) to focus only on syntax, leaving the semantics-related decision-making to the proto-MIR construction.
For arguments, the translation uses temporaries (both owning and non-owning) to make sure that the following invariants are true:
- normal argument expressions are pure (the expression always evaluates to the same value)
- lvalue argument expressions are stable (the expression always has the same address)
- sink arguments are always moveable
- index and dereference targets are always pure
These guarantees make the following analysis and transformation a lot easier.
Origin information
Each produced MirNode is associated with the PNode it originated from (referred to as "source information"). The PNode is registered in the SourceMap, with the resulting SourceId then assigned to the nodes associated with the AST.
In order to reduce the amount manual bookkeeping and to improve the ergonomics of producing MIR node sequences, assigning the SourceId is decoupled from the initial production. SourceProvider keeps track of the currently processed AST node and manages setting the info field on nodes.
Changing the active AST node is done via calling the useSource routine, which will apply the previous AST node as the origin to all MIR nodes added to a MirBuffer since the last call to useSource. When the scope useSource is called in is exited, the previous AST node is restored as the active origin, allowing for arbitrary nesting.
Imports
-
../ast/ast, ../ast/astalgo, ../ast/astmsgs, ../ast/trees, ../ast/types, ../ast/wordrecg, datatables, mirbodies, mirconstr, mirenv, mirgen_blocks, mirtrees, mirtypes, proto_mir, sourcemaps, ../modules/magicsys, ../modules/modulegraphs, ../front/options, ../sem/ast_analysis, ../utils/containers, ../utils/idioms, ../front/msgs
Types
GenOption = enum goIsNimvm, ## choose the ``nimvm`` branch for ``when nimvm`` statements goGenTypeExpr, ## don't omit type expressions goIsCompileTime ## whether the code is meant to be run at compile-time. ## Affects handling of ``.compileTime`` globals
- Source Edit
TranslationConfig = object options*: set[GenOption] magicsToKeep*: set[TMagic] ## magic procedures that need to be referenced via their symbols, either ## because they're not really magic or because the symbol has ## additional information
- Extra configuration for the AST -> MIR translation. Source Edit
Procs
proc constDataToMir(env: var MirEnv; n: PNode): MirTree {. ...raises: [Exception, ERecoverableError, KeyError], tags: [RootEffect, ReadDirEffect].}
- Translates the construction expression AST n representing some constant data to its corresponding MIR representation. Source Edit
proc exprToMir(graph: ModuleGraph; env: var MirEnv; config: TranslationConfig; e: PNode): MirBody {....raises: [Exception, ERecoverableError, KeyError], tags: [RootEffect, ReadDirEffect].}
- Only meant to be used by vmjit. Produces a MIR body for a standalone expression. The result of the expression is assigned to the special local with ID 0. Source Edit
proc generateAssignment(graph: ModuleGraph; env: var MirEnv; config: TranslationConfig; n: PNode; builder: var MirBuilder; source: var SourceMap) {. ...raises: [Exception, ERecoverableError, KeyError], tags: [RootEffect, ReadDirEffect].}
- Translates an nkIdentDefs AST into MIR and emits the result into builder's currently selected buffer. Source Edit
proc generateCode(graph: ModuleGraph; env: var MirEnv; owner: PSym; config: TranslationConfig; body: PNode): MirBody {. ...raises: [Exception, ERecoverableError, KeyError, ValueError], tags: [RootEffect, ReadDirEffect].}
-
Generates the full MIR body for the given AST body.
owner it the symbol of the entity (module or procedure) that body belongs to. If the owner is a procedure, body is expected to be the full body of the procedure.
config provides additional configuration options that alter how some AST is translated.
Source Edit