treeRepr() implementation for the PNode tree structures. This module provides helper procedures that can be used for debugging purposes - dumping compiler IR in the textual form.
For each IR type (PType, PSym, PNode) there are several procs defined:
- treeRepr - main implementation to generate the ColText chunk for the object.
- debug - convenience overloads that print generated text immediately. There are two version of the debug - one that accept ConfigRef object, and one that can work without it. Both call treeRepr internally, but with ConfigRef present more information can be printed.
- debugAst, debugSym, debugType - procs added for use in gdb debugging. They have {.exportc.} annotations, so can be used directly by name there
treeRepr and all other procedures in the module accept TReprConf object (default value is provided via implicitTReprConf global, for gdb procs it is used implicitly) that controls which fields specifically will be printed.
Configuration object also includes callbacks that would allow you to provide additional information for the printed targets. For example, you want to perform some analysis, and don't have ConfigRef object passed around (because your code only collects some data from the nodes). But then you need to figure out the actual location of where node comes from. In that case you simply assign to implicitTReprConf.extraNodeInfo, and next debug you call will provide needed information.
implicitTReprConf.extraNodeInfo = proc(node: PNode): ColText = result.add "node location " & (config $ node.info)
You can change implicit trepr configuration in the necessary modules or in compiler/nim.nim, right after creation of the config reference.
If you need to figure out what specific flag controls which field (without going into the source code) add trfDescFlag to the configuration.
Types
TReprConf = object flags*: set[TReprFlag] ## Set of the formatting options for the ## procedure. Several built-in constants are defined in this module ## that might be suitable for different debugging or AST exploration ## tasks. maxDepth*: int ## Ignore all nodes that are placed deeper than that. ## Useful to see a high-level overview for large nodes, such as full ## proc bodies maxLen*: int ## on each level, print upto that number of subnodes. ## Useful to cut out parts on large `case` trees, toplevel nodes for ## modules, statement lists and such. maxPath*: int ## maximum path length for subnodes extraNodeInfo*: proc (node: PNode): ColText ## Additional information ## for node, symbol or type printing. By default these procs are not ## implemented and ignored. If the procedure is not nil it is called at ## the start of each entry (before mandatory fields and nested ## elements) and results are indented to match the surroundings. extraSymInfo*: proc (sym: PSym): ColText ## Extra info for symbol extraTypInfo*: proc (typ: PType): ColText ## Extra info for type
- Main debug configuration object Source Edit
TReprFlag = enum trfReportInfo, ## Show information about embedded errors trfPackedFields, ## Put fields horizontally instead of arranging them ## out veritcally. Should be used only when a small ## number of total fields is enabled, otherwise output ## will be unreadable. trfSkipAuxError, ## Skip 'data store' fields of the `nkError` node - ## elements `[1..2]` are used to store additional metadata and are ## rarely needed for printing. trfIndexVisisted, ## Enumerate each visited node when printing the ## `PNode` tree trfShowKindTypes, ## Show `T:`, `S:`, `N:` prefixes for the enum kinds ## when printed in the tree. This is useful to distinguish between ## various structure types when printing node that contains symbols ## which also have types. trfShowDefaultedFields, ## Show fields with defaulted values trfShowNilFields, ## Show fields with `nil` values trfShowDebugLocation, ## Show location of the `debug` calls in the ## source code - useful if you have multiple debugging places and need ## to diferentiate between them. trfShowFullSymTypes, ## Full render of the symbol type on one level. ## Multiple levels are not printed trfShowSymFlags, ## Show symbol `.flags` field trfShowSymLineInfo, ## Line information trfShowSymName, trfShowSymTypes, ## Flat render of the symbol type trfShowSymMagic, ## used symbol magic trfShowSymKind, ## `.kind` trfShowSymOwner, ## Full chain of the symbol owners trfShowSymOptions, ## `.options` trfShowSymPosition, ## `.position` trfShowSymOffset, ## `.offset` trfShowSymBitsize, ## `.bitsize` trfShowSymAlignment, ## `.alignment` trfShowFullSymChoice, ## Show all alternative symbols for the ## `nkOpenSymChoice` and `nkClosedSymChoice` node kinds trfShowSymAst, ## `.ast` from the symbol trfShowSymId, ## `module` and `item` from `itemId` field trfShowTypeCallConv, ## Calling convention trfShowTypeFlags, ## `.flags` trfShowTypeSym, ## `.sym` trfShowTypeAst, ## `.n` of the `PType` object trfShowTypeAlloc, ## `.align` and `.size` fields. They represent a ## single logical chunk of information, and pinter together trfShowTypeOwner, ## Full chain of the type owner trfShowTypeId, ## `module` and `item` from `itemId` field trfShowNodeLineInfo, ## Node location information trfShowNodeFlags, ## `.flags` trfShowNodeIds, ## `.id` field trfShowNodeComments, ## `.comment` field trfShowNodeErrors, ## Embedded `nkError` reports trfShowNodeTypes, trfDescFlag ## For each formatted field, show name of the flag that ## controls it
- Configuration options for treeRepr debugging Source Edit
Vars
implicitCompilerTraceReprConf: TReprConf = block: ## default tree repr config for compiler tracing, meant to be compact as ## there is a lot of tracing spam. var base = defaultTReprConf base.maxDepth = 4 base.maxLen = 5 base.flags = {trfPackedFields, trfSkipAuxError, trfShowKindTypes, trfShowSymId, trfShowSymName, trfShowSymTypes, trfShowSymKind, trfShowNodeErrors, trfShowNodeIds, trfShowNodeLineInfo} base
- default tree repr config for compiler tracing, meant to be compact as there is a lot of tracing spam. Source Edit
implicitTReprConf: TReprConf = defaultTReprConf
- global configuration object that is implicitly used by debugAst and debugType. Can be used in order to configure behaviour of the debugging functions that could later be called from gdb environment (debugAst, debugType, debugSym), or sem execution tracer Source Edit
Lets
compactTReprConf = defaultTReprConf + trfPackedFields
- Compacted tree repr configuration Source Edit
defaultTReprConf = TReprConf(maxDepth: 120, maxLen: 30, maxPath: 1, flags: { trfReportInfo, trfShowKindTypes, trfShowSymName, trfShowSymMagic..trfShowSymKind, trfShowSymOffset..trfShowSymAlignment, trfShowTypeCallConv..trfShowTypeFlags, trfShowNodeFlags..trfShowNodeTypes})
- Default based configuration for the tree repr printing functions Source Edit
onlyStructureTReprConf = block: var base = defaultTReprConf base.flags = {trfShowNodeComments} base.maxPath = 0 base
- Source Edit
verboseTReprConf = block: ## Show absolutely everything var base = defaultTReprConf + {trfReportInfo..trfDescFlag} - {trfPackedFields, trfDescFlag} base.maxPath = 40 base
- Show absolutely everything Source Edit
Consts
treeReprAllFields = {trfShowSymFlags..trfShowNodeTypes}
- Set of flags to print all fields in all tree reprs Source Edit
Procs
proc debugAst(it: PNode) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect, ...raises: [KeyError, ValueError, Exception], tags: [RootEffect, ReadDirEffect].}
-
Note: there is no ConfigRef argument, and because of that some information cannot be fully retrieved from the AST (such as full paths of the FileIndex entries).Tip: This proc is annotated with {.exportc.} which means it's mangled name exactly the same - debugAst and you can call it from the gdb debugging session.Source Edit
Print out tree representation of the AST node.
proc debugParsedAst(it: ParsedNode) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect, ...raises: [KeyError, ValueError], tags: [].}
- Source Edit Print out tree representation of the parsed AST node
proc debugSym(it: PSym) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect, ...raises: [Exception, ValueError, KeyError], tags: [RootEffect, ReadDirEffect].}
- .exportc. annotation Source Edit Print out tree represntation of the symbol. Can also be used in gdb debugging session due to
proc debugType(it: PType) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect, ...raises: [ValueError, Exception, KeyError], tags: [RootEffect, ReadDirEffect].}
- .exportc. annotation Source Edit Print out tree represntation of the type. Can also be used in gdb debugging session due to
func inDebug(): bool {....raises: [], tags: [].}
-
Check whether current implicit compiler configuration is in the 'debug' range.Warning: Requires implicit debug configuration to be setSource Edit
proc inFile(conf: ConfigRef; node: PNode | PSym; file: string; lrange: Slice[int] = low(int) .. high(int)): bool {. ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect.}
- info has filename in it, and that node is located in the specified line range. For debugging purposes as it is pretty slow. Source Edit Check if file name of the
proc inFile(node: PNode | PSym; file: string; lrange: Slice[int] = low(int) .. high(int)): bool {. ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect.}
-
Check if file name of the info has filename in it. For debugging purposes as it is pretty slow. Should be used like this:
..code-block::nim
- if inFile(conf, node.info, "filename"):
- debug node # For example
This proc requries implicit debug config to be set, since information about nodde file names is not available otherwise.
Warning: Requires implicit debug configuration to be setNote: It checks whether file is a substring of the full path, so you can only write the a part of the name, like "osproc" or "strutils"Source Edit proc inLines(node: PNode; lrange: Slice[int]): bool {. ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect, ...raises: [], tags: [].}
- Source Edit
proc setImplicitDebugConfRef(conf: ConfigRef) {. ...deprecated: "DEBUG proc, should not be used in the final build!", noSideEffect, ...raises: [], tags: [].}
- Source Edit Set implicit debug config reference.
proc treeRepr(conf: ConfigRef; id: PIdent; rconf: TReprConf = implicitTReprConf; indent: int = 0): ColText {....raises: [ValueError], tags: [].}
- Source Edit
proc treeRepr(conf: ConfigRef; pnode: ParsedNode; rconf: TReprConf = implicitTReprConf; indent: int = 0): ColText {. ...raises: [KeyError, ValueError], tags: [].}
- Source Edit
proc treeRepr(conf: ConfigRef; pnode: PNode; rconf: TReprConf = implicitTReprConf; indent: int = 0): ColText {. ...raises: [KeyError, ValueError, Exception], tags: [RootEffect, ReadDirEffect].}
-
Generate tree representation from PNode.
Procedure arguments:
- conf: used to get some configuration options, such as --filenames:canonical, but it is mostly used to get full paths from file ids
- pnode: node to print - can be nil, recursive, nkError or any other kind form or shape.
- rconf: print configuration - all nested calls to treeRepr also used it (for PType and PSym)
- indentIncreas: start tree indentation from certain formatting
Generated output packs in a lot of information - here is a short list of features, those will be elaborated on
- subnode index in relation to the parent node, optionally extended index (like[0][0])
- symbol kind, flags, other relevant elements
- type, if exists
- comment message (optionally)
- all node flags
- all IDs when applicable
- maximum target node depth and maximum node length (to avoid drowning in dumps when printing large entries)
- pack things as close as possible horizontally, or make them more spaced out vertically
- node declaration information
- any associated structured reports (IDs, kinds, generation location)
- symbol definition location if any
- type symbols definition location if any
Note: Output examples in the documentation might be slightly different from the actual output due to changes in the default formatting options, or layout changes.Call 0 Sym vmTarget (file.vmTarget) sk: Proc flags:{Used, Global} typ: Proc (arg): 1 ObjConstr nflags:{Sem} typ: Object sk:Type 1.0 Sym Obj (file.Obj) sk: Type flags:{Used, Global} typ: Object sk:Type
This is a tree representation listing from the end of the semexprs.semExpr for this piece of code:
vmTarget(Obj())
.0, .1 and .1.0 show subnode positions of the analyzed input. This is very useful when you need to index into input tree - you can immediately see necessary positions.
TODO: Allow printing out special defines, like ast.pragmasPos instead of the hardcoded indices
- After node position comes the node symbol - Call, Sym, ObjConstr and so on - they correspond to the value of the .kind field of the node.
- If node in question is some form of token (identifier, symbol, text or numeric literal) it is printed after node kind - Sym vmTarget means that it is a symbol that mvTarget has resolved into, in your code.
- If symbol node has an .owner set, it is printed adjacent to the name - file.vmTarget means that input node symbol had owner and it's name was file
- In addition to short summary of the node kind and it's 'value' information is printed in the fields down below. Most fields are optional, and displayed only if target value is non-nil or not empty (for sets)
- sk stands for 'symbol kind' and shows which specific kind of the symbol - skProc, skLet etc.
- flags - set of the TNodeFlag enums
- typ - type of the node
- err - optional field, shown only for nkError nodes. Contains type of the error report. Corresponds to the rsem* report kinds in the reports.ReportKind
- errid - shown after error report kind and corresponds to the ID of the stored error report. Note that only reports that are processed via nkError are enumerated, so errid:1 does not mean it is the first report ever created, it means it it the first report that got into AST. Warnings, hints and other internal messages are processed in different channel.
The treeRepr is also useful for printing out AST with nkError nodes. This piece of code will fail to compile because there is no + overload that can accept Obj() and 12
vmTarget(Obj() + 2)
Error err: CallTypeMismatch errid:2 typ: Proxy 0 Call 0.0 Ident vmTarget 0.1 Error err: CallTypeMismatch errid:1 nflags:{Sem} typ: Proxy 0.1.0 Infix 1.0.0 Ident + 1.0.1 ObjConstr nflags:{Sem} typ: Object sk:Type 0.1.0 Sym Obj (file.Obj) sk: Type flags:{Used, Global} typ: Object sk:Type 1.0.2 IntLit 2 nflags:{Sem}
Note the Error node at 0.1 in the ast. In addition to the regular fields it shows error type (CallTypeMismatch and error report id). Note that due to nkError propagation AST contains multiple error nodes. Innermost was caused by missing + overload, and then vmTarget also failed to resolve, due to malformed arguments.
Source Edit