next steps for closure iterators

This commit is contained in:
Araq 2014-01-22 17:32:38 +01:00
commit 37229df7fc
28 changed files with 164 additions and 71 deletions

View file

@ -287,6 +287,7 @@ const
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
# require RC ops # require RC ops
sfClosureCreated* = sfDiscriminant # for transf-lambdalifting interaction
const const
# getting ready for the future expr/stmt merge # getting ready for the future expr/stmt merge

View file

@ -150,6 +150,18 @@ proc newInnerContext(fn: PSym): PInnerContext =
result.fn = fn result.fn = fn
initIdNodeTable(result.localsToAccess) initIdNodeTable(result.localsToAccess)
proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc createStateField(iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info)
result.typ = getStateType(iter)
proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv = proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
new(result) new(result)
result.deps = @[] result.deps = @[]
@ -170,6 +182,9 @@ proc addField(tup: PType, s: PSym) =
proc addCapturedVar(e: PEnv, v: PSym) = proc addCapturedVar(e: PEnv, v: PSym) =
for x in e.capturedVars: for x in e.capturedVars:
if x == v: return if x == v: return
# XXX meh, just add the state field for every closure for now, it's too
# hard to figure out if it comes from a closure iterator:
if e.tup.len == 0: addField(e.tup, createStateField(v.owner))
e.capturedVars.add(v) e.capturedVars.add(v)
addField(e.tup, v) addField(e.tup, v)
@ -189,6 +204,7 @@ proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node # returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info) var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.sons[0] deref.typ = a.typ.sons[0]
assert deref.typ.kind == tyTuple
let field = getSymFromList(deref.typ.n, b.name) let field = getSymFromList(deref.typ.n, b.name)
assert field != nil, b.name.s assert field != nil, b.name.s
addSon(deref, a) addSon(deref, a)
@ -220,18 +236,30 @@ proc getHiddenParam(routine: PSym): PSym =
assert hidden.kind == nkSym assert hidden.kind == nkSym
result = hidden.sym result = hidden.sym
proc getEnvParam(routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym
proc isInnerProc(s, outerProc: PSym): bool {.inline.} = proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
result = s.kind in {skProc, skMethod, skConverter} and result = (s.kind in {skProc, skMethod, skConverter} or
s.kind == skIterator and s.typ.callConv == ccClosure) and
s.skipGenericOwner == outerProc s.skipGenericOwner == outerProc
#s.typ.callConv == ccClosure #s.typ.callConv == ccClosure
proc addClosureParam(i: PInnerContext, e: PEnv) = proc addClosureParam(i: PInnerContext, e: PEnv) =
var cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info) var cp = getEnvParam(i.fn)
if cp == nil:
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, i.fn) cp.typ = newType(tyRef, i.fn)
rawAddSon(cp.typ, e.tup) rawAddSon(cp.typ, e.tup)
addHiddenParam(i.fn, cp)
else:
e.tup = cp.typ.sons[0]
assert e.tup.kind == tyTuple
i.closureParam = cp i.closureParam = cp
addHiddenParam(i.fn, i.closureParam)
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id #echo "closure param added for ", i.fn.name.s, " ", i.fn.id
proc dummyClosureParam(o: POuterContext, i: PInnerContext) = proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
@ -344,6 +372,7 @@ proc transformOuterConv(n: PNode): PNode =
proc makeClosure(prc, env: PSym, info: TLineInfo): PNode = proc makeClosure(prc, env: PSym, info: TLineInfo): PNode =
result = newNodeIT(nkClosure, info, prc.typ) result = newNodeIT(nkClosure, info, prc.typ)
result.add(newSymNode(prc)) result.add(newSymNode(prc))
if prc.kind == skIterator: incl(prc.flags, sfClosureCreated)
if env == nil: if env == nil:
result.add(newNodeIT(nkNilLit, info, getSysType(tyNil))) result.add(newNodeIT(nkNilLit, info, getSysType(tyNil)))
else: else:
@ -366,10 +395,10 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
else: else:
# captured symbol? # captured symbol?
result = idNodeTableGet(i.localsToAccess, n.sym) result = idNodeTableGet(i.localsToAccess, n.sym)
of nkLambdaKinds: of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformInnerProc(o, i, n.sons[namePos]) result = transformInnerProc(o, i, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef:
nkIteratorDef:
# don't recurse here: # don't recurse here:
discard discard
else: else:
@ -400,7 +429,8 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
if inner.closureParam != nil: if inner.closureParam != nil:
let ti = transformInnerProc(o, inner, body) let ti = transformInnerProc(o, inner, body)
if ti != nil: n.sym.ast.sons[bodyPos] = ti if ti != nil: n.sym.ast.sons[bodyPos] = ti
of nkLambdaKinds: of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
searchForInnerProcs(o, n.sons[namePos]) searchForInnerProcs(o, n.sons[namePos])
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt: of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
# some nodes open a new scope, so they are candidates for the insertion # some nodes open a new scope, so they are candidates for the insertion
@ -437,8 +467,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
searchForInnerProcs(o, it.sons[L-1]) searchForInnerProcs(o, it.sons[L-1])
else: else:
internalError(it.info, "transformOuter") internalError(it.info, "transformOuter")
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef:
nkIteratorDef:
# don't recurse here: # don't recurse here:
# XXX recurse here and setup 'up' pointers # XXX recurse here and setup 'up' pointers
discard discard
@ -535,10 +564,10 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
assert result != nil, "cannot find: " & local.name.s assert result != nil, "cannot find: " & local.name.s
# else it is captured by copy and this means that 'outer' should continue # else it is captured by copy and this means that 'outer' should continue
# to access the local as a local. # to access the local as a local.
of nkLambdaKinds: of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformOuterProc(o, n.sons[namePos]) result = transformOuterProc(o, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef:
nkIteratorDef:
# don't recurse here: # don't recurse here:
discard discard
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
@ -607,11 +636,14 @@ type
tup: PType tup: PType
proc newIterResult(iter: PSym): PSym = proc newIterResult(iter: PSym): PSym =
if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym result = iter.ast.sons[resultPos].sym
when false: else:
# XXX a bit hacky:
result = newSym(skResult, getIdent":result", iter, iter.info) result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0] result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed) incl(result.flags, sfUsed)
iter.ast.add newSymNode(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
@ -663,36 +695,40 @@ proc transfIterBody(c: var TIterContext, n: PNode): PNode =
let x = transfIterBody(c, n.sons[i]) let x = transfIterBody(c, n.sons[i])
if x != nil: n.sons[i] = x if x != nil: n.sons[i] = x
proc getStateType(iter: PSym): PType = proc initIterContext(c: var TIterContext, iter: PSym) =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc liftIterator*(iter: PSym, body: PNode): PNode =
var c: TIterContext
c.iter = iter c.iter = iter
c.capturedVars = initIntSet() c.capturedVars = initIntSet()
var cp = getEnvParam(iter)
if cp == nil:
c.tup = newType(tyTuple, iter) c.tup = newType(tyTuple, iter)
c.tup.n = newNodeI(nkRecList, iter.info) c.tup.n = newNodeI(nkRecList, iter.info)
var cp = newSym(skParam, getIdent(paramName), iter, iter.info) cp = newSym(skParam, getIdent(paramName), iter, iter.info)
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter) cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.tup) rawAddSon(cp.typ, c.tup)
c.closureParam = cp
addHiddenParam(iter, cp) addHiddenParam(iter, cp)
c.state = newSym(skField, getIdent(":state"), iter, iter.info) c.state = createStateField(iter)
c.state.typ = getStateType(iter) addField(c.tup, c.state)
else:
c.tup = cp.typ.sons[0]
assert c.tup.kind == tyTuple
if c.tup.len > 0:
c.state = c.tup.n[0].sym
else:
c.state = createStateField(iter)
addField(c.tup, c.state) addField(c.tup, c.state)
c.closureParam = cp
if iter.typ.sons[0] != nil: if iter.typ.sons[0] != nil:
c.resultSym = newIterResult(iter) c.resultSym = newIterResult(iter)
iter.ast.add(newSymNode(c.resultSym)) #iter.ast.add(newSymNode(c.resultSym))
proc liftIterator*(iter: PSym, body: PNode): PNode =
var c: TIterContext
initIterContext c, iter
result = newNodeI(nkStmtList, iter.info) result = newNodeI(nkStmtList, iter.info)
var gs = newNodeI(nkGotoState, iter.info) var gs = newNodeI(nkGotoState, iter.info)
@ -716,12 +752,14 @@ proc liftIterator*(iter: PSym, body: PNode): PNode =
proc liftIterSym*(n: PNode): PNode = proc liftIterSym*(n: PNode): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env)) # transforms (iter) to (let env = newClosure[iter](); (iter, env))
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let iter = n.sym let iter = n.sym
assert iter.kind == skIterator assert iter.kind == skIterator
if sfClosureCreated in iter.flags: return n
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var env = copySym(getHiddenParam(iter)) var env = copySym(getHiddenParam(iter))
env.kind = skLet env.kind = skLet
var v = newNodeI(nkVarSection, n.info) var v = newNodeI(nkVarSection, n.info)
addVar(v, newSymNode(env)) addVar(v, newSymNode(env))
result.add(v) result.add(v)
@ -766,7 +804,7 @@ proc liftForLoop*(body: PNode): PNode =
# static binding? # static binding?
var env: PSym var env: PSym
if call[0].kind == nkSym and call[0].sym.kind == skIterator: if call[0].kind == nkSym and call[0].sym.kind == skIterator:
# createClose() # createClosure()
let iter = call[0].sym let iter = call[0].sym
assert iter.kind == skIterator assert iter.kind == skIterator
env = copySym(getHiddenParam(iter)) env = copySym(getHiddenParam(iter))

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -31,7 +31,7 @@ type
TParser*{.final.} = object # a TParser object represents a module that TParser*{.final.} = object # a TParser object represents a module that
# is being parsed # is being parsed
currInd: int # current indentation currInd: int # current indentation
firstTok: bool firstTok, strongSpaces: bool
lex*: TLexer # the lexer that is used for parsing lex*: TLexer # the lexer that is used for parsing
tok*: TToken # the current token tok*: TToken # the current token
inPragma: int inPragma: int

View file

@ -1251,6 +1251,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParLe, "(META|") put(g, tkParLe, "(META|")
gsub(g, n.sons[0]) gsub(g, n.sons[0])
put(g, tkParRi, ")") put(g, tkParRi, ")")
of nkGotoState, nkState:
var c: TContext
initContext c
putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
gsons(g, n, c)
else: else:
#nkNone, nkExplicitTypeListCall: #nkNone, nkExplicitTypeListCall:
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')') internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')

View file

@ -868,6 +868,8 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
return semStmt(c, x) return semStmt(c, x)
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX semProcAux should be good enough for this now, we will eventually
# remove semLambda
result = semProcAnnotation(c, n) result = semProcAnnotation(c, n)
if result != nil: return result if result != nil: return result
result = n result = n
@ -949,11 +951,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
var s: PSym var s: PSym
var typeIsDetermined = false var typeIsDetermined = false
var isAnon = false
if n[namePos].kind != nkSym: if n[namePos].kind != nkSym:
assert phase == stepRegisterSymbol assert phase == stepRegisterSymbol
if n[namePos].kind == nkEmpty: if n[namePos].kind == nkEmpty:
s = newSym(kind, idAnon, getCurrOwner(), n.info) s = newSym(kind, idAnon, getCurrOwner(), n.info)
isAnon = true
else: else:
s = semIdentDef(c, n.sons[0], kind) s = semIdentDef(c, n.sons[0], kind)
n.sons[namePos] = newSymNode(s) n.sons[namePos] = newSymNode(s)
@ -996,11 +1000,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
rawAddSon(s.typ, nil) rawAddSon(s.typ, nil)
if n.sons[patternPos].kind != nkEmpty: if n.sons[patternPos].kind != nkEmpty:
n.sons[patternPos] = semPattern(c, n.sons[patternPos]) n.sons[patternPos] = semPattern(c, n.sons[patternPos])
if s.kind == skIterator: s.typ.flags.incl(tfIterator) if s.kind == skIterator:
s.typ.flags.incl(tfIterator)
var proto = searchForProc(c, s.scope, s) var proto = searchForProc(c, s.scope, s)
if proto == nil: if proto == nil:
s.typ.callConv = lastOptionEntry(c).defaultCC if s.kind == skIterator and isAnon: s.typ.callConv = ccClosure
else: s.typ.callConv = lastOptionEntry(c).defaultCC
# add it here, so that recursive procs are possible: # add it here, so that recursive procs are possible:
if sfGenSym in s.flags: discard if sfGenSym in s.flags: discard
elif kind in OverloadableSyms: elif kind in OverloadableSyms:
@ -1078,6 +1084,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner() popOwner()
if n.sons[patternPos].kind != nkEmpty: if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s) c.patterns.add(s)
if isAnon: result.typ = s.typ
proc determineType(c: PContext, s: PSym) = proc determineType(c: PContext, s: PSym) =
if s.typ != nil: return if s.typ != nil: return

View file

@ -636,6 +636,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
s.ast.sons[bodyPos] = n.sons[bodyPos] s.ast.sons[bodyPos] = n.sons[bodyPos]
#n.sons[bodyPos] = liftLambdas(s, n) #n.sons[bodyPos] = liftLambdas(s, n)
#if n.kind == nkMethodDef: methodDef(s, false) #if n.kind == nkMethodDef: methodDef(s, false)
if n.kind == nkIteratorDef and n.typ != nil:
return liftIterSym(n.sons[namePos]).PTransNode
result = PTransNode(n) result = PTransNode(n)
of nkMacroDef: of nkMacroDef:
# XXX no proper closure support yet: # XXX no proper closure support yet:
@ -708,6 +710,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
# XXX comment handling really sucks: # XXX comment handling really sucks:
if importantComments(): if importantComments():
PNode(result).comment = n.comment PNode(result).comment = n.comment
of nkClosure: return PTransNode(n)
else: else:
result = transformSons(c, n) result = transformSons(c, n)
var cnst = getConstExpr(c.module, PNode(result)) var cnst = getConstExpr(c.module, PNode(result))

View file

@ -2261,8 +2261,8 @@ from different modules having the same name.
using sdl.SetTimer using sdl.SetTimer
Note that ``using`` only *adds* to the current context, it doesn't remove or Note that ``using`` only *adds* to the current context, it doesn't remove or
replace, **neither** does it create a new scope. What this means is that if you replace, **neither** does it create a new scope. What this means is that if one
apply this to multiple variables the compiler will find conflicts in what applies this to multiple variables the compiler will find conflicts in what
variable to use: variable to use:
.. code-block:: nimrod .. code-block:: nimrod
@ -2275,7 +2275,7 @@ variable to use:
echo b echo b
When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
be used with the proc, so you get ``Error: expression '(a|b)' has no type (or be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or
is ambiguous)``. To solve this you would need to nest ``using`` with a is ambiguous)``. To solve this you would need to nest ``using`` with a
``block`` statement so as to control the reach of the ``using`` statement. ``block`` statement so as to control the reach of the ``using`` statement.
@ -2368,8 +2368,8 @@ The `addr`:idx: operator returns the address of an l-value. If the type of the
location is ``T``, the `addr` operator result is of the type ``ptr T``. An location is ``T``, the `addr` operator result is of the type ``ptr T``. An
address is always an untraced reference. Taking the address of an object that address is always an untraced reference. Taking the address of an object that
resides on the stack is **unsafe**, as the pointer may live longer than the resides on the stack is **unsafe**, as the pointer may live longer than the
object on the stack and can thus reference a non-existing object. You can get object on the stack and can thus reference a non-existing object. One can get
the address of variables, but you can't use it on variables declared through the address of variables, but one can't use it on variables declared through
``let`` statements: ``let`` statements:
.. code-block:: nimrod .. code-block:: nimrod
@ -2764,7 +2764,7 @@ First class iterators
There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators. There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators.
An `inline iterator`:idx: is an iterator that's always inlined by the compiler An `inline iterator`:idx: is an iterator that's always inlined by the compiler
leading to zero overhead for the abstraction, but may result in a heavy leading to zero overhead for the abstraction, but may result in a heavy
increasee in code size. Inline iterators are second class increase in code size. Inline iterators are second class
citizens; one cannot pass them around like first class procs. citizens; one cannot pass them around like first class procs.
In contrast to that, a `closure iterator`:idx: can be passed around: In contrast to that, a `closure iterator`:idx: can be passed around:
@ -2837,6 +2837,9 @@ 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
Type sections Type sections
============= =============
@ -2923,9 +2926,9 @@ in an implicit try block:
finally: close(f) finally: close(f)
... ...
The ``except`` statement has a limitation in this form: you can't specify the The ``except`` statement has a limitation in this form: one can't specify the
type of the exception, you have to catch everything. Also, if you want to use type of the exception, one has to catch everything. Also, if one wants to use
both ``finally`` and ``except`` you need to reverse the usual sequence of the both ``finally`` and ``except`` one needs to reverse the usual sequence of the
statements. Example: statements. Example:
.. code-block:: nimrod .. code-block:: nimrod
@ -3353,7 +3356,7 @@ currently matched type. These instances can act both as variables of the type,
when used in contexts, where a value is expected, and as the type itself, when when used in contexts, where a value is expected, and as the type itself, when
used in a contexts, where a type is expected. used in a contexts, where a type is expected.
Please note that the ``is`` operator allows you to easily verify the precise Please note that the ``is`` operator allows one to easily verify the precise
type signatures of the required operations, but since type inference and type signatures of the required operations, but since type inference and
default parameters are still applied in the provided block, it's also possible default parameters are still applied in the provided block, it's also possible
to encode usage protocols that doesn't reveal implementation details. to encode usage protocols that doesn't reveal implementation details.

View file

@ -42,7 +42,7 @@ Possible Commands:
csource [options] builds the C sources for installation csource [options] builds the C sources for installation
zip builds the installation ZIP package zip builds the installation ZIP package
inno [options] builds the Inno Setup installer (for Windows) inno [options] builds the Inno Setup installer (for Windows)
tests run the testsuite tests [options] run the testsuite
update updates nimrod to the latest version from github update updates nimrod to the latest version from github
(compile koch with -d:withUpdate to enable) (compile koch with -d:withUpdate to enable)
temp options creates a temporary compiler for testing temp options creates a temporary compiler for testing
@ -260,11 +260,14 @@ when defined(withUpdate):
# -------------- tests -------------------------------------------------------- # -------------- tests --------------------------------------------------------
template `|`(a, b): expr = (if a.len > 0: a else: b)
proc tests(args: string) = proc tests(args: string) =
# we compile the tester with taintMode:on to have a basic # we compile the tester with taintMode:on to have a basic
# taint mode test :-) # taint mode test :-)
exec("nimrod cc --taintMode:on tests/testament/tester") exec "nimrod cc --taintMode:on tests/testament/tester"
exec(getCurrentDir() / "tests/testament/tester".exe & " all") exec quoteShell(getCurrentDir() / "tests/testament/tester".exe) & " " &
(args|"all")
proc temp(args: string) = proc temp(args: string) =
var output = "compiler" / "nimrod".exe var output = "compiler" / "nimrod".exe

View file

@ -390,7 +390,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
res.add(($n.kind).substr(3)) res.add(($n.kind).substr(3))
case n.kind case n.kind
of nnkEmpty: nil # same as nil node in this representation of nnkEmpty: discard # same as nil node in this representation
of nnkNilLit: res.add(" nil") of nnkNilLit: res.add(" nil")
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal) of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal) of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
@ -415,7 +415,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
add(result, "(") add(result, "(")
case n.kind case n.kind
of nnkEmpty: nil # same as nil node in this representation of nnkEmpty: discard # same as nil node in this representation
of nnkNilLit: add(result, "nil") of nnkNilLit: add(result, "nil")
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal) of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal) of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)

32
tests/iter/tanoniter1.nim Normal file
View file

@ -0,0 +1,32 @@
discard """
output: '''1
2
3
4
1
2'''
"""
proc factory(a, b: int): iterator (): int =
iterator foo(): int =
var x = a
while x <= b:
yield x
inc x
return foo
proc factory2(a, b: int): iterator (): int =
return iterator (): int =
var x = a
while x <= b:
yield x
inc x
let foo = factory 1, 4
for f in foo():
echo f
let foo2 = factory2 1,2
for f in foo2(): echo f

View file

@ -1,6 +1,6 @@
discard """ discard """
output: '''true''' output: '''true'''
cmd: "nimrod cc --gc:none --hints:on $# $#" cmd: "nimrod cc --gc:none --hints:on --warnings:off $# $#"
""" """
import hashes import hashes

View file

@ -3,6 +3,7 @@ version 0.9.4
- test&finish first class iterators: - test&finish first class iterators:
* nested iterators * nested iterators
- implement strongSpaces:on
- ensure (ref T)(a, b) works as a type conversion and type constructor - 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 - make '--implicitStatic:on' the default