summary refs log tree commit diff stats
path: root/compiler/importer.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/importer.nim')
-rw-r--r--compiler/importer.nim167
1 files changed, 127 insertions, 40 deletions
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 6722eab15..a055e16b7 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -20,30 +20,67 @@ proc readExceptSet*(c: PContext, n: PNode): IntSet =
     let ident = lookups.considerQuotedIdent(c, n[i])
     result.incl(ident.id)
 
-proc importPureEnumField*(c: PContext; s: PSym) =
-  let check = strTableGet(c.importTable.symbols, s.name)
-  if check == nil:
-    let checkB = strTableGet(c.pureEnumFields, s.name)
-    if checkB == nil:
-      strTableAdd(c.pureEnumFields, s)
-    else:
+proc declarePureEnumField*(c: PContext; s: PSym) =
+  # XXX Remove the outer 'if' statement and see what breaks.
+  var amb = false
+  if someSymFromImportTable(c, s.name, amb) == nil:
+    strTableAdd(c.pureEnumFields, s)
+    when false:
+      let checkB = strTableGet(c.pureEnumFields, s.name)
+      if checkB == nil:
+        strTableAdd(c.pureEnumFields, s)
+    when false:
+      # mark as ambiguous:
+      incl(c.ambiguousSymbols, checkB.id)
+      incl(c.ambiguousSymbols, s.id)
+
+proc importPureEnumField(c: PContext; s: PSym) =
+  var amb = false
+  if someSymFromImportTable(c, s.name, amb) == nil:
+    strTableAdd(c.pureEnumFields, s)
+    when false:
+      let checkB = strTableGet(c.pureEnumFields, s.name)
+      if checkB == nil:
+        strTableAdd(c.pureEnumFields, s)
+    when false:
       # mark as ambiguous:
       incl(c.ambiguousSymbols, checkB.id)
       incl(c.ambiguousSymbols, s.id)
 
-proc rawImportSymbol(c: PContext, s, origin: PSym) =
+proc importPureEnumFields(c: PContext; s: PSym; etyp: PType) =
+  assert sfPure in s.flags
+  for j in 0..<etyp.n.len:
+    var e = etyp.n[j].sym
+    if e.kind != skEnumField:
+      internalError(c.config, s.info, "rawImportSymbol")
+      # BUGFIX: because of aliases for enums the symbol may already
+      # have been put into the symbol table
+      # BUGFIX: but only iff they are the same symbols!
+    for check in importedItems(c, e.name):
+      if check.id == e.id:
+        e = nil
+        break
+    if e != nil:
+      importPureEnumField(c, e)
+
+proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
   # This does not handle stubs, because otherwise loading on demand would be
   # pointless in practice. So importing stubs is fine here!
   # check if we have already a symbol of the same name:
-  var check = strTableGet(c.importTable.symbols, s.name)
-  if check != nil and check.id != s.id:
-    if s.kind notin OverloadableSyms or check.kind notin OverloadableSyms:
-      # s and check need to be qualified:
-      incl(c.ambiguousSymbols, s.id)
-      incl(c.ambiguousSymbols, check.id)
+  when false:
+    var check = someSymFromImportTable(c, s.name)
+    if check != nil and check.id != s.id:
+      if s.kind notin OverloadableSyms or check.kind notin OverloadableSyms:
+        # s and check need to be qualified:
+        incl(c.ambiguousSymbols, s.id)
+        incl(c.ambiguousSymbols, check.id)
   # thanks to 'export' feature, it could be we import the same symbol from
-  # multiple sources, so we need to call 'StrTableAdd' here:
-  strTableAdd(c.importTable.symbols, s)
+  # multiple sources, so we need to call 'strTableAdd' here:
+  when false:
+    # now lazy. Speeds up the compiler and is a prerequisite for IC.
+    strTableAdd(c.importTable.symbols, s)
+  else:
+    importSet.incl s.id
   if s.kind == skType:
     var etyp = s.typ
     if etyp.kind in {tyBool, tyEnum}:
@@ -54,16 +91,13 @@ proc rawImportSymbol(c: PContext, s, origin: PSym) =
           # BUGFIX: because of aliases for enums the symbol may already
           # have been put into the symbol table
           # BUGFIX: but only iff they are the same symbols!
-        var it: TIdentIter
-        check = initIdentIter(it, c.importTable.symbols, e.name)
-        while check != nil:
+        for check in importedItems(c, e.name):
           if check.id == e.id:
             e = nil
             break
-          check = nextIdentIter(it, c.importTable.symbols)
         if e != nil:
           if sfPure notin s.flags:
-            rawImportSymbol(c, e, origin)
+            rawImportSymbol(c, e, origin, importSet)
           else:
             importPureEnumField(c, e)
   else:
@@ -72,7 +106,7 @@ proc rawImportSymbol(c: PContext, s, origin: PSym) =
   if s.owner != origin:
     c.exportIndirections.incl((origin.id, s.id))
 
-proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
+proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) =
   let ident = lookups.considerQuotedIdent(c, n)
   let s = strTableGet(fromMod.tab, ident)
   if s == nil:
@@ -89,29 +123,79 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
       while e != nil:
         if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
         if s.kind in ExportableSymKinds:
-          rawImportSymbol(c, e, fromMod)
+          rawImportSymbol(c, e, fromMod, importSet)
         e = nextIdentIter(it, fromMod.tab)
     else:
-      rawImportSymbol(c, s, fromMod)
+      rawImportSymbol(c, s, fromMod, importSet)
     suggestSym(c.config, n.info, s, c.graph.usageSym, false)
 
+proc addImport(c: PContext; im: sink ImportedModule) =
+  for i in 0..high(c.imports):
+    if c.imports[i].m == im.m:
+      # we have already imported the module: Check which import
+      # is more "powerful":
+      case c.imports[i].mode
+      of importAll: discard "already imported all symbols"
+      of importSet:
+        case im.mode
+        of importAll, importExcept:
+          # XXX: slightly wrong semantics for 'importExcept'...
+          # But we should probably change the spec and disallow this case.
+          c.imports[i] = im
+        of importSet:
+          # merge the import sets:
+          c.imports[i].imported.incl im.imported
+      of importExcept:
+        case im.mode
+        of importAll:
+          c.imports[i] = im
+        of importSet:
+          discard
+        of importExcept:
+          var cut = initIntSet()
+          # only exclude what is consistent between the two sets:
+          for j in im.exceptSet:
+            if j in c.imports[i].exceptSet:
+              cut.incl j
+          c.imports[i].exceptSet = cut
+      return
+  c.imports.add im
+
+template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} =
+  for it in c.graph.ifaces[fromMod.position].converters:
+    if filter:
+      addConverter(c, it)
+  for it in c.graph.ifaces[fromMod.position].patterns:
+    if filter:
+      addPattern(c, it)
+  for it in c.graph.ifaces[fromMod.position].pureEnums:
+    if filter:
+      importPureEnumFields(c, it, it.typ)
+
 proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
-  var i: TTabIter
-  var s = initTabIter(i, fromMod.tab)
-  while s != nil:
-    if s.kind != skModule:
-      if s.kind != skEnumField:
-        if s.kind notin ExportableSymKinds:
-          internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
-        if exceptSet.isNil or s.name.id notin exceptSet:
-          rawImportSymbol(c, s, fromMod)
-    s = nextIter(i, fromMod.tab)
+  c.addImport ImportedModule(m: fromMod, mode: importExcept, exceptSet: exceptSet)
+  addUnnamedIt(c, fromMod, it.id notin exceptSet)
+
+  when false:
+    var i: TTabIter
+    var s = initTabIter(i, fromMod.tab)
+    while s != nil:
+      if s.kind != skModule:
+        if s.kind != skEnumField:
+          if s.kind notin ExportableSymKinds:
+            internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
+          if exceptSet.isNil or s.name.id notin exceptSet:
+            rawImportSymbol(c, s, fromMod)
+      s = nextIter(i, fromMod.tab)
 
 proc importAllSymbols*(c: PContext, fromMod: PSym) =
-  var exceptSet: IntSet
-  importAllSymbolsExcept(c, fromMod, exceptSet)
+  c.addImport ImportedModule(m: fromMod, mode: importAll)
+  addUnnamedIt(c, fromMod, true)
+  when false:
+    var exceptSet: IntSet
+    importAllSymbolsExcept(c, fromMod, exceptSet)
 
-proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym) =
+proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; importSet: var IntSet) =
   if n.isNil: return
   case n.kind
   of nkExportStmt:
@@ -121,12 +205,12 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym) =
       if s.kind == skModule:
         importAllSymbolsExcept(c, s, exceptSet)
       elif exceptSet.isNil or s.name.id notin exceptSet:
-        rawImportSymbol(c, s, fromMod)
+        rawImportSymbol(c, s, fromMod, importSet)
   of nkExportExceptStmt:
     localError(c.config, n.info, "'export except' not implemented")
   else:
     for i in 0..n.safeLen-1:
-      importForwarded(c, n[i], exceptSet, fromMod)
+      importForwarded(c, n[i], exceptSet, fromMod, importSet)
 
 proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
   result = realModule
@@ -224,9 +308,12 @@ proc evalFrom*(c: PContext, n: PNode): PNode =
   if m != nil:
     n[0] = newSymNode(m)
     addDecl(c, m, n.info)               # add symbol to symbol table of module
+
+    var im = ImportedModule(m: m, mode: importSet, imported: initIntSet())
     for i in 1..<n.len:
       if n[i].kind != nkNilLit:
-        importSymbol(c, n[i], m)
+        importSymbol(c, n[i], m, im.imported)
+    c.addImport im
 
 proc evalImportExcept*(c: PContext, n: PNode): PNode =
   result = newNodeI(nkImportStmt, n.info)