modulegraphs.nim 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2017 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements the module graph data structure. The module graph
  10. ## represents a complete Nim project. Single modules can either be kept in RAM
  11. ## or stored in a rod-file.
  12. import intsets, tables, hashes, md5_old, sequtils
  13. import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
  14. import ic / [packed_ast, ic]
  15. when defined(nimPreviewSlimSystem):
  16. import std/assertions
  17. type
  18. SigHash* = distinct MD5Digest
  19. LazySym* = object
  20. id*: FullId
  21. sym*: PSym
  22. Iface* = object ## data we don't want to store directly in the
  23. ## ast.PSym type for s.kind == skModule
  24. module*: PSym ## module this "Iface" belongs to
  25. converters*: seq[LazySym]
  26. patterns*: seq[LazySym]
  27. pureEnums*: seq[LazySym]
  28. interf: TStrTable
  29. interfHidden: TStrTable
  30. uniqueName*: Rope
  31. Operators* = object
  32. opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym
  33. opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym
  34. FullId* = object
  35. module*: int
  36. packed*: PackedItemId
  37. LazyType* = object
  38. id*: FullId
  39. typ*: PType
  40. LazyInstantiation* = object
  41. module*: int
  42. sym*: FullId
  43. concreteTypes*: seq[FullId]
  44. inst*: PInstantiation
  45. ModuleGraph* {.acyclic.} = ref object
  46. ifaces*: seq[Iface] ## indexed by int32 fileIdx
  47. packed*: PackedModuleGraph
  48. encoders*: seq[PackedEncoder]
  49. typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId.
  50. procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
  51. attachedOps*: array[TTypeAttachedOp, Table[ItemId, PSym]] # Type ID, destructors, etc.
  52. methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
  53. enumToStringProcs*: Table[ItemId, LazySym]
  54. emittedTypeInfo*: Table[string, FileIndex]
  55. startupPackedConfig*: PackedConfig
  56. packageSyms*: TStrTable
  57. deps*: IntSet # the dependency graph or potentially its transitive closure.
  58. importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
  59. suggestMode*: bool # whether we are in nimsuggest mode or not.
  60. invalidTransitiveClosure: bool
  61. inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
  62. # first module that included it
  63. importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive
  64. # module dependencies.
  65. backend*: RootRef # minor hack so that a backend can extend this easily
  66. config*: ConfigRef
  67. cache*: IdentCache
  68. vm*: RootRef # unfortunately the 'vm' state is shared project-wise, this will
  69. # be clarified in later compiler implementations.
  70. doStopCompile*: proc(): bool {.closure.}
  71. usageSym*: PSym # for nimsuggest
  72. owners*: seq[PSym]
  73. suggestSymbols*: Table[FileIndex, seq[tuple[sym: PSym, info: TLineInfo]]]
  74. suggestErrors*: Table[FileIndex, seq[Suggest]]
  75. methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
  76. systemModule*: PSym
  77. sysTypes*: array[TTypeKind, PType]
  78. compilerprocs*: TStrTable
  79. exposed*: TStrTable
  80. packageTypes*: TStrTable
  81. emptyNode*: PNode
  82. canonTypes*: Table[SigHash, PType]
  83. symBodyHashes*: Table[int, SigHash] # symId to digest mapping
  84. importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
  85. includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
  86. cacheSeqs*: Table[string, PNode] # state that is shared to support the 'macrocache' API; IC: implemented
  87. cacheCounters*: Table[string, BiggestInt] # IC: implemented
  88. cacheTables*: Table[string, BTree[string, PNode]] # IC: implemented
  89. passes*: seq[TPass]
  90. onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
  91. onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
  92. onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
  93. globalDestructors*: seq[PNode]
  94. strongSemCheck*: proc (graph: ModuleGraph; owner: PSym; body: PNode) {.nimcall.}
  95. compatibleProps*: proc (graph: ModuleGraph; formal, actual: PType): bool {.nimcall.}
  96. idgen*: IdGenerator
  97. operators*: Operators
  98. TPassContext* = object of RootObj # the pass's context
  99. idgen*: IdGenerator
  100. PPassContext* = ref TPassContext
  101. TPassOpen* = proc (graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nimcall.}
  102. TPassClose* = proc (graph: ModuleGraph; p: PPassContext, n: PNode): PNode {.nimcall.}
  103. TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
  104. TPass* = tuple[open: TPassOpen,
  105. process: TPassProcess,
  106. close: TPassClose,
  107. isFrontend: bool]
  108. proc resetForBackend*(g: ModuleGraph) =
  109. initStrTable(g.compilerprocs)
  110. g.typeInstCache.clear()
  111. g.procInstCache.clear()
  112. for a in mitems(g.attachedOps):
  113. a.clear()
  114. g.methodsPerType.clear()
  115. g.enumToStringProcs.clear()
  116. const
  117. cb64 = [
  118. "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
  119. "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
  120. "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
  121. "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
  122. "0", "1", "2", "3", "4", "5", "6", "7", "8", "9a",
  123. "9b", "9c"]
  124. proc toBase64a(s: cstring, len: int): string =
  125. ## encodes `s` into base64 representation.
  126. result = newStringOfCap(((len + 2) div 3) * 4)
  127. result.add "__"
  128. var i = 0
  129. while i < len - 2:
  130. let a = ord(s[i])
  131. let b = ord(s[i+1])
  132. let c = ord(s[i+2])
  133. result.add cb64[a shr 2]
  134. result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
  135. result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
  136. result.add cb64[c and 0x3F]
  137. inc(i, 3)
  138. if i < len-1:
  139. let a = ord(s[i])
  140. let b = ord(s[i+1])
  141. result.add cb64[a shr 2]
  142. result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
  143. result.add cb64[((b and 0x0F) shl 2)]
  144. elif i < len:
  145. let a = ord(s[i])
  146. result.add cb64[a shr 2]
  147. result.add cb64[(a and 3) shl 4]
  148. template interfSelect(iface: Iface, importHidden: bool): TStrTable =
  149. var ret = iface.interf.addr # without intermediate ptr, it creates a copy and compiler becomes 15x slower!
  150. if importHidden: ret = iface.interfHidden.addr
  151. ret[]
  152. template semtab(g: ModuleGraph, m: PSym): TStrTable =
  153. g.ifaces[m.position].interf
  154. template semtabAll*(g: ModuleGraph, m: PSym): TStrTable =
  155. g.ifaces[m.position].interfHidden
  156. proc initStrTables*(g: ModuleGraph, m: PSym) =
  157. initStrTable(semtab(g, m))
  158. initStrTable(semtabAll(g, m))
  159. proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
  160. strTableAdd(semtab(g, m), s)
  161. strTableAdd(semtabAll(g, m), s)
  162. proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
  163. result = module < g.packed.len and g.packed[module].status == loaded
  164. proc isCachedModule(g: ModuleGraph; m: PSym): bool {.inline.} =
  165. isCachedModule(g, m.position)
  166. proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
  167. when false:
  168. echo "simulating ", moduleSym.name.s, " ", moduleSym.position
  169. simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
  170. proc initEncoder*(g: ModuleGraph; module: PSym) =
  171. let id = module.position
  172. if id >= g.encoders.len:
  173. setLen g.encoders, id+1
  174. ic.initEncoder(g.encoders[id],
  175. g.packed[id].fromDisk, module, g.config, g.startupPackedConfig)
  176. type
  177. ModuleIter* = object
  178. fromRod: bool
  179. modIndex: int
  180. ti: TIdentIter
  181. rodIt: RodIter
  182. importHidden: bool
  183. proc initModuleIter*(mi: var ModuleIter; g: ModuleGraph; m: PSym; name: PIdent): PSym =
  184. assert m.kind == skModule
  185. mi.modIndex = m.position
  186. mi.fromRod = isCachedModule(g, mi.modIndex)
  187. mi.importHidden = optImportHidden in m.options
  188. if mi.fromRod:
  189. result = initRodIter(mi.rodIt, g.config, g.cache, g.packed, FileIndex mi.modIndex, name, mi.importHidden)
  190. else:
  191. result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden), name)
  192. proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym =
  193. if mi.fromRod:
  194. result = nextRodIter(mi.rodIt, g.packed)
  195. else:
  196. result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden))
  197. iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
  198. let importHidden = optImportHidden in m.options
  199. if isCachedModule(g, m):
  200. var rodIt: RodIter
  201. var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position, importHidden)
  202. while r != nil:
  203. yield r
  204. r = nextRodIter(rodIt, g.packed)
  205. else:
  206. for s in g.ifaces[m.position].interfSelect(importHidden).data:
  207. if s != nil:
  208. yield s
  209. proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym =
  210. let importHidden = optImportHidden in m.options
  211. if isCachedModule(g, m):
  212. result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden)
  213. else:
  214. result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name)
  215. proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
  216. result = someSym(g, g.systemModule, name)
  217. iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym =
  218. var mi: ModuleIter
  219. var r = initModuleIter(mi, g, g.systemModule, name)
  220. while r != nil:
  221. yield r
  222. r = nextModuleIter(mi, g)
  223. proc resolveType(g: ModuleGraph; t: var LazyType): PType =
  224. result = t.typ
  225. if result == nil and isCachedModule(g, t.id.module):
  226. result = loadTypeFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
  227. t.typ = result
  228. assert result != nil
  229. proc resolveSym(g: ModuleGraph; t: var LazySym): PSym =
  230. result = t.sym
  231. if result == nil and isCachedModule(g, t.id.module):
  232. result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
  233. t.sym = result
  234. assert result != nil
  235. proc resolveInst(g: ModuleGraph; t: var LazyInstantiation): PInstantiation =
  236. result = t.inst
  237. if result == nil and isCachedModule(g, t.module):
  238. result = PInstantiation(sym: loadSymFromId(g.config, g.cache, g.packed, t.sym.module, t.sym.packed))
  239. result.concreteTypes = newSeq[PType](t.concreteTypes.len)
  240. for i in 0..high(result.concreteTypes):
  241. result.concreteTypes[i] = loadTypeFromId(g.config, g.cache, g.packed,
  242. t.concreteTypes[i].module, t.concreteTypes[i].packed)
  243. t.inst = result
  244. assert result != nil
  245. iterator typeInstCacheItems*(g: ModuleGraph; s: PSym): PType =
  246. if g.typeInstCache.contains(s.itemId):
  247. let x = addr(g.typeInstCache[s.itemId])
  248. for t in mitems(x[]):
  249. yield resolveType(g, t)
  250. iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
  251. if g.procInstCache.contains(s.itemId):
  252. let x = addr(g.procInstCache[s.itemId])
  253. for t in mitems(x[]):
  254. yield resolveInst(g, t)
  255. proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
  256. ## returns the requested attached operation for type `t`. Can return nil
  257. ## if no such operation exists.
  258. result = g.attachedOps[op].getOrDefault(t.itemId)
  259. proc setAttachedOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
  260. ## we also need to record this to the packed module.
  261. g.attachedOps[op][t.itemId] = value
  262. proc setAttachedOpPartial*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
  263. ## we also need to record this to the packed module.
  264. g.attachedOps[op][t.itemId] = value
  265. # XXX Also add to the packed module!
  266. proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
  267. if g.config.symbolFiles != disabledSf:
  268. assert module < g.encoders.len
  269. assert isActive(g.encoders[module])
  270. toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk)
  271. proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
  272. result = resolveSym(g, g.enumToStringProcs[t.itemId])
  273. assert result != nil
  274. proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
  275. g.enumToStringProcs[t.itemId] = LazySym(sym: value)
  276. iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
  277. if g.methodsPerType.contains(t.itemId):
  278. for it in mitems g.methodsPerType[t.itemId]:
  279. yield (it[0], resolveSym(g, it[1]))
  280. proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
  281. g.methodsPerType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
  282. proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
  283. let op = getAttachedOp(g, t, attachedAsgn)
  284. result = op != nil and sfError in op.flags
  285. proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
  286. for k in low(TTypeAttachedOp)..high(TTypeAttachedOp):
  287. let op = getAttachedOp(g, src, k)
  288. if op != nil:
  289. setAttachedOp(g, module, dest, k, op)
  290. proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
  291. if g.config.symbolFiles == disabledSf: return nil
  292. # slow, linear search, but the results are cached:
  293. for module in 0..high(g.packed):
  294. #if isCachedModule(g, module):
  295. let x = searchForCompilerproc(g.packed[module], name)
  296. if x >= 0:
  297. result = loadSymFromId(g.config, g.cache, g.packed, module, toPackedItemId(x))
  298. if result != nil:
  299. strTableAdd(g.compilerprocs, result)
  300. return result
  301. proc loadPackedSym*(g: ModuleGraph; s: var LazySym) =
  302. if s.sym == nil:
  303. s.sym = loadSymFromId(g.config, g.cache, g.packed, s.id.module, s.id.packed)
  304. proc `$`*(u: SigHash): string =
  305. toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
  306. proc `==`*(a, b: SigHash): bool =
  307. result = equalMem(unsafeAddr a, unsafeAddr b, sizeof(a))
  308. proc hash*(u: SigHash): Hash =
  309. result = 0
  310. for x in 0..3:
  311. result = (result shl 8) or u.MD5Digest[x].int
  312. proc hash*(x: FileIndex): Hash {.borrow.}
  313. template getPContext(): untyped =
  314. when c is PContext: c
  315. else: c.c
  316. when defined(nimfind):
  317. template onUse*(info: TLineInfo; s: PSym) =
  318. let c = getPContext()
  319. if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info)
  320. template onDef*(info: TLineInfo; s: PSym) =
  321. let c = getPContext()
  322. if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info)
  323. template onDefResolveForward*(info: TLineInfo; s: PSym) =
  324. let c = getPContext()
  325. if c.graph.onDefinitionResolveForward != nil:
  326. c.graph.onDefinitionResolveForward(c.graph, s, info)
  327. else:
  328. when defined(nimsuggest):
  329. template onUse*(info: TLineInfo; s: PSym) = discard
  330. template onDef*(info: TLineInfo; s: PSym) =
  331. let c = getPContext()
  332. if c.graph.config.suggestVersion == 3:
  333. suggestSym(c.graph, info, s, c.graph.usageSym)
  334. template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
  335. else:
  336. template onUse*(info: TLineInfo; s: PSym) = discard
  337. template onDef*(info: TLineInfo; s: PSym) = discard
  338. template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
  339. proc stopCompile*(g: ModuleGraph): bool {.inline.} =
  340. result = g.doStopCompile != nil and g.doStopCompile()
  341. proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym =
  342. result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {})
  343. result.magic = m
  344. result.flags = {sfNeverRaises}
  345. proc createMagic(g: ModuleGraph; name: string, m: TMagic): PSym =
  346. result = createMagic(g, g.idgen, name, m)
  347. proc registerModule*(g: ModuleGraph; m: PSym) =
  348. assert m != nil
  349. assert m.kind == skModule
  350. if m.position >= g.ifaces.len:
  351. setLen(g.ifaces, m.position + 1)
  352. if m.position >= g.packed.len:
  353. setLen(g.packed, m.position + 1)
  354. g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
  355. uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position))))
  356. initStrTables(g, m)
  357. proc registerModuleById*(g: ModuleGraph; m: FileIndex) =
  358. registerModule(g, g.packed[int m].module)
  359. proc initOperators*(g: ModuleGraph): Operators =
  360. # These are safe for IC.
  361. # Public because it's used by DrNim.
  362. result.opLe = createMagic(g, "<=", mLeI)
  363. result.opLt = createMagic(g, "<", mLtI)
  364. result.opAnd = createMagic(g, "and", mAnd)
  365. result.opOr = createMagic(g, "or", mOr)
  366. result.opIsNil = createMagic(g, "isnil", mIsNil)
  367. result.opEq = createMagic(g, "==", mEqI)
  368. result.opAdd = createMagic(g, "+", mAddI)
  369. result.opSub = createMagic(g, "-", mSubI)
  370. result.opMul = createMagic(g, "*", mMulI)
  371. result.opDiv = createMagic(g, "div", mDivI)
  372. result.opLen = createMagic(g, "len", mLengthSeq)
  373. result.opNot = createMagic(g, "not", mNot)
  374. result.opContains = createMagic(g, "contains", mInSet)
  375. proc initModuleGraphFields(result: ModuleGraph) =
  376. # A module ID of -1 means that the symbol is not attached to a module at all,
  377. # but to the module graph:
  378. result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
  379. initStrTable(result.packageSyms)
  380. result.deps = initIntSet()
  381. result.importDeps = initTable[FileIndex, seq[FileIndex]]()
  382. result.ifaces = @[]
  383. result.importStack = @[]
  384. result.inclToMod = initTable[FileIndex, FileIndex]()
  385. result.owners = @[]
  386. result.suggestSymbols = initTable[FileIndex, seq[tuple[sym: PSym, info: TLineInfo]]]()
  387. result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
  388. result.methods = @[]
  389. initStrTable(result.compilerprocs)
  390. initStrTable(result.exposed)
  391. initStrTable(result.packageTypes)
  392. result.emptyNode = newNode(nkEmpty)
  393. result.cacheSeqs = initTable[string, PNode]()
  394. result.cacheCounters = initTable[string, BiggestInt]()
  395. result.cacheTables = initTable[string, BTree[string, PNode]]()
  396. result.canonTypes = initTable[SigHash, PType]()
  397. result.symBodyHashes = initTable[int, SigHash]()
  398. result.operators = initOperators(result)
  399. result.emittedTypeInfo = initTable[string, FileIndex]()
  400. proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
  401. result = ModuleGraph()
  402. result.config = config
  403. result.cache = cache
  404. initModuleGraphFields(result)
  405. proc resetAllModules*(g: ModuleGraph) =
  406. initStrTable(g.packageSyms)
  407. g.deps = initIntSet()
  408. g.ifaces = @[]
  409. g.importStack = @[]
  410. g.inclToMod = initTable[FileIndex, FileIndex]()
  411. g.usageSym = nil
  412. g.owners = @[]
  413. g.methods = @[]
  414. initStrTable(g.compilerprocs)
  415. initStrTable(g.exposed)
  416. initModuleGraphFields(g)
  417. proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
  418. if fileIdx.int32 >= 0:
  419. if isCachedModule(g, fileIdx.int32):
  420. result = g.packed[fileIdx.int32].module
  421. elif fileIdx.int32 < g.ifaces.len:
  422. result = g.ifaces[fileIdx.int32].module
  423. proc moduleOpenForCodegen*(g: ModuleGraph; m: FileIndex): bool {.inline.} =
  424. if g.config.symbolFiles == disabledSf:
  425. result = true
  426. else:
  427. result = g.packed[m.int32].status notin {undefined, stored, loaded}
  428. proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) =
  429. #assert(not isCachedModule(g, m.int32))
  430. if g.config.symbolFiles != disabledSf:
  431. #assert g.encoders[m.int32].isActive
  432. assert g.packed[m.int32].status != stored
  433. g.packed[m.int32].fromDisk.emittedTypeInfo.add ti
  434. #echo "added typeinfo ", m.int32, " ", ti, " suspicious ", not g.encoders[m.int32].isActive
  435. proc rememberFlag*(g: ModuleGraph; m: PSym; flag: ModuleBackendFlag) =
  436. if g.config.symbolFiles != disabledSf:
  437. #assert g.encoders[m.int32].isActive
  438. assert g.packed[m.position].status != stored
  439. g.packed[m.position].fromDisk.backendFlags.incl flag
  440. proc closeRodFile*(g: ModuleGraph; m: PSym) =
  441. if g.config.symbolFiles in {readOnlySf, v2Sf}:
  442. # For stress testing we seek to reload the symbols from memory. This
  443. # way much of the logic is tested but the test is reproducible as it does
  444. # not depend on the hard disk contents!
  445. let mint = m.position
  446. saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))),
  447. g.encoders[mint], g.packed[mint].fromDisk)
  448. g.packed[mint].status = stored
  449. elif g.config.symbolFiles == stressTest:
  450. # debug code, but maybe a good idea for production? Could reduce the compiler's
  451. # memory consumption considerably at the cost of more loads from disk.
  452. let mint = m.position
  453. simulateCachedModule(g, m, g.packed[mint].fromDisk)
  454. g.packed[mint].status = loaded
  455. proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
  456. proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
  457. assert m.position == m.info.fileIndex.int32
  458. if g.suggestMode:
  459. g.deps.incl m.position.dependsOn(dep.int)
  460. # we compute the transitive closure later when querying the graph lazily.
  461. # this improves efficiency quite a lot:
  462. #invalidTransitiveClosure = true
  463. proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
  464. discard hasKeyOrPut(g.inclToMod, includeFile, module)
  465. proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =
  466. ## returns 'fileIdx' if the file belonging to this index is
  467. ## directly used as a module or else the module that first
  468. ## references this include file.
  469. if fileIdx.int32 >= 0 and fileIdx.int32 < g.ifaces.len and g.ifaces[fileIdx.int32].module != nil:
  470. result = fileIdx
  471. else:
  472. result = g.inclToMod.getOrDefault(fileIdx)
  473. proc transitiveClosure(g: var IntSet; n: int) =
  474. # warshall's algorithm
  475. for k in 0..<n:
  476. for i in 0..<n:
  477. for j in 0..<n:
  478. if i != j and not g.contains(i.dependsOn(j)):
  479. if g.contains(i.dependsOn(k)) and g.contains(k.dependsOn(j)):
  480. g.incl i.dependsOn(j)
  481. proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
  482. let m = g.getModule fileIdx
  483. if m != nil:
  484. g.suggestSymbols.del(fileIdx)
  485. g.suggestErrors.del(fileIdx)
  486. incl m.flags, sfDirty
  487. proc unmarkAllDirty*(g: ModuleGraph) =
  488. for i in 0i32..<g.ifaces.len.int32:
  489. let m = g.ifaces[i].module
  490. if m != nil:
  491. m.flags.excl sfDirty
  492. proc isDirty*(g: ModuleGraph; m: PSym): bool =
  493. result = g.suggestMode and sfDirty in m.flags
  494. proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
  495. # we need to mark its dependent modules D as dirty right away because after
  496. # nimsuggest is done with this module, the module's dirty flag will be
  497. # cleared but D still needs to be remembered as 'dirty'.
  498. if g.invalidTransitiveClosure:
  499. g.invalidTransitiveClosure = false
  500. transitiveClosure(g.deps, g.ifaces.len)
  501. # every module that *depends* on this file is also dirty:
  502. for i in 0i32..<g.ifaces.len.int32:
  503. if g.deps.contains(i.dependsOn(fileIdx.int)):
  504. g.markDirty(FileIndex(i))
  505. proc needsCompilation*(g: ModuleGraph): bool =
  506. # every module that *depends* on this file is also dirty:
  507. for i in 0i32..<g.ifaces.len.int32:
  508. let m = g.ifaces[i].module
  509. if m != nil:
  510. if sfDirty in m.flags:
  511. return true
  512. proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
  513. let module = g.getModule(fileIdx)
  514. if module != nil and g.isDirty(module):
  515. return true
  516. for i in 0i32..<g.ifaces.len.int32:
  517. let m = g.ifaces[i].module
  518. if m != nil and g.isDirty(m) and g.deps.contains(fileIdx.int32.dependsOn(i)):
  519. return true
  520. proc getBody*(g: ModuleGraph; s: PSym): PNode {.inline.} =
  521. result = s.ast[bodyPos]
  522. if result == nil and g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
  523. result = loadProcBody(g.config, g.cache, g.packed, s)
  524. s.ast[bodyPos] = result
  525. assert result != nil
  526. proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
  527. cachedModules: var seq[FileIndex]): PSym =
  528. ## Returns 'nil' if the module needs to be recompiled.
  529. if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
  530. result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
  531. proc configComplete*(g: ModuleGraph) =
  532. rememberStartupConfig(g.startupPackedConfig, g.config)
  533. from std/strutils import repeat, `%`
  534. proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, fromModule: PSym, ) =
  535. let conf = graph.config
  536. let isNimscript = conf.isDefined("nimscript")
  537. if (not isNimscript) or hintProcessing in conf.cmdlineNotes:
  538. let path = toFilenameOption(conf, fileIdx, conf.filenameOption)
  539. let indent = ">".repeat(graph.importStack.len)
  540. let fromModule2 = if fromModule != nil: $fromModule.name.s else: "(toplevel)"
  541. let mode = if isNimscript: "(nims) " else: ""
  542. rawMessage(conf, hintProcessing, "$#$# $#: $#: $#" % [mode, indent, fromModule2, moduleStatus, path])
  543. proc getPackage*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
  544. ## Returns a package symbol for yet to be defined module for fileIdx.
  545. ## The package symbol is added to the graph if it doesn't exist.
  546. let pkgSym = getPackage(graph.config, graph.cache, fileIdx)
  547. # check if the package is already in the graph
  548. result = graph.packageSyms.strTableGet(pkgSym.name)
  549. if result == nil:
  550. # the package isn't in the graph, so create and add it
  551. result = pkgSym
  552. graph.packageSyms.strTableAdd(pkgSym)
  553. func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
  554. ## Check if symbol belongs to the 'stdlib' package.
  555. sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId
  556. iterator suggestSymbolsIter*(g: ModuleGraph): tuple[sym: PSym, info: TLineInfo] =
  557. for xs in g.suggestSymbols.values:
  558. for x in xs.deduplicate:
  559. yield x
  560. iterator suggestErrorsIter*(g: ModuleGraph): Suggest =
  561. for xs in g.suggestErrors.values:
  562. for x in xs:
  563. yield x