summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-09-24 09:36:31 +0200
committerAraq <rumpf_a@web.de>2013-09-24 09:36:31 +0200
commit83584bf88934c45ce10e770ee15d070a09f88f45 (patch)
treec681f943c2f4ba6348eb8f5208c4a577ff183acd /compiler
parent367abca3825fcd2f2a7fdf2bd699986f0535e6b1 (diff)
downloadNim-83584bf88934c45ce10e770ee15d070a09f88f45.tar.gz
implemented 'import a as b'
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim23
-rw-r--r--compiler/importer.nim57
-rw-r--r--compiler/parser.nim23
-rw-r--r--compiler/renderer.nim6
4 files changed, 84 insertions, 25 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index ea60284da..c9c049137 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -131,7 +131,7 @@ type
     nkFormalParams,       # formal parameters
     nkOfInherit,          # inherited from symbol
 
-    nkModule,             # the syntax tree of a module
+    nkImportAs,           # a 'as' b in an import statement
     nkProcDef,            # a proc
     nkMethodDef,          # a method
     nkConverterDef,       # a converter
@@ -641,6 +641,11 @@ type
       # this is because in incremental compilation, when a module is about to
       # be replaced with a newer version, we must decrement the usage count
       # of all previously used generics.
+      # For 'import as' we copy the module symbol but shallowCopy the 'tab'
+      # and set the 'usedGenerics' to ... XXX gah! Better set module.name
+      # instead? But this doesn't work either. --> We need an skModuleAlias?
+      # No need, just leave it as skModule but set the owner accordingly and
+      # check for the owner when touching 'usedGenerics'.
       usedGenerics*: seq[PInstantiation]
       tab*: TStrTable         # interface table for modules
     else: nil
@@ -1106,7 +1111,7 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
   
 proc copySym(s: PSym, keepId: bool = false): PSym = 
   result = newSym(s.kind, s.name, s.owner, s.info)
-  result.ast = nil            # BUGFIX; was: s.ast which made problems
+  #result.ast = nil            # BUGFIX; was: s.ast which made problems
   result.typ = s.typ
   if keepId:
     result.id = s.id
@@ -1121,6 +1126,20 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
   result.position = s.position
   result.loc = s.loc
   result.annex = s.annex      # BUGFIX
+
+proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
+  result = newSym(s.kind, newIdent, s.owner, info)
+  # keep ID!
+  result.ast = s.ast
+  result.id = s.id
+  result.flags = s.flags
+  system.shallowCopy(result.tab, s.tab)
+  result.options = s.options
+  result.position = s.position
+  result.loc = s.loc
+  result.annex = s.annex
+  # XXX once usedGenerics is used, ensure module aliases keep working!
+  assert s.usedGenerics == nil
   
 proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym,
             info: TLineInfo): PSym = 
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 7159072f7..077e5e0c9 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2013 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -27,12 +27,24 @@ proc getModuleName*(n: PNode): string =
     result = n.ident.s
   of nkSym:
     result = n.sym.name.s
-  else:
+  of nkInfix:
+    if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
+      # XXX hack ahead:
+      n.kind = nkImportAs
+      n.sons[0] = n.sons[1]
+      n.sons[1] = n.sons[2]
+      n.sons.setLen(2)
+      return getModuleName(n.sons[0])
     # hacky way to implement 'x / y /../ z':
     result = renderTree(n, {renderNoComments}).replace(" ")
-    #localError(n.info, errGenerated,
-    #  "invalide module name: '$1'" % renderTree(n))
-    #result = ""
+  of nkDotExpr:
+    result = renderTree(n, {renderNoComments}).replace(".")
+  of nkImportAs:
+    result = getModuleName(n.sons[0])
+  else:
+    localError(n.info, errGenerated,
+      "invalid module name: '$1'" % renderTree(n))
+    result = ""
 
 proc checkModuleName*(n: PNode): int32 =
   # This returns the full canonical path for a given module import
@@ -135,15 +147,28 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
     for i in 0 ..safeLen(n)-1:
       importForwarded(c, n.sons[i], exceptSet)
 
+proc importModuleAs(n: PNode, realModule: PSym): PSym =
+  result = realModule
+  if n.kind != nkImportAs: discard
+  elif n.len != 2 or n.sons[1].kind != nkIdent:
+    localError(n.info, errGenerated, "module alias must be an identifier")
+  elif n.sons[1].ident.id != realModule.name.id:
+    # some misguided guy will write 'import abc.foo as foo' ...
+    result = createModuleAlias(realModule, n.sons[1].ident, n.sons[1].info)
+
+proc myImportModule(c: PContext, n: PNode): PSym =
+  var f = checkModuleName(n)
+  if f != InvalidFileIDX:
+    result = importModuleAs(n, gImportModule(c.module, f))
+    if sfDeprecated in result.flags:
+      Message(n.info, warnDeprecated, result.name.s)
+
 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 != InvalidFileIDX:
-      var m = gImportModule(c.module, f)
-      if sfDeprecated in m.flags: 
-        Message(n.sons[i].info, warnDeprecated, m.name.s) 
+    var m = myImportModule(c, n.sons[i])
+    if m != nil:
       # ``addDecl`` needs to be done before ``importAllSymbols``!
       addDecl(c, m)             # add symbol to symbol table of module
       importAllSymbolsExcept(c, m, emptySet)
@@ -152,21 +177,19 @@ proc evalImport(c: PContext, n: PNode): PNode =
 proc evalFrom(c: PContext, n: PNode): PNode = 
   result = n
   checkMinSonsLen(n, 2)
-  var f = checkModuleName(n.sons[0])
-  if f != InvalidFileIDX:
-    var m = gImportModule(c.module, f)
+  var m = myImportModule(c, n.sons[0])
+  if m != nil:
     n.sons[0] = newSymNode(m)
     addDecl(c, m)               # add symbol to symbol table of module
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       if n.sons[i].kind != nkNilLit:
         importSymbol(c, n.sons[i], m)
 
 proc evalImportExcept*(c: PContext, n: PNode): PNode = 
   result = n
   checkMinSonsLen(n, 2)
-  var f = checkModuleName(n.sons[0])
-  if f != InvalidFileIDX:
-    var m = gImportModule(c.module, f)
+  var m = myImportModule(c, n.sons[0])
+  if m != nil:
     n.sons[0] = newSymNode(m)
     addDecl(c, m)               # add symbol to symbol table of module
     var exceptSet = initIntSet()
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 0d9d27e02..a2fe34849 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1088,6 +1088,17 @@ proc parseExprStmt(p: var TParser): PNode =
         addSon(result, b)
         if b.kind == nkElse: break
 
+proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
+  result = parseExpr(p)
+  when false:
+    # parseExpr already handles 'as' syntax ...
+    if p.tok.tokType == tkAs and kind == nkImportStmt:
+      let a = result
+      result = newNodeP(nkImportAs, p)
+      getTok(p)
+      result.add(a)
+      result.add(parseExpr(p))
+
 proc parseImport(p: var TParser, kind: TNodeKind): PNode =
   #| importStmt = 'import' optInd expr
   #|               ((comma expr)*
@@ -1095,7 +1106,7 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
   result = newNodeP(kind, p)
   getTok(p)                   # skip `import` or `export`
   optInd(p, result)
-  var a = parseExpr(p)
+  var a = parseModuleName(p, kind)
   addSon(result, a)
   if p.tok.tokType in {tkComma, tkExcept}:
     if p.tok.tokType == tkExcept:
@@ -1104,10 +1115,10 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
     optInd(p, result)
     while true:
       # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
-      a = parseExpr(p)
-      if a.kind == nkEmpty: break 
+      a = parseModuleName(p, kind)
+      if a.kind == nkEmpty: break
       addSon(result, a)
-      if p.tok.tokType != tkComma: break 
+      if p.tok.tokType != tkComma: break
       getTok(p)
       optInd(p, a)
   #expectNl(p)
@@ -1128,11 +1139,11 @@ proc parseIncludeStmt(p: var TParser): PNode =
   #expectNl(p)
 
 proc parseFromStmt(p: var TParser): PNode =
-  #| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
+  #| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
   result = newNodeP(nkFromStmt, p)
   getTok(p)                   # skip `from`
   optInd(p, result)
-  var a = parseExpr(p)
+  var a = parseModuleName(p, nkImportStmt)
   addSon(result, a)           #optInd(p, a);
   eat(p, tkImport)
   optInd(p, result)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index efa4ecaba..f6fb0f8c0 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -448,6 +448,7 @@ proc lsub(n: PNode): int =
   of nkPragma: result = lcomma(n) + 4
   of nkCommentStmt: result = len(n.comment)
   of nkOfBranch: result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("of_:_")
+  of nkImportAs: result = lsub(n.sons[0]) + len("_as_") + lsub(n.sons[1])
   of nkElifBranch: result = lsons(n) + len("elif_:_")
   of nkElse: result = lsub(n.sons[0]) + len("else:_")
   of nkFinally: result = lsub(n.sons[0]) + len("finally:_")
@@ -1191,6 +1192,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, lastSon(n), c)
+  of nkImportAs:
+    gsub(g, n.sons[0])
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkAs, "as")
+    gsub(g, n.sons[1])
   of nkBindStmt: 
     putWithSpace(g, tkBind, "bind")
     gcomma(g, n, c)