next steps for first class iterators

This commit is contained in:
Araq 2012-11-15 22:54:06 +01:00
commit 7a2c11d3cf
6 changed files with 75 additions and 16 deletions

View file

@ -114,13 +114,15 @@ proc genGotoState(p: BProc, n: PNode) =
proc genBreakState(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
if n.sons[0].kind == nkClosure:
# XXX this produces quite inefficient code!
initLocExpr(p, n.sons[0].sons[1], a)
lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)])
else:
initLocExpr(p, n.sons[0], a)
# 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)])
# lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
proc genSingleVar(p: BProc, a: PNode) =
var v = a.sons[0].sym

View file

@ -692,6 +692,28 @@ 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)
let iter = n.sym
assert iter.kind == skIterator
var env = copySym(getHiddenParam(iter))
env.kind = skLet
var v = newNodeI(nkVarSection, n.info)
addVar(v, newSymNode(env))
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env))
result.add makeClosure(iter, env, n.info)
proc liftForLoop*(body: PNode): PNode =
# problem ahead: the iterator could be invoked indirectly, but then
# we don't know what environment to create here:
@ -763,10 +785,10 @@ proc liftForLoop*(body: PNode): PNode =
loopBody.sons[0] = v2
var bs = newNodeI(nkBreakState, 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])
#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

@ -406,7 +406,10 @@ proc semFor(c: PContext, n: PNode): PNode =
openScope(c.tab)
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
var call = n.sons[length-2]
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
if call.kind in nkCallKinds and call.sons[0].typ.callConv == ccClosure:
# first class iterator:
result = semForVars(c, n)
elif call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
call.sons[0].sym.kind != skIterator:
if length == 3:
n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])

View file

@ -112,7 +112,9 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
result[0] = PTransNode(le)
result[1] = ri
proc transformSymAux(c: PTransf, n: PNode): PNode =
proc transformSymAux(c: PTransf, n: PNode): PNode =
if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure:
return liftIterSym(n)
var b: PNode
var tc = c.transCon
if sfBorrow in n.sym.flags: