modules.nim 6.9 KB

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