summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--compiler/importer.nim13
-rw-r--r--compiler/semexprs.nim23
-rw-r--r--doc/manual.rst3
-rw-r--r--tests/modules/definitions.nim4
-rw-r--r--tests/modules/proxy_module.nim3
6 files changed, 41 insertions, 7 deletions
diff --git a/changelog.md b/changelog.md
index 2a1e80573..cbefbc421 100644
--- a/changelog.md
+++ b/changelog.md
@@ -108,6 +108,8 @@
 - Thread-local variables can now be declared inside procs. This implies all
   the effects of the `global` pragma.
 
+- Nim now supports `except` clause in the export statement.
+
 ### Tool changes
 
 - ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed
diff --git a/compiler/importer.nim b/compiler/importer.nim
index f4903e6c4..a5c361864 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -16,6 +16,13 @@ import
 proc evalImport*(c: PContext, n: PNode): PNode
 proc evalFrom*(c: PContext, n: PNode): PNode
 
+proc readExceptSet*(n: PNode): IntSet =
+  assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
+  result = initIntSet()
+  for i in 1 ..< n.len:
+    let ident = lookups.considerQuotedIdent(n[i])
+    result.incl(ident.id)
+
 proc importPureEnumField*(c: PContext; s: PSym) =
   var check = strTableGet(c.importTable.symbols, s.name)
   if check == nil:
@@ -198,9 +205,5 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
   if m != nil:
     n.sons[0] = newSymNode(m)
     addDecl(c, m, n.info)               # add symbol to symbol table of module
-    var exceptSet = initIntSet()
-    for i in countup(1, sonsLen(n) - 1):
-      let ident = lookups.considerQuotedIdent(n.sons[i])
-      exceptSet.incl(ident.id)
-    importAllSymbolsExcept(c, m, exceptSet)
+    importAllSymbolsExcept(c, m, readExceptSet(n))
     #importForwarded(c, m.ast, exceptSet)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 5ef9916ad..1ef284a77 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -2160,9 +2160,25 @@ proc semBlock(c: PContext, n: PNode): PNode =
   closeScope(c)
   dec(c.p.nestedBlockCounter)
 
+proc semExportExcept(c: PContext, n: PNode): PNode =
+  let moduleName = semExpr(c, n[0])
+  if moduleName.kind != nkSym or moduleName.sym.kind != skModule:
+    localError(n.info, "The export/except syntax expects a module name")
+    return
+  let exceptSet = readExceptSet(n)
+  let exported = moduleName.sym
+  strTableAdd(c.module.tab, exported)
+  var i: TTabIter
+  var s = initTabIter(i, exported.tab)
+  while s != nil:
+    if s.kind in ExportableSymKinds+{skModule} and
+       s.name.id notin exceptSet:
+      strTableAdd(c.module.tab, s)
+    s = nextIter(i, exported.tab)
+  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
@@ -2448,9 +2464,12 @@ 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:
+  of nkExportStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
     result = semExport(c, n)
+  of nkExportExceptStmt:
+    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
+    result = semExportExcept(c, n)
   of nkPragmaBlock:
     result = semPragmaBlock(c, n)
   of nkStaticStmt:
diff --git a/doc/manual.rst b/doc/manual.rst
index 1a4ed19b7..44e2ee5b5 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -6298,6 +6298,9 @@ modules don't need to import a module's dependencies:
   var x: MyObject
   echo $x
 
+When the exported symbol is another module, all of its definitions will
+be forwarded. You can use an ``except`` list to exclude some of the symbols.
+
 Note on paths
 -----------
 In module related statements, if any part of the module name /
diff --git a/tests/modules/definitions.nim b/tests/modules/definitions.nim
new file mode 100644
index 000000000..edc6eaa6d
--- /dev/null
+++ b/tests/modules/definitions.nim
@@ -0,0 +1,4 @@
+var v*: int
+proc p* = echo "proc p called"
+template t* = echo "template t expanded"
+
diff --git a/tests/modules/proxy_module.nim b/tests/modules/proxy_module.nim
new file mode 100644
index 000000000..c244688cd
--- /dev/null
+++ b/tests/modules/proxy_module.nim
@@ -0,0 +1,3 @@
+import definitions
+export definitions except p
+