mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-27 01:34:02 +00:00
closure iterators work
This commit is contained in:
@@ -116,7 +116,7 @@ type
|
||||
TDep = tuple[e: PEnv, field: PSym]
|
||||
TEnv {.final.} = object of TObject
|
||||
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
|
||||
deps: seq[TDep] # dependencies
|
||||
up: PEnv
|
||||
@@ -544,19 +544,20 @@ proc addVar*(father, v: PNode) =
|
||||
addSon(vpart, ast.emptyNode)
|
||||
addSon(father, vpart)
|
||||
|
||||
proc getClosureVar(o: POuterContext, e: PEnv): PSym =
|
||||
if e.closure == nil:
|
||||
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
||||
incl(result.flags, sfShadowed)
|
||||
result.typ = newType(tyRef, o.fn)
|
||||
result.typ.rawAddSon(e.tup)
|
||||
e.closure = result
|
||||
proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
|
||||
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
||||
incl(result.flags, sfShadowed)
|
||||
result.typ = newType(tyRef, o.fn)
|
||||
result.typ.rawAddSon(e.tup)
|
||||
|
||||
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
|
||||
if e.createdVar == nil:
|
||||
result = newClosureCreationVar(o, e)
|
||||
e.createdVar = result
|
||||
else:
|
||||
result = e.closure
|
||||
|
||||
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||
var env = getClosureVar(o, scope)
|
||||
result = e.createdVar
|
||||
|
||||
proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
|
||||
result = newNodeI(nkStmtList, env.info)
|
||||
var v = newNodeI(nkVarSection, env.info)
|
||||
addVar(v, newSymNode(env))
|
||||
@@ -577,6 +578,21 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||
# add ``env.up = env2``
|
||||
result.add(newAsgnStmt(indirectAccess(env, field, 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.} =
|
||||
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))
|
||||
if closure != nil:
|
||||
# we need to replace the lambda with '(lambda, env)':
|
||||
let a = closure.closure
|
||||
# we need to replace the lambda with '(lambda, env)':
|
||||
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:
|
||||
return makeClosure(local, a, n.info)
|
||||
else:
|
||||
@@ -646,7 +670,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||
if scope.sons[0].kind == nkEmpty:
|
||||
# change the empty node to contain the closure construction:
|
||||
scope.sons[0] = generateClosureCreation(o, closure)
|
||||
let x = closure.closure
|
||||
let x = closure.createdVar
|
||||
assert x != nil
|
||||
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
|
||||
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
|
||||
|
||||
@@ -4,8 +4,8 @@ type
|
||||
TButtonClicked = proc(button: PButton) {.nimcall.}
|
||||
|
||||
proc newButton*(onClick: TButtonClicked) =
|
||||
nil
|
||||
|
||||
discard
|
||||
|
||||
proc main() =
|
||||
newButton(onClick = proc(b: PButton) =
|
||||
var requestomat = 12
|
||||
|
||||
35
todo.txt
35
todo.txt
@@ -1,20 +1,8 @@
|
||||
version 0.9.4
|
||||
=============
|
||||
|
||||
- test&finish first class iterators:
|
||||
* nested iterators
|
||||
- implement strongSpaces:on
|
||||
- ensure (ref T)(a, b) works as a type conversion and type constructor
|
||||
- better debugging support for writes to locations
|
||||
- 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
|
||||
|
||||
|
||||
@@ -37,12 +25,29 @@ Bugs
|
||||
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
|
||||
|
||||
- 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:
|
||||
* special case ``tyStmt``
|
||||
- FFI:
|
||||
* test libffi on windows
|
||||
* test: times.format with the FFI
|
||||
- document NimMain and check whether it works for threading
|
||||
- 'quote' without 'do' doesn't work: parser/grammar issue; could be supported
|
||||
|
||||
Reference in New Issue
Block a user