summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-12-02 11:13:05 +0100
committerAraq <rumpf_a@web.de>2012-12-02 11:13:05 +0100
commit6ce15652d355abcd7356be1348f6e7817de53a90 (patch)
treefb2209f0bca795674a16ac7cafb839e1181caacc /compiler
parentda5ba6ce622d8a3fa7c0b6c1f234bd01dfa573a4 (diff)
parent9c0355a13fce08b99f2bac52d7042b73f21003d7 (diff)
downloadNim-6ce15652d355abcd7356be1348f6e7817de53a90.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/astalgo.nim17
-rwxr-xr-xcompiler/importer.nim79
-rwxr-xr-xcompiler/semexprs.nim23
3 files changed, 79 insertions, 40 deletions
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index da0de3e94..9a2bebab4 100755
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -585,8 +585,9 @@ proc StrTableContains(t: TStrTable, n: PSym): bool =
 proc StrTableRawInsert(data: var TSymSeq, n: PSym) = 
   var h: THash = n.name.h and high(data)
   while data[h] != nil: 
-    if data[h] == n: 
-      InternalError(n.info, "StrTableRawInsert: " & n.name.s)
+    if data[h] == n:
+      # allowed for 'export' feature:
+      #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
       return
     h = nextTry(h, high(data))
   assert(data[h] == nil)
@@ -617,23 +618,23 @@ proc StrTableAdd(t: var TStrTable, n: PSym) =
   StrTableRawInsert(t.data, n)
   inc(t.counter)
 
-proc StrTableIncl*(t: var TStrTable, n: PSym): bool = 
+proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
   # returns true if n is already in the string table:
   # It is essential that `n` is written nevertheless!
   # This way the newest redefinition is picked by the semantic analyses!
   assert n.name != nil
   var h: THash = n.name.h and high(t.data)
-  while true: 
+  while true:
     var it = t.data[h]
-    if it == nil: break 
-    if it.name.id == n.name.id: 
+    if it == nil: break
+    if it.name.id == n.name.id:
       t.data[h] = n           # overwrite it with newer definition!
       return true             # found it
     h = nextTry(h, high(t.data))
-  if mustRehash(len(t.data), t.counter): 
+  if mustRehash(len(t.data), t.counter):
     StrTableEnlarge(t)
     StrTableRawInsert(t.data, n)
-  else: 
+  else:
     assert(t.data[h] == nil)
     t.data[h] = n
   inc(t.counter)
diff --git a/compiler/importer.nim b/compiler/importer.nim
index b3821746c..774bcea6a 100755
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -15,7 +15,6 @@ import
 
 proc evalImport*(c: PContext, n: PNode): PNode
 proc evalFrom*(c: PContext, n: PNode): PNode
-proc importAllSymbols*(c: PContext, fromMod: PSym)
 
 proc getModuleName*(n: PNode): string =
   # This returns a short relative module name without the nim extension
@@ -29,9 +28,11 @@ proc getModuleName*(n: PNode): string =
   of nkSym:
     result = n.sym.name.s
   else:
-    localError(n.info, errGenerated,
-      "invalide module name: '$1'" % renderTree(n))
-    result = ""
+    # hacky way to implement 'x / y /../ z':
+    result = renderTree(n, {renderNoComments}).replace(" ")
+    #localError(n.info, errGenerated,
+    #  "invalide module name: '$1'" % renderTree(n))
+    #result = ""
 
 proc checkModuleName*(n: PNode): string =
   # This returns the full canonical path for a given module import
@@ -40,42 +41,43 @@ proc checkModuleName*(n: PNode): string =
   if result.len == 0:
     LocalError(n.info, errCannotOpenFile, modulename)
 
-proc rawImportSymbol(c: PContext, s: PSym) = 
+proc rawImportSymbol(c: PContext, s: PSym) =
   # This does not handle stubs, because otherwise loading on demand would be
   # pointless in practice. So importing stubs is fine here!
-  var copy = s # do not copy symbols when importing!
   # check if we have already a symbol of the same name:
   var check = StrTableGet(c.tab.stack[importTablePos], s.name)
-  if check != nil and check.id != copy.id: 
-    if s.kind notin OverloadableSyms: 
+  if check != nil and check.id != s.id:
+    if s.kind notin OverloadableSyms:
       # s and check need to be qualified:
-      Incl(c.AmbiguousSymbols, copy.id)
+      Incl(c.AmbiguousSymbols, s.id)
       Incl(c.AmbiguousSymbols, check.id)
-  StrTableAdd(c.tab.stack[importTablePos], copy)
-  if s.kind == skType: 
+  # thanks to 'export' feature, it could be we import the same symbol from
+  # multiple sources, so we need to call 'StrTableAdd' here:
+  StrTableAdd(c.tab.stack[importTablePos], s)
+  if s.kind == skType:
     var etyp = s.typ
-    if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags: 
-      for j in countup(0, sonsLen(etyp.n) - 1): 
+    if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
+      for j in countup(0, sonsLen(etyp.n) - 1):
         var e = etyp.n.sons[j].sym
-        if (e.Kind != skEnumField): 
+        if e.Kind != skEnumField: 
           InternalError(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!
         var it: TIdentIter 
         check = InitIdentIter(it, c.tab.stack[importTablePos], e.name)
-        while check != nil: 
-          if check.id == e.id: 
+        while check != nil:
+          if check.id == e.id:
             e = nil
-            break 
+            break
           check = NextIdentIter(it, c.tab.stack[importTablePos])
-        if e != nil: 
+        if e != nil:
           rawImportSymbol(c, e)
   else:
     # rodgen assures that converters and patterns are no stubs
     if s.kind == skConverter: addConverter(c, s)
     if hasPattern(s): addPattern(c, s)
-  
+
 proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = 
   let ident = lookups.considerAcc(n)
   let s = StrTableGet(fromMod.tab, ident)
@@ -96,17 +98,6 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
         rawImportSymbol(c, e)
         e = NextIdentIter(it, fromMod.tab)
     else: rawImportSymbol(c, s)
-  
-proc importAllSymbols(c: PContext, fromMod: PSym) = 
-  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(s.info, "importAllSymbols: " & $s.kind)
-        rawImportSymbol(c, s) # this is correct!
-    s = NextIter(i, fromMod.tab)
 
 proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
   var i: TTabIter
@@ -116,12 +107,34 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
       if s.kind != skEnumField:
         if s.Kind notin ExportableSymKinds:
           InternalError(s.info, "importAllSymbols: " & $s.kind)
-        if s.name.id notin exceptSet:
+        if exceptSet.empty or s.name.id notin exceptSet:
           rawImportSymbol(c, s)
     s = NextIter(i, fromMod.tab)
 
+proc importAllSymbols*(c: PContext, fromMod: PSym) =
+  var exceptSet: TIntSet
+  importAllSymbolsExcept(c, fromMod, exceptSet)
+
+proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
+  if n.isNil: return
+  case n.kind
+  of nkExportStmt:
+    for a in n:
+      assert a.kind == nkSym
+      let s = a.sym
+      if s.kind == skModule:
+        importAllSymbolsExcept(c, s, exceptSet)
+      elif exceptSet.empty or s.name.id notin exceptSet:
+        rawImportSymbol(c, s)
+  of nkExportExceptStmt:
+    localError(n.info, errGenerated, "'export except' not implemented")
+  else:
+    for i in 0 ..safeLen(n)-1:
+      importForwarded(c, n.sons[i], exceptSet)
+
 proc evalImport(c: PContext, n: PNode): PNode = 
   result = n
+  var emptySet: TIntSet
   for i in countup(0, sonsLen(n) - 1): 
     var f = checkModuleName(n.sons[i])
     if f.len > 0:
@@ -130,7 +143,8 @@ proc evalImport(c: PContext, n: PNode): PNode =
         Message(n.sons[i].info, warnDeprecated, m.name.s) 
       # ``addDecl`` needs to be done before ``importAllSymbols``!
       addDecl(c, m)             # add symbol to symbol table of module
-      importAllSymbols(c, m)
+      importAllSymbolsExcept(c, m, emptySet)
+      importForwarded(c, m.ast, emptySet)
 
 proc evalFrom(c: PContext, n: PNode): PNode = 
   result = n
@@ -155,3 +169,4 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
       let ident = lookups.considerAcc(n.sons[i])
       exceptSet.incl(ident.id)
     importAllSymbolsExcept(c, m, exceptSet)
+    importForwarded(c, m.ast, exceptSet)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index c5e3fdc1e..7b37987ee 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1659,6 +1659,26 @@ proc fixImmediateParams(n: PNode): PNode =
   
   result = n
 
+proc semExport(c: PContext, n: PNode): PNode =
+  var x = newNodeI(n.kind, n.info)
+  #let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
+  for i in 0.. <n.len:
+    let a = n.sons[i]
+    var o: TOverloadIter
+    var s = initOverloadIter(o, c, a)
+    if s == nil:
+      localError(a.info, errGenerated, "invalid expr for 'export': " &
+          renderTree(a))
+    while s != nil:
+      if s.kind in ExportableSymKinds+{skModule}:
+        x.add(newSymNode(s, a.info))
+      s = nextOverloadIter(o, c, a)
+  if c.module.ast.isNil:
+    c.module.ast = newNodeI(nkStmtList, n.info)
+  assert c.module.ast.kind == nkStmtList
+  c.module.ast.add x
+  result = n
+
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
   result = n
   if gCmd == cmdIdeTools: suggestExpr(c, n)
@@ -1861,6 +1881,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkIncludeStmt: 
     if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include")
     result = evalInclude(c, n)
+  of nkExportStmt, nkExportExceptStmt:
+    if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "export")
+    result = semExport(c, n)
   of nkPragmaBlock:
     result = semPragmaBlock(c, n)
   of nkStaticStmt: