closure iterators work
This commit is contained in:
parent
3f87326247
commit
d01ff8994b
4 changed files with 76 additions and 33 deletions
|
|
@ -116,7 +116,7 @@ type
|
||||||
TDep = tuple[e: PEnv, field: PSym]
|
TDep = tuple[e: PEnv, field: PSym]
|
||||||
TEnv {.final.} = object of TObject
|
TEnv {.final.} = object of TObject
|
||||||
attachedNode: PNode
|
attachedNode: PNode
|
||||||
closure: PSym # if != nil it is a used environment
|
createdVar: PSym # if != nil it is a used environment
|
||||||
capturedVars: seq[PSym] # captured variables in this environment
|
capturedVars: seq[PSym] # captured variables in this environment
|
||||||
deps: seq[TDep] # dependencies
|
deps: seq[TDep] # dependencies
|
||||||
up: PEnv
|
up: PEnv
|
||||||
|
|
@ -544,19 +544,20 @@ proc addVar*(father, v: PNode) =
|
||||||
addSon(vpart, ast.emptyNode)
|
addSon(vpart, ast.emptyNode)
|
||||||
addSon(father, vpart)
|
addSon(father, vpart)
|
||||||
|
|
||||||
proc getClosureVar(o: POuterContext, e: PEnv): PSym =
|
proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
|
||||||
if e.closure == nil:
|
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
||||||
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
incl(result.flags, sfShadowed)
|
||||||
incl(result.flags, sfShadowed)
|
result.typ = newType(tyRef, o.fn)
|
||||||
result.typ = newType(tyRef, o.fn)
|
result.typ.rawAddSon(e.tup)
|
||||||
result.typ.rawAddSon(e.tup)
|
|
||||||
e.closure = result
|
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
|
||||||
|
if e.createdVar == nil:
|
||||||
|
result = newClosureCreationVar(o, e)
|
||||||
|
e.createdVar = result
|
||||||
else:
|
else:
|
||||||
result = e.closure
|
result = e.createdVar
|
||||||
|
|
||||||
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
|
||||||
var env = getClosureVar(o, scope)
|
|
||||||
|
|
||||||
|
proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
|
||||||
result = newNodeI(nkStmtList, env.info)
|
result = newNodeI(nkStmtList, env.info)
|
||||||
var v = newNodeI(nkVarSection, env.info)
|
var v = newNodeI(nkVarSection, env.info)
|
||||||
addVar(v, newSymNode(env))
|
addVar(v, newSymNode(env))
|
||||||
|
|
@ -577,6 +578,21 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||||
# add ``env.up = env2``
|
# add ``env.up = env2``
|
||||||
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
|
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
|
||||||
newSymNode(getClosureVar(o, e)), env.info))
|
newSymNode(getClosureVar(o, e)), env.info))
|
||||||
|
|
||||||
|
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||||
|
var env = getClosureVar(o, scope)
|
||||||
|
result = rawClosureCreation(o, scope, env)
|
||||||
|
|
||||||
|
proc generateIterClosureCreation(o: POuterContext; env: PEnv;
|
||||||
|
scope: PNode): PSym =
|
||||||
|
result = newClosureCreationVar(o, env)
|
||||||
|
let cc = rawClosureCreation(o, env, result)
|
||||||
|
var insertPoint = scope.sons[0]
|
||||||
|
if insertPoint.kind == nkEmpty: scope.sons[0] = cc
|
||||||
|
else:
|
||||||
|
assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
|
||||||
|
for x in cc: insertPoint.add(x)
|
||||||
|
if env.createdVar == nil: env.createdVar = result
|
||||||
|
|
||||||
proc interestingIterVar(s: PSym): bool {.inline.} =
|
proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||||
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
||||||
|
|
@ -635,8 +651,16 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||||
|
|
||||||
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
||||||
if closure != nil:
|
if closure != nil:
|
||||||
# we need to replace the lambda with '(lambda, env)':
|
# we need to replace the lambda with '(lambda, env)':
|
||||||
let a = closure.closure
|
if local.kind == skIterator and local.typ.callConv == ccClosure:
|
||||||
|
# consider: [i1, i2, i1] Since we merged the iterator's closure
|
||||||
|
# with the captured owning variables, we need to generate the
|
||||||
|
# closure generation code again:
|
||||||
|
let createdVar = generateIterClosureCreation(o, closure,
|
||||||
|
closure.attachedNode)
|
||||||
|
return makeClosure(local, createdVar, n.info)
|
||||||
|
|
||||||
|
let a = closure.createdVar
|
||||||
if a != nil:
|
if a != nil:
|
||||||
return makeClosure(local, a, n.info)
|
return makeClosure(local, a, n.info)
|
||||||
else:
|
else:
|
||||||
|
|
@ -646,7 +670,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||||
if scope.sons[0].kind == nkEmpty:
|
if scope.sons[0].kind == nkEmpty:
|
||||||
# change the empty node to contain the closure construction:
|
# change the empty node to contain the closure construction:
|
||||||
scope.sons[0] = generateClosureCreation(o, closure)
|
scope.sons[0] = generateClosureCreation(o, closure)
|
||||||
let x = closure.closure
|
let x = closure.createdVar
|
||||||
assert x != nil
|
assert x != nil
|
||||||
return makeClosure(local, x, n.info)
|
return makeClosure(local, x, n.info)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2837,8 +2837,22 @@ The builtin ``system.finished`` can be used to determine if an iterator has
|
||||||
finished its operation; no exception is raised on an attempt to invoke an
|
finished its operation; no exception is raised on an attempt to invoke an
|
||||||
iterator that has already finished its work.
|
iterator that has already finished its work.
|
||||||
|
|
||||||
One always has to
|
Closure iterators are *resumable functions* and so one has to provide the
|
||||||
|
arguments to every call. To get around this limitation one can capture
|
||||||
|
parameters of an outer factory proc:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc mycount(a, b: int): iterator (): int =
|
||||||
|
return iterator (): int =
|
||||||
|
var x = a
|
||||||
|
while x <= b:
|
||||||
|
yield x
|
||||||
|
inc x
|
||||||
|
|
||||||
|
let foo = mycount 1, 4
|
||||||
|
|
||||||
|
for f in foo():
|
||||||
|
echo f
|
||||||
|
|
||||||
|
|
||||||
Type sections
|
Type sections
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ type
|
||||||
TButtonClicked = proc(button: PButton) {.nimcall.}
|
TButtonClicked = proc(button: PButton) {.nimcall.}
|
||||||
|
|
||||||
proc newButton*(onClick: TButtonClicked) =
|
proc newButton*(onClick: TButtonClicked) =
|
||||||
nil
|
discard
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
newButton(onClick = proc(b: PButton) =
|
newButton(onClick = proc(b: PButton) =
|
||||||
var requestomat = 12
|
var requestomat = 12
|
||||||
|
|
|
||||||
35
todo.txt
35
todo.txt
|
|
@ -1,20 +1,8 @@
|
||||||
version 0.9.4
|
version 0.9.4
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- test&finish first class iterators:
|
- better debugging support for writes to locations
|
||||||
* nested iterators
|
|
||||||
- implement strongSpaces:on
|
|
||||||
- ensure (ref T)(a, b) works as a type conversion and type constructor
|
|
||||||
- document new templating symbol binding rules
|
- document new templating symbol binding rules
|
||||||
- make '--implicitStatic:on' the default
|
|
||||||
- change comment handling in the AST
|
|
||||||
|
|
||||||
- special rule for ``[]=``
|
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``; general
|
|
||||||
lift mechanism in the compiler is already implemented for 'fields'
|
|
||||||
- built-in 'getImpl'
|
|
||||||
- optimize 'genericReset'; 'newException' leads to code bloat
|
|
||||||
- stack-less GC
|
|
||||||
- fix eval in macros.nim
|
- fix eval in macros.nim
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -37,12 +25,29 @@ Bugs
|
||||||
version 0.9.x
|
version 0.9.x
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- macros as type pragmas
|
- ensure (ref T)(a, b) works as a type conversion and type constructor
|
||||||
|
- optimize 'genericReset'; 'newException' leads to code bloat
|
||||||
|
- stack-less GC
|
||||||
|
- implement strongSpaces:on
|
||||||
|
- make '--implicitStatic:on' the default
|
||||||
- implicit deref for parameter matching
|
- implicit deref for parameter matching
|
||||||
|
|
||||||
|
- special rule for ``[]=``
|
||||||
|
- ``=`` should be overloadable; requires specialization for ``=``; general
|
||||||
|
lift mechanism in the compiler is already implemented for 'fields'
|
||||||
|
- built-in 'getImpl'
|
||||||
|
|
||||||
|
- change comment handling in the AST; that's lots of work as c2nim and pas2nim
|
||||||
|
make use of the fast every node can have a comment!
|
||||||
|
|
||||||
|
|
||||||
|
version 0.9.X
|
||||||
|
=============
|
||||||
|
|
||||||
|
- macros as type pragmas
|
||||||
- lazy overloading resolution:
|
- lazy overloading resolution:
|
||||||
* special case ``tyStmt``
|
* special case ``tyStmt``
|
||||||
- FFI:
|
- FFI:
|
||||||
* test libffi on windows
|
|
||||||
* test: times.format with the FFI
|
* test: times.format with the FFI
|
||||||
- document NimMain and check whether it works for threading
|
- document NimMain and check whether it works for threading
|
||||||
- 'quote' without 'do' doesn't work: parser/grammar issue; could be supported
|
- 'quote' without 'do' doesn't work: parser/grammar issue; could be supported
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue