added system.finished for first class iterators

This commit is contained in:
Araq
2012-11-17 01:25:32 +01:00
parent 7a2c11d3cf
commit 7f6633a06f
8 changed files with 55 additions and 12 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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