diff options
-rwxr-xr-x | compiler/ast.nim | 5 | ||||
-rwxr-xr-x | compiler/ccgstmts.nim | 3 | ||||
-rwxr-xr-x | compiler/depends.nim | 2 | ||||
-rwxr-xr-x | compiler/docgen.nim | 2 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 3 | ||||
-rwxr-xr-x | compiler/importer.nim | 33 | ||||
-rwxr-xr-x | compiler/parser.nim | 102 | ||||
-rwxr-xr-x | compiler/renderer.nim | 33 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 5 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 1 | ||||
-rwxr-xr-x | doc/manual.txt | 13 | ||||
-rwxr-xr-x | lib/core/macros.nim | 8 | ||||
-rw-r--r-- | tests/compile/titerovl.nim | 21 | ||||
-rw-r--r-- | tests/reject/timportexcept.nim | 10 | ||||
-rwxr-xr-x | todo.txt | 32 |
15 files changed, 160 insertions, 113 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 77f8723e2..f4ba1ef70 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -172,10 +172,11 @@ type nkDiscardStmt, # a discard statement nkStmtList, # a list of statements nkImportStmt, # an import statement - nkFromStmt, # a from * import statement nkImportExceptStmt, # an import x except a statement - nkIncludeStmt, # an include statement nkExportStmt, # an export statement + nkExportExceptStmt, # an 'export except' statement + nkFromStmt, # a from * import statement + nkIncludeStmt, # an include statement nkBindStmt, # a bind statement nkMixinStmt, # a mixin statement nkCommentStmt, # a comment statement diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index a950c62df..089f7fb83 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -880,7 +880,8 @@ proc genStmts(p: BProc, t: PNode) = # we have to emit the type information for object types here to support # separate compilation: genTypeSection(p.module, t) - of nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt, + of nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, + nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, nkFromStmt, nkTemplateDef, nkMacroDef: nil of nkPragma: genPragma(p, t) diff --git a/compiler/depends.nim b/compiler/depends.nim index 4fde24ab4..b9d38236b 100755 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -35,7 +35,7 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): var imported = getModuleName(n.sons[i]) addDependencyAux(g.module.name.s, imported) - of nkFromStmt: + of nkFromStmt, nkImportExceptStmt: var imported = getModuleName(n.sons[0]) addDependencyAux(g.module.name.s, imported) of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 8bbc53b74..5d46be874 100755 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -273,7 +273,7 @@ proc generateDoc*(d: PDoc, n: PNode) = generateDoc(d, lastSon(n.sons[0])) of nkImportStmt: for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i]) - of nkFromStmt: traceDeps(d, n.sons[0]) + of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) else: nil proc genSection(d: PDoc, kind: TSymKind) = diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index cff4cc1dd..770e6a4a7 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -1465,7 +1465,8 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = of nkAsmStmt: genAsmStmt(p, n, r) of nkTryStmt: genTryStmt(p, n, r) of nkRaiseStmt: genRaiseStmt(p, n, r) - of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, nkImportStmt, + of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, + nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil of nkProcDef, nkMethodDef, nkConverterDef: var s = n.sons[namePos].sym diff --git a/compiler/importer.nim b/compiler/importer.nim index f96377915..b3821746c 100755 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -11,7 +11,7 @@ import intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, - semdata, passes + semdata, passes, renderer proc evalImport*(c: PContext, n: PNode): PNode proc evalFrom*(c: PContext, n: PNode): PNode @@ -29,7 +29,8 @@ proc getModuleName*(n: PNode): string = of nkSym: result = n.sym.name.s else: - internalError(n.info, "getModuleName") + localError(n.info, errGenerated, + "invalide module name: '$1'" % renderTree(n)) result = "" proc checkModuleName*(n: PNode): string = @@ -102,11 +103,23 @@ proc importAllSymbols(c: PContext, fromMod: PSym) = while s != nil: if s.kind != skModule: if s.kind != skEnumField: - if not (s.Kind in ExportableSymKinds): + 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 + 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) + if s.name.id notin exceptSet: + rawImportSymbol(c, s) + s = NextIter(i, fromMod.tab) + proc evalImport(c: PContext, n: PNode): PNode = result = n for i in countup(0, sonsLen(n) - 1): @@ -128,3 +141,17 @@ proc evalFrom(c: PContext, n: PNode): PNode = n.sons[0] = newSymNode(m) addDecl(c, m) # add symbol to symbol table of module for i in countup(1, sonsLen(n) - 1): 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.len > 0: + var m = gImportModule(f) + n.sons[0] = newSymNode(m) + addDecl(c, m) # add symbol to symbol table of module + var exceptSet = initIntSet() + for i in countup(1, sonsLen(n) - 1): + let ident = lookups.considerAcc(n.sons[i]) + exceptSet.incl(ident.id) + importAllSymbolsExcept(c, m, exceptSet) diff --git a/compiler/parser.nim b/compiler/parser.nim index 7ab87804e..bfc6b3b65 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -872,10 +872,10 @@ proc parseExprStmt(p: var TParser): PNode = getTok(p) skipComment(p, result) if p.tok.tokType == tkSad: getTok(p) - if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}): + if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}: let body = parseStmt(p) addSon(result, newProcNode(nkDo, body.info, body)) - while true: + while true: if p.tok.tokType == tkSad: getTok(p) var b: PNode case p.tok.tokType @@ -900,33 +900,34 @@ proc parseExprStmt(p: var TParser): PNode = addSon(b, parseStmt(p)) addSon(result, b) if b.kind == nkElse: break - -proc parseModuleName(p: var TParser): PNode {.inline.} = - result = parseExpr(p) -proc parseImportOrIncludeStmt(p: var TParser, kind: TNodeKind): PNode = - var a: PNode +proc parseImport(p: var TParser, kind: TNodeKind): PNode = result = newNodeP(kind, p) - getTok(p) # skip `import` or `include` + getTok(p) # skip `import` or `export` optInd(p, result) - while true: - case p.tok.tokType - of tkEof, tkSad, tkDed: - break - of tkSymbol, tkAccent: - a = parseSymbol(p) - of tkRStrLit: - a = newStrNodeP(nkRStrLit, p.tok.literal, p) - getTok(p) - of tkStrLit: - a = newStrNodeP(nkStrLit, p.tok.literal, p) - getTok(p) - of tkTripleStrLit: - a = newStrNodeP(nkTripleStrLit, p.tok.literal, p) + var a = parseExpr(p) + addSon(result, a) + if p.tok.tokType in {tkComma, tkExcept}: + if p.tok.tokType == tkExcept: + result.kind = succ(kind) + getTok(p) + optInd(p, result) + while p.tok.tokType notin {tkEof, tkSad, tkDed}: + a = parseExpr(p) + if a.kind == nkEmpty: break + addSon(result, a) + if p.tok.tokType != tkComma: break getTok(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - break + optInd(p, a) + expectNl(p) + +proc parseIncludeStmt(p: var TParser): PNode = + result = newNodeP(nkIncludeStmt, p) + getTok(p) # skip `import` or `include` + optInd(p, result) + while p.tok.tokType notin {tkEof, tkSad, tkDed}: + var a = parseExpr(p) + if a.kind == nkEmpty: break addSon(result, a) if p.tok.tokType != tkComma: break getTok(p) @@ -937,19 +938,13 @@ proc parseFromStmt(p: var TParser): PNode = result = newNodeP(nkFromStmt, p) getTok(p) # skip `from` optInd(p, result) - var a = parseModuleName(p) + var a = parseExpr(p) addSon(result, a) #optInd(p, a); eat(p, tkImport) optInd(p, result) - while true: - case p.tok.tokType #optInd(p, a); - of tkEof, tkSad, tkDed: - break - of tkSymbol, tkAccent: - a = parseSymbol(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - break + while p.tok.tokType notin {tkEof, tkSad, tkDed}: + a = parseExpr(p) + if a.kind == nkEmpty: break addSon(result, a) if p.tok.tokType != tkComma: break getTok(p) @@ -1264,14 +1259,7 @@ proc parseEnum(p: var TParser): PNode = result = newNodeP(nkEnumTy, p) a = nil getTok(p) - if false and p.tok.tokType == tkOf: - a = newNodeP(nkOfInherit, p) - getTok(p) - optInd(p, a) - addSon(a, parseTypeDesc(p)) - addSon(result, a) - else: - addSon(result, ast.emptyNode) + addSon(result, ast.emptyNode) optInd(p, result) while true: case p.tok.tokType @@ -1410,18 +1398,6 @@ proc parseDistinct(p: var TParser): PNode = optInd(p, result) addSon(result, parseTypeDesc(p)) -proc parsePointerInTypeSection(p: var TParser, kind: TNodeKind): PNode = - result = newNodeP(kind, p) - getTok(p) - optInd(p, result) - if not isOperator(p.tok): - case p.tok.tokType - of tkObject: addSon(result, parseObject(p)) - of tkTuple: addSon(result, parseTuple(p, true)) - else: - if isExprStart(p): - addSon(result, parseTypeDesc(p)) - proc parseTypeDef(p: var TParser): PNode = result = newNodeP(nkTypeDef, p) addSon(result, identWithPragma(p)) @@ -1430,15 +1406,6 @@ proc parseTypeDef(p: var TParser): PNode = if p.tok.tokType == tkEquals: getTok(p) optInd(p, result) - #var a: PNode - #case p.tok.tokType - #of tkObject: a = parseObject(p) - #of tkEnum: a = parseEnum(p) - #of tkDistinct: a = parseDistinct(p) - #of tkTuple: a = parseTuple(p, true) - #of tkRef: a = parsePointerInTypeSection(p, nkRefTy) - #of tkPtr: a = parsePointerInTypeSection(p, nkPtrTy) - #else: a = parseTypeDesc(p) addSon(result, parseTypeDefAux(p)) else: addSon(result, ast.emptyNode) @@ -1496,11 +1463,12 @@ proc simpleStmt(p: var TParser): PNode = of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt) of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt) of tkCurlyDotLe: result = parseStmtPragma(p) - of tkImport: result = parseImportOrIncludeStmt(p, nkImportStmt) + of tkImport: result = parseImport(p, nkImportStmt) + of tkExport: result = parseImport(p, nkExportStmt) of tkFrom: result = parseFromStmt(p) - of tkInclude: result = parseImportOrIncludeStmt(p, nkIncludeStmt) + of tkInclude: result = parseIncludeStmt(p) of tkComment: result = newCommentStmt(p) - else: + else: if isExprStart(p): result = parseExprStmt(p) else: result = ast.emptyNode if result.kind != nkEmpty: skipComment(p, result) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 4444f2ab0..c8ee66e03 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1134,13 +1134,27 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkCurlyDotLe, "{.") gcomma(g, n, emptyContext) put(g, tkCurlyDotRi, ".}") - of nkImportStmt: - putWithSpace(g, tkImport, "import") + of nkImportStmt, nkExportStmt: + if n.kind == nkImportStmt: + putWithSpace(g, tkImport, "import") + else: + putWithSpace(g, tkExport, "export") gcoms(g) indentNL(g) gcommaAux(g, n, g.indent) dedent(g) putNL(g) + of nkImportExceptStmt, nkExportExceptStmt: + if n.kind == nkImportExceptStmt: + putWithSpace(g, tkImport, "import") + else: + putWithSpace(g, tkExport, "export") + gsub(g, n.sons[0]) + put(g, tkSpaces, Space) + putWithSpace(g, tkExcept, "except") + gcommaAux(g, n, g.indent, 1) + gcoms(g) + putNL(g) of nkFromStmt: putWithSpace(g, tkFrom, "from") gsub(g, n.sons[0]) @@ -1148,14 +1162,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = putWithSpace(g, tkImport, "import") gcomma(g, n, emptyContext, 1) putNL(g) - of nkImportExceptStmt: - putWithSpace(g, tkImport, "import") - gsub(g, n.sons[0]) - put(g, tkSpaces, Space) - putWithSpace(g, tkExcept, "except") - gcommaAux(g, n, g.indent, 1) - gcoms(g) - putNL(g) of nkIncludeStmt: putWithSpace(g, tkInclude, "include") gcoms(g) @@ -1163,13 +1169,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gcommaAux(g, n, g.indent) dedent(g) putNL(g) - of nkExportStmt: - putWithSpace(g, tkExport, "export") - gcoms(g) - indentNL(g) - gcommaAux(g, n, g.indent) - dedent(g) - putNL(g) of nkCommentStmt: gcoms(g) optNL(g) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cf0e8f4dd..c5e3fdc1e 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -594,7 +594,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, # to 'skIterator' anymore; skIterator is preferred in sigmatch already for # typeof support. # for ``type(countup(1,3))``, see ``tests/ttoseq``. - result = semOverloadedCall(c, n, nOrig, + result = semOverloadedCall(c, n, nOrig, {skProc, skMethod, skConverter, skMacro, skTemplate, skIterator}) else: result = semOverloadedCall(c, n, nOrig, @@ -1852,6 +1852,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkImportStmt: if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "import") result = evalImport(c, n) + of nkImportExceptStmt: + if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "import") + result = evalImportExcept(c, n) of nkFromStmt: if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "from") result = evalFrom(c, n) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f644683f5..9efeba5b7 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -825,6 +825,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = checkSonsLen(n, 3) result = semTypeNode(c, n.sons[1], prev) if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: + # XXX this is wrong for tyString at least result.flags.incl(tfNotNil) else: LocalError(n.info, errGenerated, "invalid type") diff --git a/doc/manual.txt b/doc/manual.txt index f6ff576bf..a5bce775b 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -3741,6 +3741,19 @@ This is best illustrated by an example: return x + 1 +Import statement +~~~~~~~~~~~~~~~~ + +After the import statement a list of module names can follow or a single +module name followed by an ``except`` to prevent some symbols to be imported: + +.. code-block:: nimrod + import strutils except `%` + + # doesn't work then: + echo "$1" % "abc" + + Scope rules ----------- Identifiers are valid from the point of their declaration until the end of diff --git a/lib/core/macros.nim b/lib/core/macros.nim index d2d842025..bf7510a92 100755 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -47,10 +47,12 @@ type nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt, nnkDiscardStmt, nnkStmtList, - nnkImportStmt, nnkFromStmt, - nkImportExceptStmt, - nnkIncludeStmt, + nnkImportStmt, + nnkImportExceptStmt, nnkExportStmt, + nnkExportExceptStmt, + nnkFromStmt, + nnkIncludeStmt, nnkBindStmt, nnkMixinStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, diff --git a/tests/compile/titerovl.nim b/tests/compile/titerovl.nim new file mode 100644 index 000000000..be665b2b7 --- /dev/null +++ b/tests/compile/titerovl.nim @@ -0,0 +1,21 @@ +discard """ + output: '''9 +1 +2 +3 +''' +""" + +# Test the new overloading rules for iterators: + +# test that iterator 'p' is preferred: +proc p(): seq[int] = @[1, 2, 3] +iterator p(): int = yield 9 + +for x in p(): echo x + +# test that 'q' works in this position: +proc q(): seq[int] = @[1, 2, 3] + +for x in q(): echo x + diff --git a/tests/reject/timportexcept.nim b/tests/reject/timportexcept.nim new file mode 100644 index 000000000..93a7fd642 --- /dev/null +++ b/tests/reject/timportexcept.nim @@ -0,0 +1,10 @@ +discard """ + line: 9 + errormsg: "undeclared identifier: '%'" +""" + +import strutils except `%` + +# doesn't work +echo "$1" % "abc" + diff --git a/todo.txt b/todo.txt index 79b3cb529..804f6e5f6 100755 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,7 @@ version 0.9.2 ============= -- 'export' feature; from buggymodule import * except optBroken, optBroken2 +- 'export' feature - test&finish first class iterators: * nested iterators * test generic iterators @@ -53,35 +53,27 @@ Concurrency - use the effect system to for static deadlock prevention -GC -== - -- precise stack marking; embrace C++ code generation for that -- marker procs for Boehm GC -- implement 'mixed' GC mode - - version 0.9.XX ============== -- implement the "snoopResult" pragma; no, make a strutils with string append - semantics instead ... -- implement "closure tuple consists of a single 'ref'" optimization - object branch transitions can't work with the current 'reset'; add a 'reset' with an additional parameter --> re-evaluate this issue after constructors have been added -- allow implicit forward declarations of procs via a pragma (so that the - wrappers can deactivate it) - fix destructors; don't work yet when used as expression - document nimdoc properly finally - make 'clamp' a magic for the range stuff -- 'const' objects including case objects -- mocking support with ``tyProxy`` that does: fallback for ``.`` operator Not essential for 1.0.0 ======================= +- 'const' objects including case objects +- mocking support with ``tyProxy`` that does: fallback for ``.`` operator +- allow implicit forward declarations of procs via a pragma (so that the + wrappers can deactivate it) +- implement the "snoopResult" pragma; no, make a strutils with string append + semantics instead ... +- implement "closure tuple consists of a single 'ref'" optimization - optimize method dispatchers - ``with proc `+`(x, y: T): T`` for generic code - new feature: ``distinct T with operations`` @@ -94,6 +86,14 @@ Not essential for 1.0.0 - implement closures that support nesting of *procs* > 1 +GC +== + +- precise stack marking; embrace C++ code generation for that +- marker procs for Boehm GC +- implement 'mixed' GC mode + + Optimizations ============= |