This module implements the module graph data structure. The module graph represents a complete Nim project. Single modules can either be kept in RAM or stored in a Sqlite database.

The caching of modules is critical for 'nimsuggest' and is tricky to get right. If module E is being edited, we need autocompletion (and type checking) for E but we don't want to recompile depending modules right away for faster turnaround times. Instead we mark the module's dependencies as 'dirty'. Let D be a dependency of E. If D is dirty, we need to recompile it and all of its dependencies that are marked as 'dirty'. 'nimsuggest sug' actually is invoked for the file being edited so we know its content changed and there is no need to compute any checksums. Instead of a recursive algorithm, we use an iterative algorithm:

  • If a module gets recompiled, its dependencies need to be updated.
  • Its dependent module stays the same.


SigHash = distinct MD5Digest
  Source Edit
ModuleGraph {...}{.acyclic.} = ref object
  modules*: seq[PSym]        ## indexed by int32 fileIdx
  packageSyms*: TStrTable
  deps*: IntSet
  importDeps*: Table[FileIndex, seq[FileIndex]]
  suggestMode*: bool
  invalidTransitiveClosure: bool
  inclToMod*: Table[FileIndex, FileIndex]
  importStack*: seq[FileIndex]
  backend*: RootRef
  config*: ConfigRef
  cache*: IdentCache
  vm*: RootRef
  doStopCompile*: proc (): bool {...}{.closure.}
  usageSym*: PSym
  owners*: seq[PSym]
  methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]]
  systemModule*: PSym
  sysTypes*: array[TTypeKind, PType]
  compilerprocs*: TStrTable
  exposed*: TStrTable
  intTypeCache*: array[-5 .. 64, PType]
  opContains*, opNot*: PSym
  emptyNode*: PNode
  incr*: IncrementalCtx
  canonTypes*: Table[SigHash, PType]
  symBodyHashes*: Table[int, SigHash]
  importModuleCallback*: proc (graph: ModuleGraph; m: PSym; fileIdx: FileIndex): PSym {...}{.
  includeFileCallback*: proc (graph: ModuleGraph; m: PSym; fileIdx: FileIndex): PNode {...}{.
  recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {...}{.nimcall.}
  cacheSeqs*: Table[string, PNode]
  cacheCounters*: Table[string, BiggestInt]
  cacheTables*: Table[string, BTree[string, PNode]]
  passes*: seq[TPass]
  onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {...}{.nimcall.}
  onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym;
                                     info: TLineInfo) {...}{.nimcall.}
  onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {...}{.nimcall.}
  globalDestructors*: seq[PNode]
  strongSemCheck*: proc (graph: ModuleGraph; owner: PSym; body: PNode) {...}{.nimcall.}
  compatibleProps*: proc (graph: ModuleGraph; formal, actual: PType): bool {...}{.
  Source Edit
TPassContext = object of RootObj
  Source Edit
PPassContext = ref TPassContext
  Source Edit
TPassOpen = proc (graph: ModuleGraph; module: PSym): PPassContext {...}{.nimcall.}
  Source Edit
TPassClose = proc (graph: ModuleGraph; p: PPassContext; n: PNode): PNode {...}{.
  Source Edit
TPassProcess = proc (p: PPassContext; topLevelStmt: PNode): PNode {...}{.nimcall.}
  Source Edit
TPass = tuple[open: TPassOpen, process: TPassProcess, close: TPassClose,
              isFrontend: bool]
  Source Edit


proc `$`(u: SigHash): string {...}{.raises: [], tags: [].}
  Source Edit
proc `==`(a, b: SigHash): bool {...}{.raises: [], tags: [].}
  Source Edit
proc hash(u: SigHash): Hash {...}{.raises: [], tags: [].}
  Source Edit
proc hash(x: FileIndex): Hash {...}{.borrow.}
  Source Edit
proc stopCompile(g: ModuleGraph): bool {...}{.inline, raises: [Exception],
    tags: [RootEffect].}
  Source Edit
proc createMagic(g: ModuleGraph; name: string; m: TMagic): PSym {...}{.raises: [],
    tags: [].}
  Source Edit
proc newModuleGraph(cache: IdentCache; config: ConfigRef): ModuleGraph {...}{.
    raises: [], tags: [].}
  Source Edit
proc resetAllModules(g: ModuleGraph) {...}{.raises: [], tags: [].}
  Source Edit
proc getModule(g: ModuleGraph; fileIdx: FileIndex): PSym {...}{.raises: [], tags: [].}
  Source Edit
proc addDep(g: ModuleGraph; m: PSym; dep: FileIndex) {...}{.raises: [], tags: [].}
  Source Edit
proc addIncludeDep(g: ModuleGraph; module, includeFile: FileIndex) {...}{.raises: [],
    tags: [].}
  Source Edit
proc parentModule(g: ModuleGraph; fileIdx: FileIndex): FileIndex {...}{.raises: [],
    tags: [].}
returns 'fileIdx' if the file belonging to this index is directly used as a module or else the module that first references this include file.   Source Edit
proc markDirty(g: ModuleGraph; fileIdx: FileIndex) {...}{.raises: [], tags: [].}
  Source Edit
proc markClientsDirty(g: ModuleGraph; fileIdx: FileIndex) {...}{.raises: [], tags: [].}
  Source Edit
proc isDirty(g: ModuleGraph; m: PSym): bool {...}{.raises: [], tags: [].}
  Source Edit


template onUse(info: TLineInfo; s: PSym)
  Source Edit
template onDef(info: TLineInfo; s: PSym)
  Source Edit
template onDefResolveForward(info: TLineInfo; s: PSym)
  Source Edit