'return' for first class iterators
This commit is contained in:
parent
dd9ad9e497
commit
2591ac0ada
6 changed files with 80 additions and 21 deletions
|
|
@ -594,9 +594,11 @@ type
|
||||||
tup: PType
|
tup: PType
|
||||||
|
|
||||||
proc newIterResult(iter: PSym): PSym =
|
proc newIterResult(iter: PSym): PSym =
|
||||||
result = newSym(skResult, getIdent":result", iter, iter.info)
|
result = iter.ast.sons[resultPos].sym
|
||||||
result.typ = iter.typ.sons[0]
|
when false:
|
||||||
incl(result.flags, sfUsed)
|
result = newSym(skResult, getIdent":result", iter, iter.info)
|
||||||
|
result.typ = iter.typ.sons[0]
|
||||||
|
incl(result.flags, sfUsed)
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -636,6 +638,13 @@ proc transfIterBody(c: var TIterContext, n: PNode): PNode =
|
||||||
result.add(stateAsgnStmt)
|
result.add(stateAsgnStmt)
|
||||||
result.add(retStmt)
|
result.add(retStmt)
|
||||||
result.add(stateLabelStmt)
|
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:
|
else:
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
let x = transfIterBody(c, n.sons[i])
|
let x = transfIterBody(c, n.sons[i])
|
||||||
|
|
|
||||||
|
|
@ -1101,20 +1101,22 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||||
proc SemReturn(c: PContext, n: PNode): PNode =
|
proc SemReturn(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
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\'")
|
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 =
|
proc semProcBody(c: PContext, n: PNode): PNode =
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
|
|
|
||||||
|
|
@ -792,7 +792,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||||
ParamsTypeCheck(c, s.typ)
|
ParamsTypeCheck(c, s.typ)
|
||||||
pushProcCon(c, s)
|
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)
|
addResult(c, s.typ.sons[0], n.info, kind)
|
||||||
addResultNode(c, n)
|
addResultNode(c, n)
|
||||||
if sfImportc notin s.flags:
|
if sfImportc notin s.flags:
|
||||||
|
|
|
||||||
|
|
@ -1199,6 +1199,31 @@ details like this when mixing garbage collected data with unmanaged memory.
|
||||||
.. XXX finalizers for traced objects
|
.. 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
|
Procedural type
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
A `procedural type`:idx: is internally a pointer to a procedure. ``nil`` is
|
A `procedural type`:idx: is internally a pointer to a procedure. ``nil`` is
|
||||||
|
|
|
||||||
20
tests/run/titer9.nim
Normal file
20
tests/run/titer9.nim
Normal 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)
|
||||||
|
|
||||||
8
todo.txt
8
todo.txt
|
|
@ -2,7 +2,6 @@ version 0.9.2
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- test&finish first class iterators:
|
- test&finish first class iterators:
|
||||||
* allow return in first class iterators
|
|
||||||
* nested iterators
|
* nested iterators
|
||||||
* arglist as a type?
|
* arglist as a type?
|
||||||
|
|
||||||
|
|
@ -17,7 +16,7 @@ version 0.9.2
|
||||||
|
|
||||||
- improve the compiler as a service
|
- improve the compiler as a service
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``
|
- ``=`` should be overloadable; requires specialization for ``=``
|
||||||
- implement constructors and non-nil types
|
- implement constructors
|
||||||
- make 'bind' default for templates and introduce 'mixin';
|
- make 'bind' default for templates and introduce 'mixin';
|
||||||
special rule for ``[]=``
|
special rule for ``[]=``
|
||||||
- implicit deref for parameter matching; overloading based on 'var T'
|
- implicit deref for parameter matching; overloading based on 'var T'
|
||||||
|
|
@ -38,6 +37,7 @@ Bugs
|
||||||
version 0.9.XX
|
version 0.9.XX
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
- improve not-nil types
|
||||||
- make:
|
- make:
|
||||||
p(a, b):
|
p(a, b):
|
||||||
echo a
|
echo a
|
||||||
|
|
@ -144,7 +144,9 @@ Version 2 and beyond
|
||||||
(or implicit) syncGC() calls in loops. Automatic loop injection seems
|
(or implicit) syncGC() calls in loops. Automatic loop injection seems
|
||||||
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... But then 'new' itself
|
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;
|
- const ptr/ref --> pointless because of aliasing;
|
||||||
much better: 'writes: []' effect
|
much better: 'writes: []' effect
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue