compiler/utils/astrepr

    Dark Mode
Search:
  Source   Edit

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

func `+`(conf: TReprConf; flag: TReprFlag | set[TReprFlag]): TReprConf
  Source   Edit
func `-`(conf: TReprConf; flag: TReprFlag | set[TReprFlag]): TReprConf
  Source   Edit
proc debugAst(it: PNode) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!",
                           noSideEffect,
                           ...raises: [KeyError, ValueError, Exception],
                           tags: [RootEffect, ReadDirEffect].}
Deprecated: DEBUG proc, should not be used in the final build!
Print out tree representation of the AST node.
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
proc debugParsedAst(it: ParsedNode) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!",
                                      noSideEffect,
                                      ...raises: [KeyError, ValueError], tags: [].}
Deprecated: DEBUG proc, should not be used in the final build!
Print out tree representation of the parsed AST node   Source   Edit
proc debugSym(it: PSym) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!",
                          noSideEffect,
                          ...raises: [Exception, ValueError, KeyError],
                          tags: [RootEffect, ReadDirEffect].}
Deprecated: DEBUG proc, should not be used in the final build!
Print out tree represntation of the symbol. Can also be used in gdb debugging session due to .exportc. annotation   Source   Edit
proc debugType(it: PType) {.exportc, ...deprecated: "DEBUG proc, should not be used in the final build!",
                            noSideEffect,
                            ...raises: [ValueError, Exception, KeyError],
                            tags: [RootEffect, ReadDirEffect].}
Deprecated: DEBUG proc, should not be used in the final build!
Print out tree represntation of the type. Can also be used in gdb debugging session due to .exportc. annotation   Source   Edit
func excl(conf: var TReprConf; flag: TReprFlag | set[TReprFlag])
  Source   Edit
func incl(conf: var TReprConf; flag: TReprFlag | set[TReprFlag])
  Source   Edit
func inDebug(): bool {....raises: [], tags: [].}
Check whether current implicit compiler configuration is in the 'debug' range.
Warning: Requires implicit debug configuration to be set
  Source   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.}
Deprecated: DEBUG proc, should not be used in the final build!
Check if file name of the 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
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.}
Deprecated: DEBUG proc, should not be used in the final build!

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 set
Note: 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: [].}
Deprecated: DEBUG proc, should not be used in the final build!
  Source   Edit
proc setImplicitDebugConfRef(conf: ConfigRef) {.
    ...deprecated: "DEBUG proc, should not be used in the final build!",
    noSideEffect, ...raises: [], tags: [].}
Deprecated: DEBUG proc, should not be used in the final build!
Set implicit debug config reference.   Source   Edit
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
proc treeRepr(conf: ConfigRef; sym: PSym; rconf: TReprConf = implicitTReprConf;
              indent: int = 0): ColText {.
    ...raises: [Exception, ValueError, KeyError], tags: [RootEffect, ReadDirEffect].}
  Source   Edit
proc treeRepr(conf: ConfigRef; typ: PType; rconf: TReprConf = implicitTReprConf;
              indent: int = 0): ColText {.
    ...raises: [ValueError, Exception, KeyError], tags: [RootEffect, ReadDirEffect].}
  Source   Edit

Templates

template debug(conf: ConfigRef; it: Debugable)
Print tree representation of the AST   Source   Edit
template debug(conf: ConfigRef; it: Debugable; tconf: TReprConf)
Print tree representation of the AST using provided configuration.   Source   Edit
template debug(it: Debugable; tconf: TReprConf)
Convenience overload of debugAst   Source   Edit
template debug(it: ParsedNode)
Print tree representation of a ParsedNode for compiler debugging   Source   Edit
template debug(it: PIdent)
Print tree representation of a PIdent for compiler debugging   Source   Edit
template debug(it: PNode)
Print tree representation of a PNode for compiler debugging   Source   Edit
template debug(it: PSym)
Print tree representation of a PSym for compiler debugging   Source   Edit
template debug(it: PType)
Print tree representation of a PType for compiler debugging   Source   Edit