From 7d6500f1de19379cdfc9c6f8a05d43781cf32291 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 2 Aug 2012 23:14:38 +0200 Subject: idetools improvements; preparation of first class iterators; fixes #183 --- compiler/ast.nim | 4 +++- compiler/ccgstmts.nim | 21 +++++++++++++++++++++ compiler/ccgtrav.nim | 9 ++++----- compiler/ecmasgen.nim | 2 ++ compiler/importer.nim | 25 +++++++++++++------------ compiler/lambdalifting.nim | 28 +++++++++++++++++++++++++++- compiler/msgs.nim | 2 +- compiler/parser.nim | 8 +++++--- compiler/semstmts.nim | 21 ++++++++++++--------- compiler/semtypes.nim | 8 ++++++-- compiler/sigmatch.nim | 2 +- compiler/suggest.nim | 1 - 12 files changed, 95 insertions(+), 36 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index ff493e563..071318992 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -200,7 +200,9 @@ type nkEnumTy, # enum body nkEnumFieldDef, # `ident = expr` in an enumeration nkReturnToken, # token used for interpretation - nkClosure # (prc, env)-pair (internally used for code gen) + nkClosure, # (prc, env)-pair (internally used for code gen) + nkGotoState, # used for the state machine (for iterators) + nkState # give a label to a code section (for iterators) TNodeKinds* = set[TNodeKind] type diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 591dd7089..1f480f024 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -92,6 +92,25 @@ template preserveBreakIdx(body: stmt): stmt = body p.breakIdx = oldBreakIdx +proc genState(p: BProc, n: PNode) = + internalAssert n.len == 2 and n.sons[0].kind == nkIntLit + let idx = n.sons[0].intVal + lineCg(p, cpsStmts, "STATE$1: ;$n", [idx.toRope]) + genStmts(p, n.sons[1]) + +proc genGotoState(p: BProc, n: PNode) = + # we resist the temptation to translate it into duff's device as it later + # will be translated into computed gotos anyway for GCC at least: + # switch (x.state) { + # case 0: goto STATE0; + # ... + var a: TLoc + initLocExpr(p, n.sons[0], a) + lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)]) + for i in 0 .. lastOrd(n.sons[0].typ): + lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)]) + lineF(p, cpsStmts, "}$n", []) + proc genSingleVar(p: BProc, a: PNode) = var v = a.sons[0].sym if sfCompileTime in v.flags: return @@ -863,5 +882,7 @@ proc genStmts(p: BProc, t: PNode) = if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags: genProc(p.module, prc) of nkParForStmt: genParForStmt(p, t) + of nkState: genState(p, t) + of nkGotoState: genGotoState(p, t) else: internalError(t.info, "genStmts(" & $t.kind & ')') diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 1ff6346f6..5f6f14548 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -44,6 +44,8 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) = lineF(p, cpsStmts, "} $n") of nkSym: let field = n.sym + if field.loc.t == nil: + internalError(n.info, "genTraverseProc()") genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t) else: internalError(n.info, "genTraverseProc()") @@ -73,11 +75,8 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) = if typ.n != nil: genTraverseProc(c, accessor, typ.n) of tyTuple: let typ = GetUniqueType(typ) - if typ.n != nil: - genTraverseProc(c, accessor, typ.n) - else: - for i in countup(0, sonsLen(typ) - 1): - genTraverseProc(c, ropef("$1.Field$2", accessor, i.toRope), typ.sons[i]) + for i in countup(0, sonsLen(typ) - 1): + genTraverseProc(c, ropef("$1.Field$2", accessor, i.toRope), typ.sons[i]) of tyRef, tyString, tySequence: lineCg(p, cpsStmts, c.visitorFrmt, accessor) of tyProc: diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 1ae80c74c..615386a32 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -1468,6 +1468,8 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: var r2: TCompRes genSym(p, n.sons[namePos], r2) + of nkGotoState, nkState: + internalError(n.info, "first class iterators not implemented") else: genLineDir(p, n, r) gen(p, n, r) diff --git a/compiler/importer.nim b/compiler/importer.nim index 19f0574b8..24f7cb5c6 100755 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -37,7 +37,7 @@ proc checkModuleName*(n: PNode): string = var modulename = n.getModuleName result = findModule(modulename) if result.len == 0: - Fatal(n.info, errCannotOpenFile, modulename) + LocalError(n.info, errCannotOpenFile, modulename) proc rawImportSymbol(c: PContext, s: PSym) = # This does not handle stubs, because otherwise loading on demand would be @@ -109,19 +109,20 @@ proc evalImport(c: PContext, n: PNode): PNode = result = n for i in countup(0, sonsLen(n) - 1): var f = checkModuleName(n.sons[i]) - var m = gImportModule(f) - if sfDeprecated in m.flags: - 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) + if f.len > 0: + var m = gImportModule(f) + if sfDeprecated in m.flags: + 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) proc evalFrom(c: PContext, n: PNode): PNode = result = n checkMinSonsLen(n, 2) var f = checkModuleName(n.sons[0]) - var m = gImportModule(f) - 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) - + if f.len > 0: + var m = gImportModule(f) + 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) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 647daca85..aaba47c70 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -8,7 +8,6 @@ # # This include file implements lambda lifting for the transformator. -# included from transf.nim import intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, @@ -517,3 +516,30 @@ proc liftLambdas*(n: PNode): PNode = var s = n.sons[namePos].sym if gCmd == cmdCompileToEcmaScript: return s.getBody result = liftLambdas(s, s.getBody) + +proc transformIterator*(fn: PSym, body: PNode): PNode = + if body.kind == nkEmpty: + # ignore forward declaration: + result = body + # it(a, b) --> (it(a, b), createClosure()) + # it(a, b) --> ? + discard """ + let c = chain(f, g) + + for x in c: echo x + + iterator chain[S, T](a, b: *S->T, args: *S): T = + for x in a(args): yield x + for x in b(args): yield x + + # translated to: + + + + let c = chain( (f, newClosure(f)), (g, newClosure(g)), newClosure(chain)) + + +""" + + + diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 714b6f51f..eb427954a 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -344,7 +344,7 @@ const warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]", warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]", warnXisPassedToProcVar: "\'$1\' is passed to a procvar; deprecated [XisPassedToProcVar]", - warnAnalysisLoophole: "thread analysis incomplete due to unkown call '$1' [AnalysisLoophole]", + warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]", warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", warnImplicitClosure: "implicit closure convention: '$1' [ImplicitClosure]", diff --git a/compiler/parser.nim b/compiler/parser.nim index 3d8fc1f7c..f78f07325 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -275,6 +275,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) = proc dotExpr(p: var TParser, a: PNode): PNode = getTok(p) + var info = p.lex.getlineInfo optInd(p, a) case p.tok.tokType of tkType: @@ -286,7 +287,7 @@ proc dotExpr(p: var TParser, a: PNode): PNode = getTok(p) addSon(result, a) else: - result = newNodeI(nkDotExpr, a.info) + result = newNodeI(nkDotExpr, info) addSon(result, a) addSon(result, parseSymbol(p)) @@ -758,9 +759,10 @@ proc parseExpr(p: var TParser): PNode = case p.tok.tokType: of tkIf: result = parseIfExpr(p, nkIfExpr) of tkWhen: result = parseIfExpr(p, nkWhenExpr) - of tkTry: result = parseTry(p) - of tkCase: result = parseCase(p) else: result = lowestExpr(p) + # XXX needs proper support: + #of tkCase: result = parseCase(p) + #of tkTry: result = parseTry(p) proc primary(p: var TParser, skipSuffix = false): PNode = # prefix operator? diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c82e7d8de..0e882c076 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -835,13 +835,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, closeScope(c.tab) # close scope for parameters popOwner() -proc semIterator(c: PContext, n: PNode): PNode = +proc semIterator(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skIterator, iteratorPragmas) var s = result.sons[namePos].sym var t = s.typ - if t.sons[0] == nil: + if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "iterator") - if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone: + # iterators are either 'inline' or 'closure': + if s.typ.callConv != ccInline: s.typ.callConv = ccClosure + if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone: LocalError(n.info, errImplOfXexpected, s.name.s) proc semProc(c: PContext, n: PNode): PNode = @@ -894,12 +896,13 @@ proc evalInclude(c: PContext, n: PNode): PNode = addSon(result, n) for i in countup(0, sonsLen(n) - 1): var f = checkModuleName(n.sons[i]) - var fileIndex = f.fileInfoIdx - if ContainsOrIncl(c.includedFiles, fileIndex): - LocalError(n.info, errRecursiveDependencyX, f.extractFilename) - else: - addSon(result, semStmt(c, gIncludeFile(f))) - Excl(c.includedFiles, fileIndex) + if f.len > 0: + var fileIndex = f.fileInfoIdx + if ContainsOrIncl(c.includedFiles, fileIndex): + LocalError(n.info, errRecursiveDependencyX, f.extractFilename) + else: + addSon(result, semStmt(c, gIncludeFile(f))) + Excl(c.includedFiles, fileIndex) proc setLine(n: PNode, info: TLineInfo) = for i in 0 ..