importer.nim 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2013 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 symbol importing mechanism.
  10. import
  11. intsets, ast, astalgo, msgs, options, idents, lookups,
  12. semdata, modulepaths, sigmatch, lineinfos, sets
  13. proc readExceptSet*(c: PContext, n: PNode): IntSet =
  14. assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
  15. result = initIntSet()
  16. for i in 1..<n.len:
  17. let ident = lookups.considerQuotedIdent(c, n[i])
  18. result.incl(ident.id)
  19. proc importPureEnumField*(c: PContext; s: PSym) =
  20. let check = strTableGet(c.importTable.symbols, s.name)
  21. if check == nil:
  22. let checkB = strTableGet(c.pureEnumFields, s.name)
  23. if checkB == nil:
  24. strTableAdd(c.pureEnumFields, s)
  25. else:
  26. # mark as ambiguous:
  27. incl(c.ambiguousSymbols, checkB.id)
  28. incl(c.ambiguousSymbols, s.id)
  29. proc rawImportSymbol(c: PContext, s, origin: PSym) =
  30. # This does not handle stubs, because otherwise loading on demand would be
  31. # pointless in practice. So importing stubs is fine here!
  32. # check if we have already a symbol of the same name:
  33. var check = strTableGet(c.importTable.symbols, s.name)
  34. if check != nil and check.id != s.id:
  35. if s.kind notin OverloadableSyms or check.kind notin OverloadableSyms:
  36. # s and check need to be qualified:
  37. incl(c.ambiguousSymbols, s.id)
  38. incl(c.ambiguousSymbols, check.id)
  39. # thanks to 'export' feature, it could be we import the same symbol from
  40. # multiple sources, so we need to call 'StrTableAdd' here:
  41. strTableAdd(c.importTable.symbols, s)
  42. if s.kind == skType:
  43. var etyp = s.typ
  44. if etyp.kind in {tyBool, tyEnum}:
  45. for j in 0..<etyp.n.len:
  46. var e = etyp.n[j].sym
  47. if e.kind != skEnumField:
  48. internalError(c.config, s.info, "rawImportSymbol")
  49. # BUGFIX: because of aliases for enums the symbol may already
  50. # have been put into the symbol table
  51. # BUGFIX: but only iff they are the same symbols!
  52. var it: TIdentIter
  53. check = initIdentIter(it, c.importTable.symbols, e.name)
  54. while check != nil:
  55. if check.id == e.id:
  56. e = nil
  57. break
  58. check = nextIdentIter(it, c.importTable.symbols)
  59. if e != nil:
  60. if sfPure notin s.flags:
  61. rawImportSymbol(c, e, origin)
  62. else:
  63. importPureEnumField(c, e)
  64. else:
  65. if s.kind == skConverter: addConverter(c, s)
  66. if hasPattern(s): addPattern(c, s)
  67. if s.owner != origin:
  68. c.exportIndirections.incl((origin.id, s.id))
  69. proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
  70. let ident = lookups.considerQuotedIdent(c, n)
  71. let s = strTableGet(fromMod.tab, ident)
  72. if s == nil:
  73. errorUndeclaredIdentifier(c, n.info, ident.s)
  74. else:
  75. when false:
  76. if s.kind == skStub: loadStub(s)
  77. let multiImport = s.kind notin ExportableSymKinds or s.kind in skProcKinds
  78. # for an enumeration we have to add all identifiers
  79. if multiImport:
  80. # for a overloadable syms add all overloaded routines
  81. var it: TIdentIter
  82. var e = initIdentIter(it, fromMod.tab, s.name)
  83. while e != nil:
  84. if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
  85. if s.kind in ExportableSymKinds:
  86. rawImportSymbol(c, e, fromMod)
  87. e = nextIdentIter(it, fromMod.tab)
  88. else:
  89. rawImportSymbol(c, s, fromMod)
  90. suggestSym(c.config, n.info, s, c.graph.usageSym, false)
  91. proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
  92. var i: TTabIter
  93. var s = initTabIter(i, fromMod.tab)
  94. while s != nil:
  95. if s.kind != skModule:
  96. if s.kind != skEnumField:
  97. if s.kind notin ExportableSymKinds:
  98. internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
  99. if exceptSet.isNil or s.name.id notin exceptSet:
  100. rawImportSymbol(c, s, fromMod)
  101. s = nextIter(i, fromMod.tab)
  102. proc importAllSymbols*(c: PContext, fromMod: PSym) =
  103. var exceptSet: IntSet
  104. importAllSymbolsExcept(c, fromMod, exceptSet)
  105. proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym) =
  106. if n.isNil: return
  107. case n.kind
  108. of nkExportStmt:
  109. for a in n:
  110. assert a.kind == nkSym
  111. let s = a.sym
  112. if s.kind == skModule:
  113. importAllSymbolsExcept(c, s, exceptSet)
  114. elif exceptSet.isNil or s.name.id notin exceptSet:
  115. rawImportSymbol(c, s, fromMod)
  116. of nkExportExceptStmt:
  117. localError(c.config, n.info, "'export except' not implemented")
  118. else:
  119. for i in 0..n.safeLen-1:
  120. importForwarded(c, n[i], exceptSet, fromMod)
  121. proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
  122. result = realModule
  123. c.unusedImports.add((realModule, n.info))
  124. if n.kind != nkImportAs: discard
  125. elif n.len != 2 or n[1].kind != nkIdent:
  126. localError(c.config, n.info, "module alias must be an identifier")
  127. elif n[1].ident.id != realModule.name.id:
  128. # some misguided guy will write 'import abc.foo as foo' ...
  129. result = createModuleAlias(realModule, n[1].ident, realModule.info,
  130. c.config.options)
  131. proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
  132. let f = checkModuleName(c.config, n)
  133. if f != InvalidFileIdx:
  134. let L = c.graph.importStack.len
  135. let recursion = c.graph.importStack.find(f)
  136. c.graph.importStack.add f
  137. #echo "adding ", toFullPath(f), " at ", L+1
  138. if recursion >= 0:
  139. var err = ""
  140. for i in recursion..<L:
  141. if i > recursion: err.add "\n"
  142. err.add toFullPath(c.config, c.graph.importStack[i]) & " imports " &
  143. toFullPath(c.config, c.graph.importStack[i+1])
  144. c.recursiveDep = err
  145. discard pushOptionEntry(c)
  146. result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f))
  147. popOptionEntry(c)
  148. #echo "set back to ", L
  149. c.graph.importStack.setLen(L)
  150. # we cannot perform this check reliably because of
  151. # test: modules/import_in_config)
  152. when true:
  153. if result.info.fileIndex == c.module.info.fileIndex and
  154. result.info.fileIndex == n.info.fileIndex:
  155. localError(c.config, n.info, "A module cannot import itself")
  156. if sfDeprecated in result.flags:
  157. if result.constraint != nil:
  158. message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s & " is deprecated")
  159. else:
  160. message(c.config, n.info, warnDeprecated, result.name.s & " is deprecated")
  161. suggestSym(c.config, n.info, result, c.graph.usageSym, false)
  162. importStmtResult.add newSymNode(result, n.info)
  163. #newStrNode(toFullPath(c.config, f), n.info)
  164. proc transformImportAs(c: PContext; n: PNode): PNode =
  165. if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as":
  166. result = newNodeI(nkImportAs, n.info)
  167. result.add n[1]
  168. result.add n[2]
  169. else:
  170. result = n
  171. proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
  172. let it = transformImportAs(c, it)
  173. let m = myImportModule(c, it, importStmtResult)
  174. if m != nil:
  175. var emptySet: IntSet
  176. # ``addDecl`` needs to be done before ``importAllSymbols``!
  177. addDecl(c, m, it.info) # add symbol to symbol table of module
  178. importAllSymbolsExcept(c, m, emptySet)
  179. #importForwarded(c, m.ast, emptySet, m)
  180. proc evalImport*(c: PContext, n: PNode): PNode =
  181. result = newNodeI(nkImportStmt, n.info)
  182. for i in 0..<n.len:
  183. let it = n[i]
  184. if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
  185. let sep = it[0]
  186. let dir = it[1]
  187. var imp = newNodeI(nkInfix, it.info)
  188. imp.add sep
  189. imp.add dir
  190. imp.add sep # dummy entry, replaced in the loop
  191. for x in it[2]:
  192. # transform `a/b/[c as d]` to `/a/b/c as d`
  193. if x.kind == nkInfix and x[0].ident.s == "as":
  194. let impAs = copyTree(x)
  195. imp[2] = x[1]
  196. impAs[1] = imp
  197. impMod(c, imp, result)
  198. else:
  199. imp[2] = x
  200. impMod(c, imp, result)
  201. else:
  202. impMod(c, it, result)
  203. proc evalFrom*(c: PContext, n: PNode): PNode =
  204. result = newNodeI(nkImportStmt, n.info)
  205. checkMinSonsLen(n, 2, c.config)
  206. n[0] = transformImportAs(c, n[0])
  207. var m = myImportModule(c, n[0], result)
  208. if m != nil:
  209. n[0] = newSymNode(m)
  210. addDecl(c, m, n.info) # add symbol to symbol table of module
  211. for i in 1..<n.len:
  212. if n[i].kind != nkNilLit:
  213. importSymbol(c, n[i], m)
  214. proc evalImportExcept*(c: PContext, n: PNode): PNode =
  215. result = newNodeI(nkImportStmt, n.info)
  216. checkMinSonsLen(n, 2, c.config)
  217. n[0] = transformImportAs(c, n[0])
  218. var m = myImportModule(c, n[0], result)
  219. if m != nil:
  220. n[0] = newSymNode(m)
  221. addDecl(c, m, n.info) # add symbol to symbol table of module
  222. importAllSymbolsExcept(c, m, readExceptSet(c, n))
  223. #importForwarded(c, m.ast, exceptSet, m)