From 7f6633a06feeac8d6bd1eb1e6d8e841591326618 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 17 Nov 2012 01:25:32 +0100 Subject: [PATCH] added system.finished for first class iterators --- compiler/ast.nim | 2 +- compiler/lambdalifting.nim | 7 ------- compiler/parser.nim | 2 +- compiler/semexprs.nim | 2 ++ compiler/semstmts.nim | 2 +- lib/system.nim | 6 ++++++ tests/run/titer8.nim | 40 +++++++++++++++++++++++++++++++++++++- todo.txt | 6 +++++- 8 files changed, 55 insertions(+), 12 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 46cb792b5..cdca68c20 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -344,7 +344,7 @@ type nfSem # node has been checked for semantics TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 15 for efficiency reasons (now: 14) + TTypeFlag* = enum # keep below 17 for efficiency reasons (now: 16) tfVarargs, # procedure has C styled varargs tfNoSideEffect, # procedure type does not allow side effects tfFinal, # is the object final? diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index dc51d2d22..c0098fb17 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -692,13 +692,6 @@ proc liftIterator*(iter: PSym, body: PNode): PNode = stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt))) result.add(stateAsgnStmt) -# TODO: -# - nested iterators -# - arglist as a type -# - tyIterator everywhere -# - 'finished' builtin -# - 'start' builtin (XXX copy Lua's terminology?) - proc liftIterSym*(n: PNode): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) result = newNodeIT(nkStmtListExpr, n.info, n.typ) diff --git a/compiler/parser.nim b/compiler/parser.nim index 347c12b13..680279bcf 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1473,7 +1473,7 @@ proc simpleStmt(p: var TParser): PNode = case p.tok.tokType of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt) of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt) - of tkYield: result = parseYieldOrDiscard(p, nkYieldStmt) + of tkYield: result = parseReturnOrRaise(p, nkYieldStmt) of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt) of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt) of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a047fed20..910100e92 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1173,6 +1173,8 @@ proc SemYield(c: PContext, n: PNode): PNode = SemYieldVarResult(c, n, restype) else: localError(n.info, errCannotReturnExpr) + elif c.p.owner.typ.sons[0] != nil: + localError(n.info, errGenerated, "yield statement must yield a value") proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = if onlyCurrentScope: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 18588fb49..b0cef2df7 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -818,7 +818,7 @@ 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 and s.typ.callConv != ccClosure: LocalError(n.info, errXNeedsReturnType, "iterator") # iterators are either 'inline' or 'closure'; for backwards compatibility, # we require first class iterators to be marked with 'closure' explicitly diff --git a/lib/system.nim b/lib/system.nim index b681ed51e..6d7720aa7 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -2096,6 +2096,12 @@ when not defined(EcmaScript) and not defined(NimrodVM): `result` = `x`.ClEnv; """.} + proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = + ## can be used to determine if a first class iterator has finished. + {.emit: """ + `result` = *((NI*) `x`.ClEnv) < 0; + """.} + elif defined(ecmaScript) or defined(NimrodVM): # Stubs: proc GC_disable() = nil diff --git a/tests/run/titer8.nim b/tests/run/titer8.nim index e0de6a6b0..34067c414 100644 --- a/tests/run/titer8.nim +++ b/tests/run/titer8.nim @@ -14,7 +14,14 @@ ta da1 1 3 3 0 1 -2''' +2 +a1: A +a2: A +a1: B +a2: B +a1: C +a2: C +a1: D''' """ # Test first class iterator: @@ -77,3 +84,34 @@ proc invoke(iter: proc(): int {.closure.}) = invoke(count0) invoke(count2) + + +# simple tasking: +type + TTask = proc (ticker: int) {.closure.} + +iterator a1(ticker: int) {.closure.} = + echo "a1: A" + yield + echo "a1: B" + yield + echo "a1: C" + yield + echo "a1: D" + +iterator a2(ticker: int) {.closure.} = + echo "a2: A" + yield + echo "a2: B" + yield + echo "a2: C" + +proc runTasks(t: varargs[TTask]) = + var ticker = 0 + while true: + let x = t[ticker mod t.len] + if finished(x): break + x(ticker) + inc ticker + +runTasks(a1, a2) diff --git a/todo.txt b/todo.txt index 8fd7ec6bc..e17993331 100755 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,11 @@ version 0.9.2 ============= -- test&finish first class iterators +- test&finish first class iterators: + * nested iterators + * arglist as a type? + * tyIterator? + - fix closure bug finally - overloading based on ASTs: 'constraint' should not be in PType but for the parameter *symbol*