'return' for first class iterators

This commit is contained in:
Araq
2012-11-26 08:47:57 +01:00
parent dd9ad9e497
commit 2591ac0ada
6 changed files with 80 additions and 21 deletions

View File

@@ -594,9 +594,11 @@ type
tup: PType
proc newIterResult(iter: PSym): PSym =
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
result = iter.ast.sons[resultPos].sym
when false:
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
proc interestingIterVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
@@ -636,6 +638,13 @@ proc transfIterBody(c: var TIterContext, n: PNode): PNode =
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
of nkReturnStmt:
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
result.add(n)
else:
for i in countup(0, sonsLen(n)-1):
let x = transfIterBody(c, n.sons[i])

View File

@@ -1098,23 +1098,25 @@ proc semAsgn(c: PContext, n: PNode): PNode =
asgnToResultVar(c, n, n.sons[0], n.sons[1])
result = n
proc SemReturn(c: PContext, n: PNode): PNode =
proc SemReturn(c: PContext, n: PNode): PNode =
result = n
checkSonsLen(n, 1)
if c.p.owner.kind notin {skConverter, skMethod, skProc, skMacro}:
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or
(c.p.owner.kind == skIterator and c.p.owner.typ.callConv == ccClosure):
if n.sons[0].kind != nkEmpty:
# transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil:
var a = newNodeI(nkAsgn, n.sons[0].info)
addSon(a, newSymNode(c.p.resultSym))
addSon(a, n.sons[0])
n.sons[0] = semAsgn(c, a)
# optimize away ``result = result``:
if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
n.sons[0] = ast.emptyNode
else:
LocalError(n.info, errNoReturnTypeDeclared)
else:
LocalError(n.info, errXNotAllowedHere, "\'return\'")
elif n.sons[0].kind != nkEmpty:
# transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil:
var a = newNodeI(nkAsgn, n.sons[0].info)
addSon(a, newSymNode(c.p.resultSym))
addSon(a, n.sons[0])
n.sons[0] = semAsgn(c, a)
# optimize away ``result = result``:
if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
n.sons[0] = ast.emptyNode
else:
LocalError(n.info, errNoReturnTypeDeclared)
proc semProcBody(c: PContext, n: PNode): PNode =
openScope(c.tab)

View File

@@ -792,7 +792,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if n.sons[genericParamsPos].kind == nkEmpty:
ParamsTypeCheck(c, s.typ)
pushProcCon(c, s)
if s.typ.sons[0] != nil and kind != skIterator:
if s.typ.sons[0] != nil and
(kind != skIterator or s.typ.callConv == ccClosure):
addResult(c, s.typ.sons[0], n.info, kind)
addResultNode(c, n)
if sfImportc notin s.flags:

View File

@@ -1199,6 +1199,31 @@ details like this when mixing garbage collected data with unmanaged memory.
.. XXX finalizers for traced objects
Not nil annotation
~~~~~~~~~~~~~~~~~~
All types for that ``nil`` is a valid value can be annotated to
exclude ``nil`` as a valid value with the `not nil`:idx: annotation:
.. code-block:: nimrod
type
PObject = ref TObj not nil
TProc = (proc (x, y: int)) not nil
proc p(x: PObject) =
echo "not nil"
# compiler catches this:
p(nil)
# but not this:
var x: PObject
p(x)
As shown in the example this is merely an annotation for documentation purposes;
for now the compiler can only catch the most trivial type violations.
Procedural type
~~~~~~~~~~~~~~~
A `procedural type`:idx: is internally a pointer to a procedure. ``nil`` is

20
tests/run/titer9.nim Normal file
View File

@@ -0,0 +1,20 @@
discard """
output: '''5
14
0'''
"""
iterator count(x: int, skip: bool): int {.closure.} =
if skip: return x+10
else: yield x+1
if skip: return x+10
else: yield x+2
proc takeProc(x: iterator (x: int, skip: bool): int) =
echo x(4, false)
echo x(4, true)
echo x(4, false)
takeProc(count)

View File

@@ -2,7 +2,6 @@ version 0.9.2
=============
- test&finish first class iterators:
* allow return in first class iterators
* nested iterators
* arglist as a type?
@@ -17,7 +16,7 @@ version 0.9.2
- improve the compiler as a service
- ``=`` should be overloadable; requires specialization for ``=``
- implement constructors and non-nil types
- implement constructors
- make 'bind' default for templates and introduce 'mixin';
special rule for ``[]=``
- implicit deref for parameter matching; overloading based on 'var T'
@@ -38,6 +37,7 @@ Bugs
version 0.9.XX
==============
- improve not-nil types
- make:
p(a, b):
echo a
@@ -144,7 +144,9 @@ Version 2 and beyond
(or implicit) syncGC() calls in loops. Automatic loop injection seems
troublesome, but maybe we can come up with a simple heuristic. (All procs
that `new` shared memory are syncGC() candidates... But then 'new' itself
calls syncGC() so that's pointless.)
calls syncGC() so that's pointless.) Hm instead of an heuristic simply
provide a ``syncgc`` pragma to trigger compiler injection --> more general:
an ``injectLoop`` pragma
- const ptr/ref --> pointless because of aliasing;
much better: 'writes: []' effect