next steps for first class iterators
This commit is contained in:
parent
1fada12a5f
commit
7a2c11d3cf
6 changed files with 75 additions and 16 deletions
|
|
@ -114,13 +114,15 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||||
|
|
||||||
proc genBreakState(p: BProc, n: PNode) =
|
proc genBreakState(p: BProc, n: PNode) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, n.sons[0], a)
|
|
||||||
if n.sons[0].kind == nkClosure:
|
if n.sons[0].kind == nkClosure:
|
||||||
# XXX this produces quite inefficient code!
|
# 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:
|
# 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)])
|
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) =
|
proc genSingleVar(p: BProc, a: PNode) =
|
||||||
var v = a.sons[0].sym
|
var v = a.sons[0].sym
|
||||||
|
|
|
||||||
|
|
@ -692,6 +692,28 @@ proc liftIterator*(iter: PSym, body: PNode): PNode =
|
||||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||||
result.add(stateAsgnStmt)
|
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 =
|
proc liftForLoop*(body: PNode): PNode =
|
||||||
# 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:
|
# we don't know what environment to create here:
|
||||||
|
|
@ -763,10 +785,10 @@ proc liftForLoop*(body: PNode): PNode =
|
||||||
|
|
||||||
loopBody.sons[0] = v2
|
loopBody.sons[0] = v2
|
||||||
var bs = newNodeI(nkBreakState, body.info)
|
var bs = newNodeI(nkBreakState, body.info)
|
||||||
if not env.isNil:
|
#if not env.isNil:
|
||||||
bs.addSon(indirectAccess(env,
|
# bs.addSon(indirectAccess(env,
|
||||||
newSym(skField, getIdent":state", env, env.info), body.info))
|
# newSym(skField, getIdent":state", env, env.info), body.info))
|
||||||
else:
|
#else:
|
||||||
bs.addSon(call.sons[0])
|
bs.addSon(call.sons[0])
|
||||||
loopBody.sons[1] = bs
|
loopBody.sons[1] = bs
|
||||||
loopBody.sons[2] = body[L-1]
|
loopBody.sons[2] = body[L-1]
|
||||||
|
|
|
||||||
|
|
@ -406,7 +406,10 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
||||||
var call = n.sons[length-2]
|
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:
|
call.sons[0].sym.kind != skIterator:
|
||||||
if length == 3:
|
if length == 3:
|
||||||
n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
|
n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,8 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
||||||
result[1] = ri
|
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 b: PNode
|
||||||
var tc = c.transCon
|
var tc = c.transCon
|
||||||
if sfBorrow in n.sym.flags:
|
if sfBorrow in n.sym.flags:
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,18 @@ discard """
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
3
|
3
|
||||||
ta da1
|
ta da1 1
|
||||||
2
|
1 2
|
||||||
3'''
|
1 3
|
||||||
|
2 1
|
||||||
|
2 2
|
||||||
|
2 3
|
||||||
|
3 1
|
||||||
|
3 2
|
||||||
|
3 3
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2'''
|
||||||
"""
|
"""
|
||||||
# Test first class iterator:
|
# Test first class iterator:
|
||||||
|
|
||||||
|
|
@ -44,8 +53,27 @@ proc inProc() =
|
||||||
stdout.write(word)
|
stdout.write(word)
|
||||||
|
|
||||||
for c in count3():
|
for c in count3():
|
||||||
echo c
|
for d in count3():
|
||||||
|
echo c, " ", d
|
||||||
|
|
||||||
|
|
||||||
inProc()
|
inProc()
|
||||||
|
|
||||||
|
iterator count0(): int {.closure.} =
|
||||||
|
# note: doesn't require anything in its closure (except 'state')
|
||||||
|
yield 0
|
||||||
|
|
||||||
|
iterator count2(): int {.closure.} =
|
||||||
|
# note: requires 'x' in its closure
|
||||||
|
var x = 1
|
||||||
|
yield x
|
||||||
|
inc x
|
||||||
|
yield x
|
||||||
|
|
||||||
|
# a first class iterator has the type 'proc {.closure.}', but maybe
|
||||||
|
# it shouldn't:
|
||||||
|
proc invoke(iter: proc(): int {.closure.}) =
|
||||||
|
for x in iter(): echo x
|
||||||
|
|
||||||
|
invoke(count0)
|
||||||
|
invoke(count2)
|
||||||
|
|
|
||||||
6
todo.txt
6
todo.txt
|
|
@ -53,7 +53,8 @@ version 0.9.XX
|
||||||
- JS gen:
|
- JS gen:
|
||||||
- fix exception handling
|
- fix exception handling
|
||||||
- object branch transitions can't work with the current 'reset'; add a 'reset'
|
- object branch transitions can't work with the current 'reset'; add a 'reset'
|
||||||
with an additional parameter
|
with an additional parameter --> re-evaluate this issue after constructors
|
||||||
|
have been added
|
||||||
- fix remaining closure bugs:
|
- fix remaining closure bugs:
|
||||||
- test evals.nim with closures
|
- test evals.nim with closures
|
||||||
- what about macros with closures?
|
- what about macros with closures?
|
||||||
|
|
@ -143,7 +144,8 @@ Version 2 and beyond
|
||||||
troublesome, but maybe we can come up with a simple heuristic. (All procs
|
troublesome, but maybe we can come up with a simple heuristic. (All procs
|
||||||
that `new` shared memory are syncGC() candidates...)
|
that `new` shared memory are syncGC() candidates...)
|
||||||
|
|
||||||
- const ptr/ref
|
- const ptr/ref --> pointless because of aliasing;
|
||||||
|
much better: 'writes: []' effect
|
||||||
|
|
||||||
- language change: inheritance should only work with reference types, so that
|
- language change: inheritance should only work with reference types, so that
|
||||||
the ``type`` field is not needed for objects! --> zero overhead aggregation
|
the ``type`` field is not needed for objects! --> zero overhead aggregation
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue