implemented 'import a as b'

This commit is contained in:
Araq
2013-09-24 09:36:31 +02:00
parent 367abca382
commit 83584bf889
4 changed files with 84 additions and 25 deletions

View File

@@ -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 =

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)