compiler/ast/ast_query

    Dark Mode
Search:
  Source   Edit

abstract syntax tree + symbol table querying operations

A companion module to ast_types containing things related to querying the AST and Symbol Table. Not all reads are here as some base level reading is required for manipulation, which are contained in ast itself.

Types

NodePosName = enum
  PosLastIdent,             ## Last item in the identifier
  PosType, ## Type position for variable declaration or a procedure. For
            ## procedure returns it's formal parameters (signature)
  PosInit,                  ## Initialization expression
  PosProcBody,              ## Procedure body
  PosProcReturn,            ## Return value of the procedure in formal parameters
  PosProcArgs,              ## Formal parmeters in the procedure
  PosTypeBody,              ## Type definition body
  PosName,                  ## Procedure name
  PosBody,                  ## Generic statement body
  PosPragma                  ## Pragma position in the node body
Named node position accessor   Source   Edit
NodeSliceName = enum
  SliceAllIdents,           ## All identifiers in the ident defs
  SliceAllArguments,        ## All arguments in the formal parammeters
  SliceAllBranches,         ## All case statement branches
  SliceBranchExpressions     ## All expressions in the `of` branch
Named node slice accessor   Source   Edit

Consts

AttachedOpToMagic: array[TTypeAttachedOp, TMagic] = [mDestroy, mAsgn, mAsgn,
    mTrace, mDeepCopy]
  Source   Edit
AttachedOpToStr: array[TTypeAttachedOp, string] = ["=destroy", "=copy", "=sink",
    "=trace", "=deepcopy"]
  Source   Edit
bodyPos = 6
position of body; use rodread.getBody() instead!   Source   Edit
callableDefs = {nkLambda..nkDo, nkProcDef..nkIteratorDef, nkFuncDef}
  Source   Edit
compilerInfoPos = 2
Error compiler source file as strlit, line & col on info   Source   Edit
ConcreteTypes: TTypeKinds = {tyBool, tyChar, tyEnum, tyArray, tyObject, tySet,
                             tyTuple, tyRange, tyPtr, tyRef, tyVar, tyLent,
                             tySequence, tyProc, tyPointer, tyOpenArray,
                             tyString, tyCstring, tyInt..tyInt64,
                             tyFloat..tyFloat64, tyUInt..tyUInt64}
  Source   Edit
ConstantDataTypes: TTypeKinds = {tyArray, tySet, tyTuple, tySequence}
  Source   Edit
declarativeDefs = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef,
                   nkConverterDef}
  Source   Edit
defaultOffset = -1
  Source   Edit
defaultSize = -1
  Source   Edit
dispatcherPos = 8
  Source   Edit
entityDefs = {nkIdentDefs..nkVarTuple, nkLambda..nkDo, nkProcDef..nkIteratorDef,
              nkForStmt, nkConstDef, nkFuncDef}
all nodes that have definition slots. In other words, semantic analysis of these can introduce new symbols   Source   Edit
errorKindPos = 1
Error kind enum as an intlit   Source   Edit
FakeVarParams = {mInc, mDec, mIncl, mExcl, mSetLengthStr, mSetLengthSeq,
                 mAppendStrCh, mAppendStrStr, mSwap, mAppendSeqElem, mNewSeq,
                 mReset, mShallowCopy, mDeepCopy, mMove, mWasMoved}
An arguments to these magics never uses nkHiddenAddr, even if the corresponding parameter is a 'var' parameter. The reason for this is that these magics are lowered into code that, because it gets inlined directly, doesn't mutate the arguments through indirection. This also implies that the "is address taken" analysis (see sfAddrTaken) must not be performed for arguments to these magics.   Source   Edit
firstArgPos = 3
Error first 0..n additional nodes depends on error kind   Source   Edit
genericParamsPos = 2
Generic parametesr in the procedure-like nodes   Source   Edit
GenericTypes: TTypeKinds = {tyGenericInvocation, tyGenericBody, tyGenericParam}
  Source   Edit
IntegralTypes = {tyBool, tyChar, tyEnum, tyInt..tyInt64, tyFloat..tyFloat64,
                 tyUInt..tyUInt64}
  Source   Edit
magicsThatCanRaise = {mNone, mParseExprToAst, mParseStmtToAst, mEcho, mChckRange}
  Source   Edit
MaxLockLevel = 1000'i16
  Source   Edit
miscPos = 5
used for undocumented and hacky stuff   Source   Edit
namePos = 0
Name of the type/proc-like node   Source   Edit
NilableTypes: TTypeKinds = {tyPointer, tyCstring, tyRef, tyPtr, tyProc, tyProxy}
  Source   Edit
nkAllNodeKinds = {nkError..nkNilRodNode}
  Source   Edit
nkCallKinds = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit,
               nkHiddenCallConv}
  Source   Edit
nkFloatKinds = {nkFloatLit..nkFloat64Lit}
  Source   Edit
nkIdentKinds = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice, nkClosedSymChoice}
  Source   Edit
nkIntKinds = {nkCharLit..nkUInt64Lit}
  Source   Edit
nkLambdaKinds = {nkLambda, nkDo}
  Source   Edit
nkPragmaCallKinds = {nkExprColonExpr, nkCall, nkCallStrLit}
  Source   Edit
nkStrKinds = {nkStrLit..nkTripleStrLit}
  Source   Edit
nkSymChoices = {nkClosedSymChoice, nkOpenSymChoice}
  Source   Edit
nkTypeExprs = {nkTypeOfExpr, nkObjectTy, nkTupleTy, nkTupleClassTy,
               nkTypeClassTy, nkStaticTy, nkRefTy, nkPtrTy, nkVarTy, nkConstTy,
               nkMutableTy, nkDistinctTy, nkProcTy, nkIteratorTy, nkSharedTy,
               nkEnumTy}
  Source   Edit
OverloadableSyms = {skProc, skFunc, skMethod, skIterator, skConverter,
                    skTemplate, skMacro, skEnumField, skModule}
  Source   Edit
paramsPos = 3
Formal parameters in the procedure-like nodes   Source   Edit
patternPos = 1
empty except for term rewriting macros   Source   Edit
PersistentNodeFlags: TNodeFlags = {nfDotSetter, nfDotField, nfLL,
                                   nfFromTemplate, nfDefaultRefsParam,
                                   nfWasGensym}
  Source   Edit
pragmasPos = 4
Position of the pragma in the procedure-like nodes   Source   Edit
procDefs = {nkLambda..nkDo, nkProcDef..nkConverterDef, nkIteratorDef, nkFuncDef}
  Source   Edit
PtrLikeKinds: TTypeKinds = {tyPointer, tyPtr}
  Source   Edit
resultPos = 7
  Source   Edit
routineDefs = {nkProcDef..nkIteratorDef, nkFuncDef}
  Source   Edit
skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch, nkElse,
                      nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
                      nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt,
                      nkBlockExpr, nkHiddenStdConv, nkHiddenDeref}
  Source   Edit
skLocalVars = {skVar, skLet, skForVar, skParam, skResult}
  Source   Edit
skProcKinds = {skProc, skFunc, skTemplate, skMacro, skIterator, skMethod,
               skConverter}
  Source   Edit
StructuralEquivTypes: TTypeKinds = {tyNil, tyTuple, tyArray, tySet, tyRange,
                                    tyPtr, tyRef, tyVar, tyLent, tySequence,
                                    tyProc, tyOpenArray, tyVarargs}
  Source   Edit
UnknownLockLevel = 1001'i16
  Source   Edit
UnspecifiedLockLevel = -1'i16
  Source   Edit
wrongNodePos = 0
Error the ast node we swapped   Source   Edit

Procs

proc `$`(s: PSym): string {....raises: [], tags: [].}
  Source   Edit
proc `$`(x: TLockLevel): string {....raises: [], tags: [].}
  Source   Edit
proc `[]`(node: PNode; pos: NodePosName): PNode {....raises: [], tags: [].}
Get subnode by named position   Source   Edit
proc `[]`(node: PNode; slice: NodeSliceName): seq[PNode] {....raises: [], tags: [].}
Access named node slice   Source   Edit
proc astdef(s: PSym): PNode {....raises: [], tags: [].}
get only the definition (initializer) portion of the ast   Source   Edit
proc canRaise(panicsEnabled: bool; n: PNode): bool {....raises: [], tags: [].}
'true' if a call with n as the callee can exit via exceptional control- flow, otherwise 'false'. If panics are not enabled, this also includes all routines that are not certain magics, compiler procs, or imported.   Source   Edit
proc canRaiseConservative(fn: PNode): bool {....raises: [], tags: [].}
  Source   Edit
proc containsNode(n: PNode; kinds: TNodeKinds): bool {....raises: [], tags: [].}
  Source   Edit
proc endsInNoReturn(n: PNode): bool {....raises: [], tags: [].}
Checks if expression n ends in an unstructured exit (raise, return, etc.) or a call of a noreturn proc. This is meant to be called on a semmed n.   Source   Edit
proc findUnresolvedStatic(n: PNode): PNode {....raises: [], tags: [].}
  Source   Edit
proc getDeclPragma(n: PNode): PNode {....raises: [], tags: [].}
return the nkPragma node for declaration n, or nil if no pragma was found. Currently only supports routineDefs + {nkTypeDef}.   Source   Edit
proc getFloat(a: PNode): BiggestFloat {....raises: [ERecoverableError], tags: [].}
  Source   Edit
proc getIdentLineInfo(n: PNode): TLineInfo {....raises: [], tags: [].}
Returns the line information of the identifier-like node in the (semantically valid) AST n appearing in a name slot.   Source   Edit
proc getInt(a: PNode): Int128 {....raises: [ERecoverableError], tags: [].}
  Source   Edit
proc getInt64(a: PNode): int64 {....deprecated: "use getInt",
                                 raises: [ERecoverableError], tags: [].}
Deprecated: use getInt
  Source   Edit
proc getnimblePkg(a: PSym): PSym {....raises: [], tags: [].}
  Source   Edit
proc getnimblePkgId(a: PSym): int {....raises: [], tags: [].}
  Source   Edit
proc getPIdent(a: PNode): PIdent {.inline, ...raises: [], tags: [].}
Returns underlying PIdent for {nkSym, nkIdent}, or nil.   Source   Edit
proc getStr(a: PNode): string {....raises: [ERecoverableError], tags: [].}
  Source   Edit
proc getStrOrChar(a: PNode): string {....raises: [ERecoverableError], tags: [].}
  Source   Edit
func hasDestructor(t: PType): bool {.inline, ...raises: [], tags: [].}
Returns whether the underlying concrete type of t has attached lifetime tracking hooks (that is, is resource-like).   Source   Edit
proc hasNilSon(n: PNode): bool {....raises: [], tags: [].}
  Source   Edit
proc hasPattern(s: PSym): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc hasSonWith(n: PNode; kind: TNodeKind): bool {....raises: [], tags: [].}
  Source   Edit
proc hasSubnodeWith(n: PNode; kind: TNodeKind): bool {....raises: [], tags: [].}
  Source   Edit
proc isAtom(n: PNode): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isCallExpr(n: PNode): bool {....raises: [], tags: [].}
  Source   Edit
proc isClosure(typ: PType): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isClosureIterator(typ: PType): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isCompileTimeProc(s: PSym): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isEmptyType(t: PType): bool {.inline, ...raises: [], tags: [].}
'void' and 'typed' types are often equivalent to 'nil' these days:   Source   Edit
proc isError(n: PNode): bool {.inline, ...raises: [], tags: [].}
whether the node is an error, strictly checks nkError and is nil safe   Source   Edit
proc isError(s: PSym): bool {.inline, ...raises: [], tags: [].}
whether the symbol is an error, strictly checks skError, an error node exists, and is nil safe.   Source   Edit
proc isError(t: PType): bool {.inline, ...raises: [], tags: [].}

whether the type is an error. useful because of compiler legacy, as tyError isn't an enum field rather a const refering to tyProxy.

xxx: currently we have no way to disambiguate between legacy and new

  Source   Edit
proc isErrorLike(n: PNode): bool {.inline, ...raises: [], tags: [].}
whether the node is an error, including error symbol, or error type
xxx: longer term we should probably not produce nodes like these in the
first place and mark them as nkErrors with an appropriate error kind.
  Source   Edit
proc isErrorLike(s: PSym): bool {.inline, ...raises: [], tags: [].}
whether the symbol is an error. useful because of compiler legacy, as skError isn't an enum field rather a const refering to skUnkonwn. we disambiguate via the presence of the ast field being non-nil and of kind nkError   Source   Edit
proc isErrorLike(t: PType): bool {.inline, ...raises: [], tags: [].}

whether the type is an error. useful because of compiler legacy, as tyError isn't an enum field rather a const refering to tyProxy.

xxx: currently we have no way to disambiguate between legacy and new

  Source   Edit
proc isGenericParams(n: PNode): bool {.inline, ...raises: [], tags: [].}
used to judge whether a node is generic params.   Source   Edit
proc isGenericRoutine(n: PNode): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isGenericRoutine(s: PSym): bool {.inline, ...raises: [], tags: [].}

determines if this symbol represents a generic routine or an instance of one. This should be renamed accordingly and isGenericRoutineStrict should take this name instead.

Warning/XXX: Unfortunately, it considers a proc kind symbol flagged with sfFromGeneric as a generic routine. Instead this should likely not be the case and the concepts should be teased apart:

  • generic definition
  • generic instance
  • either generic definition or instance
  Source   Edit
proc isGenericRoutineStrict(s: PSym): bool {.inline, ...raises: [], tags: [].}
determines if this symbol represents a generic routine the unusual name is so it doesn't collide and eventually replaces isGenericRoutine   Source   Edit
proc isInfixAs(n: PNode): bool {....raises: [], tags: [].}
  Source   Edit
proc isInlineIterator(typ: PType): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isMetaType(t: PType): bool {....raises: [], tags: [].}
  Source   Edit
func isOwnedBy(a, b: PSym): bool {....raises: [], tags: [].}
Tests if b is the transitive owner of a, returns true if a got owned! :)   Source   Edit
proc isRoutine(s: PSym): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isRunnableExamples(n: PNode): bool {....raises: [], tags: [].}
  Source   Edit
proc isSinkParam(s: PSym): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isSinkType(t: PType): bool {.inline, ...raises: [], tags: [].}
  Source   Edit
proc isUnresolvedStatic(t: PType): bool {....raises: [], tags: [].}
  Source   Edit
proc isUnresolvedSym(s: PSym): bool {....raises: [], tags: [].}
  Source   Edit
func lastSon(n: Indexable): Indexable
  Source   Edit
proc originatingModule(s: PSym): PSym {....raises: [], tags: [].}
  Source   Edit
proc requiredGenericParams(s: PSym): int {....raises: [], tags: [].}
  Source   Edit
proc requiredParams(s: PSym): int {....raises: [], tags: [].}
  Source   Edit
proc safeLen(n: PNode): int {.inline, ...raises: [], tags: [].}
works even for leaves.   Source   Edit
proc skipAddr(n: PNode): PNode {.inline, ...raises: [], tags: [].}
  Source   Edit
proc skipColon(n: PNode): PNode {....raises: [], tags: [].}
  Source   Edit
proc skipDistincts(t: PType): PType {.inline, ...raises: [], tags: [].}
Skips over all possible distinct instantiations, getting base.   Source   Edit
proc skipGenericOwner(s: PSym): PSym {....raises: [], tags: [].}
Generic instantiations are owned by their originating generic symbol. This proc skips such owners and goes straight to the owner of the generic itself (the module or the enclosing proc).   Source   Edit
proc skipStmtList(n: PNode): PNode {....raises: [], tags: [].}
  Source   Edit
proc skipTypes(t: PType; kinds: TTypeKinds): PType {....raises: [], tags: [].}
Used throughout the compiler code to test whether a type tree contains or doesn't contain a specific type/types - it is often the case that only the last child nodes of a type tree need to be searched. This is a really hot path within the compiler!   Source   Edit
proc skipTypes(t: PType; kinds: TTypeKinds; maxIters: int): PType {....raises: [],
    tags: [].}
  Source   Edit
proc skipTypesOrNil(t: PType; kinds: TTypeKinds): PType {....raises: [], tags: [].}
same as skipTypes but handles 'nil'   Source   Edit

Iterators

iterator branches(node: PNode): tuple[position: int, n: PNode] {....raises: [],
    tags: [].}
Returns all branches of the case statement or expression node in order of occurrence. position is the 0-based position of the branch, not the index of the sub-node   Source   Edit
iterator branchLabels(node: PNode): (int, PNode) {....raises: [], tags: [].}
Returns all labels of the branch-like constructs (i.e. of, if, elif) that node represents, together with their position. For convenience, else branches are also allowed: they're treated as having no labels   Source   Edit
iterator forLoopDefs(forStmt: PNode): PNode {....raises: [], tags: [].}
Returns the nodes appearing in the name slots (including nested ones) of the provided nkForStmt node.   Source   Edit
iterator genericParamsInMacroCall(macroSym: PSym; call: PNode): (PSym, PNode) {.
    ...raises: [], tags: [].}
For a macro call, yields the symbol for each generic parameter toghether with the argument provided to it   Source   Edit
iterator items(n: PNode): PNode {....raises: [], tags: [].}
  Source   Edit
iterator names(node: PNode): PNode {....raises: [], tags: [].}
Returns the node for each name slot of the node, where node is the definition node for some symbol that is not a routine.   Source   Edit
iterator pairs(n: PNode): tuple[i: int, n: PNode] {....raises: [], tags: [].}
  Source   Edit

Templates

template detailedInfo(sym: PSym): string
  Source   Edit
template fileIdx(c: PSym): FileIndex
  Source   Edit
template filename(c: PSym): string
  Source   Edit
template id(a: PIdObj): int
  Source   Edit
template incompleteType(t: PType): bool
  Source   Edit
template previouslyInferred(t: PType): PType
  Source   Edit
template typeCompleted(s: PSym)
  Source   Edit