modules.nim 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Implements the module handling, including the caching of modules.
  10. import
  11. ast, astalgo, magicsys, msgs, options,
  12. idents, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod,
  13. lineinfos, pathutils, tables
  14. proc resetSystemArtifacts*(g: ModuleGraph) =
  15. magicsys.resetSysTypes(g)
  16. template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent =
  17. getIdent(graph.cache, splitFile(filename).name)
  18. proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym =
  19. ## returns package symbol (skPackage) for yet to be defined module for fileIdx
  20. let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
  21. let name = getModuleIdent(graph, filename)
  22. let info = newLineInfo(fileIdx, 1, 1)
  23. let
  24. pck = getPackageName(graph.config, filename.string)
  25. pck2 = if pck.len > 0: pck else: "unknown"
  26. pack = getIdent(graph.cache, pck2)
  27. var packSym = graph.packageSyms.strTableGet(pack)
  28. if packSym == nil:
  29. packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, info)
  30. initStrTable(packSym.tab)
  31. graph.packageSyms.strTableAdd(packSym)
  32. else:
  33. let existing = strTableGet(packSym.tab, name)
  34. if existing != nil and existing.info.fileIndex != info.fileIndex:
  35. when false:
  36. # we used to produce an error:
  37. localError(graph.config, info,
  38. "module names need to be unique per Nimble package; module clashes with " &
  39. toFullPath(graph.config, existing.info.fileIndex))
  40. else:
  41. # but starting with version 0.20 we now produce a fake Nimble package instead
  42. # to resolve the conflicts:
  43. let pck3 = fakePackageName(graph.config, filename)
  44. # this makes the new `packSym`'s owner be the original `packSym`
  45. packSym = newSym(skPackage, getIdent(graph.cache, pck3), packSym, info)
  46. initStrTable(packSym.tab)
  47. graph.packageSyms.strTableAdd(packSym)
  48. result = packSym
  49. proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
  50. let packSym = getPackage(graph, fileIdx)
  51. result.owner = packSym
  52. result.position = int fileIdx
  53. if int(fileIdx) >= graph.modules.len:
  54. setLen(graph.modules, int(fileIdx) + 1)
  55. graph.modules[result.position] = result
  56. initStrTable(result.tab)
  57. strTableAdd(result.tab, result) # a module knows itself
  58. strTableAdd(packSym.tab, result)
  59. proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
  60. let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
  61. # We cannot call ``newSym`` here, because we have to circumvent the ID
  62. # mechanism, which we do in order to assign each module a persistent ID.
  63. result = PSym(kind: skModule, id: -1, # for better error checking
  64. name: getModuleIdent(graph, filename),
  65. info: newLineInfo(fileIdx, 1, 1))
  66. if not isNimIdentifier(result.name.s):
  67. rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
  68. partialInitModule(result, graph, fileIdx, filename)
  69. proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym =
  70. var flags = flags
  71. if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
  72. result = graph.getModule(fileIdx)
  73. if result == nil:
  74. let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
  75. let (r, id) = loadModuleSym(graph, fileIdx, filename)
  76. result = r
  77. if result == nil:
  78. result = newModule(graph, fileIdx)
  79. result.flags = result.flags + flags
  80. result.id = id
  81. registerModule(graph, result)
  82. else:
  83. partialInitModule(result, graph, fileIdx, filename)
  84. result.id = id
  85. assert result.id < 0
  86. discard processModule(graph, result,
  87. if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
  88. elif graph.isDirty(result):
  89. result.flags.excl sfDirty
  90. # reset module fields:
  91. initStrTable(result.tab)
  92. result.ast = nil
  93. discard processModule(graph, result,
  94. if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
  95. graph.markClientsDirty(fileIdx)
  96. proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
  97. # this is called by the semantic checking phase
  98. assert graph.config != nil
  99. result = compileModule(graph, fileIdx, {})
  100. graph.addDep(s, fileIdx)
  101. # keep track of import relationships
  102. if graph.config.hcrOn:
  103. graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
  104. #if sfSystemModule in result.flags:
  105. # localError(result.info, errAttemptToRedefine, result.name.s)
  106. # restore the notes for outer module:
  107. graph.config.notes =
  108. if s.getnimblePkgId == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
  109. else: graph.config.foreignPackageNotes
  110. proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
  111. result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
  112. graph.addDep(s, fileIdx)
  113. graph.addIncludeDep(s.position.FileIndex, fileIdx)
  114. proc connectCallbacks*(graph: ModuleGraph) =
  115. graph.includeFileCallback = includeModule
  116. graph.importModuleCallback = importModule
  117. proc compileSystemModule*(graph: ModuleGraph) =
  118. if graph.systemModule == nil:
  119. connectCallbacks(graph)
  120. graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
  121. graph.config.libpath / RelativeFile"system.nim")
  122. discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
  123. proc wantMainModule*(conf: ConfigRef) =
  124. if conf.projectFull.isEmpty:
  125. fatal(conf, newLineInfo(conf, AbsoluteFile(commandLineDesc), 1, 1), errGenerated,
  126. "command expects a filename")
  127. conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
  128. proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
  129. connectCallbacks(graph)
  130. let conf = graph.config
  131. wantMainModule(conf)
  132. let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
  133. let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
  134. conf.projectMainIdx2 = projectFile
  135. let packSym = getPackage(graph, projectFile)
  136. graph.config.mainPackageId = packSym.getnimblePkgId
  137. graph.importStack.add projectFile
  138. if projectFile == systemFileIdx:
  139. discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
  140. else:
  141. graph.compileSystemModule()
  142. discard graph.compileModule(projectFile, {sfMainModule})
  143. proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
  144. result = graph.newModule(fileInfoIdx(graph.config, filename))
  145. result.id = getID()
  146. registerModule(graph, result)
  147. proc makeModule*(graph: ModuleGraph; filename: string): PSym =
  148. result = makeModule(graph, AbsoluteFile filename)
  149. proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule(AbsoluteFile"stdin")