improvements for first class iterators

This commit is contained in:
Araq
2012-11-15 08:45:16 +01:00
parent e4211230e8
commit 1fada12a5f
3 changed files with 35 additions and 6 deletions

View File

@@ -115,7 +115,12 @@ proc genGotoState(p: BProc, n: PNode) =
proc genBreakState(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
if n.sons[0].kind == nkClosure:
# XXX this produces quite inefficient code!
# the environment is guaranteed to contain the 'state' field at offset 0:
lineF(p, cpsStmts, "if ((((NI*) $1.ClEnv)[0]) < 0) break;$n", [rdLoc(a)])
else:
lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
proc genSingleVar(p: BProc, a: PNode) =
var v = a.sons[0].sym

View File

@@ -693,7 +693,7 @@ proc liftIterator*(iter: PSym, body: PNode): PNode =
result.add(stateAsgnStmt)
proc liftForLoop*(body: PNode): PNode =
# BIG problem ahead: the iterator could be invoked indirectly, but then
# problem ahead: the iterator could be invoked indirectly, but then
# we don't know what environment to create here:
#
# iterator count(): int =
@@ -750,7 +750,10 @@ proc liftForLoop*(body: PNode): PNode =
# gather vars in a tuple:
var v2 = newNodeI(nkLetSection, body.info)
var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info)
for i in 0 .. L-3: addSon(vpart, body[i])
for i in 0 .. L-3:
assert body[i].kind == nkSym
body[i].sym.kind = skLet
addSon(vpart, body[i])
addSon(vpart, ast.emptyNode) # no explicit type
if not env.isnil:
@@ -760,7 +763,10 @@ proc liftForLoop*(body: PNode): PNode =
loopBody.sons[0] = v2
var bs = newNodeI(nkBreakState, body.info)
bs.addSon(indirectAccess(env,
newSym(skField, getIdent(":state"), env, env.info), body.info))
if not env.isNil:
bs.addSon(indirectAccess(env,
newSym(skField, getIdent":state", env, env.info), body.info))
else:
bs.addSon(call.sons[0])
loopBody.sons[1] = bs
loopBody.sons[2] = body[L-1]

View File

@@ -1,6 +1,11 @@
discard """
output: '''tada
ta da'''
1
2
3
ta da1
2
3'''
"""
# Test first class iterator:
@@ -21,13 +26,26 @@ iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[
yield (substr(s, i, j-1), false)
i = j
iterator count3(): int {.closure.} =
yield 1
yield 2
yield 3
for word, isSep in tokenize2("ta da", whiteSpace):
if not isSep:
stdout.write(word)
echo ""
proc inProc() =
for c in count3():
echo c
for word, isSep in tokenize2("ta da", whiteSpace):
stdout.write(word)
for c in count3():
echo c
inProc()