# # # The Nimrod Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # this module does the semantic checking of type declarations # included from sem.nim proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = if prev == nil: result = newTypeS(kind, c) else: result = prev if result.kind == tyForward: result.kind = kind proc newConstraint(c: PContext, k: TTypeKind): PType = result = newTypeS(tyTypeClass, c) result.addSonSkipIntLit(newTypeS(k, c)) proc semEnum(c: PContext, n: PNode, prev: PType): PType = if n.sonsLen == 0: return newConstraint(c, tyEnum) var counter, x: BiggestInt e: PSym base: PType counter = 0 base = nil result = newOrPrevType(tyEnum, prev, c) result.n = newNodeI(nkEnumTy, n.info) checkMinSonsLen(n, 1) if n.sons[0].kind != nkEmpty: base = semTypeNode(c, n.sons[0].sons[0], nil) if base.kind != tyEnum: localError(n.sons[0].info, errInheritanceOnlyWithEnums) counter = lastOrd(base) + 1 rawAddSon(result, base) let isPure = result.sym != nil and sfPure in result.sym.flags var hasNull = false for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind of nkEnumFieldDef: e = newSymS(skEnumField, n.sons[i].sons[0], c) var v = semConstExpr(c, n.sons[i].sons[1]) var strVal: PNode = nil case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind of tyTuple: if sonsLen(v) == 2: strVal = v.sons[1] # second tuple part is the string value if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCstring}: x = getOrdValue(v.sons[0]) # first tuple part is the ordinal else: LocalError(strVal.info, errStringLiteralExpected) else: LocalError(v.info, errWrongNumberOfVariables) of tyString, tyCstring: strVal = v x = counter else: x = getOrdValue(v) if i != 1: if x != counter: incl(result.flags, tfEnumHasHoles) if x < counter: LocalError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s) x = counter e.ast = strVal # might be nil counter = x of nkSym: e = n.sons[i].sym of nkIdent: e = newSymS(skEnumField, n.sons[i], c) else: illFormedAst(n) e.typ = result e.position = int(counter) if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: incl(e.flags, sfUsed) incl(e.flags, sfExported) if not isPure: StrTableAdd(c.module.tab, e) addSon(result.n, newSymNode(e)) if sfGenSym notin e.flags and not isPure: addDecl(c, e) inc(counter) if not hasNull: incl(result.flags, tfNeedsInit) proc semSet(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tySet, prev, c) if sonsLen(n) == 2: var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) if base.kind == tyGenericInst: base = lastSon(base) if base.kind != tyGenericParam: if not isOrdinalType(base): LocalError(n.info, errOrdinalTypeExpected) elif lengthOrd(base) > MaxSetElements: LocalError(n.info, errSetTooBig) else: LocalError(n.info, errXExpectsOneTypeParam, "set") addSonSkipIntLit(result, errorType(c)) proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, prev: PType): PType = result = newOrPrevType(kind, prev, c) if sonsLen(n) == 2: var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) else: LocalError(n.info, errXExpectsOneTypeParam, kindStr) addSonSkipIntLit(result, errorType(c)) proc semVarargs(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyVarargs, prev, c) if sonsLen(n) == 2 or sonsLen(n) == 3: var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) if sonsLen(n) == 3: result.n = newIdentNode(considerAcc(n.sons[2]), n.sons[2].info) else: LocalError(n.info, errXExpectsOneTypeParam, "varargs") addSonSkipIntLit(result, errorType(c)) proc semAnyRef(c: PContext, n: PNode, kind: TTypeKind, prev: PType): PType = if sonsLen(n) == 1: result = newOrPrevType(kind, prev, c) var base = semTypeNode(c, n.sons[0], nil) addSonSkipIntLit(result, base) else: result = newConstraint(c, kind) proc semVarType(c: PContext, n: PNode, prev: PType): PType = if sonsLen(n) == 1: result = newOrPrevType(tyVar, prev, c) var base = semTypeNode(c, n.sons[0], nil) if base.kind == tyVar: LocalError(n.info, errVarVarTypeNotAllowed) base = base.sons[0] addSonSkipIntLit(result, base) else: result = newConstraint(c, tyVar) proc semDistinct(c: PContext, n: PNode, prev: PType): PType = if sonsLen(n) == 1: result = newOrPrevType(tyDistinct, prev, c) addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil)) else: result = newConstraint(c, tyDistinct) proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = assert IsRange(n) checkSonsLen(n, 3) result = newOrPrevType(tyRange, prev, c) result.n = newNodeI(nkRange, n.info) if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): LocalError(n.Info, errRangeIsEmpty) var a = semConstExpr(c, n[1]) var b = semConstExpr(c, n[2]) if not sameType(a.typ, b.typ): LocalError(n.info, errPureTypeMismatch) elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar, tyFloat..tyFloat128,tyUInt8..tyUInt32}: LocalError(n.info, errOrdinalTypeExpected) elif enumHasHoles(a.typ): LocalError(n.info, errEnumXHas
discard """
output: '''0
1
2
3
4
5
6
7
8
9
10
5 5
7 7
9 9
0
0
0
0
1
2
70'''
"""
when true:
proc main() =
let
lo=0
hi=10
iterator itA(): int =
for x in lo..hi:
yield x
for x in itA():
echo x
var y: int
iterator itB(): int =
while y <= hi:
yield y
inc y
y = 5
for x in itB():
echo x, " ", y
inc y
main()
iterator infinite(): int {.closure.} =
var i = 0
while true:
yield i
inc i
iterator take[T](it: iterator (): T, numToTake: int): T {.closure.} =
var i = 0
for x in it():
if i >= numToTake:
break
yield x
inc i
# gives wrong reasult (3 times 0)
for x in infinite.take(3):
echo x
# does what we want
let inf = infinite
for x in inf.take(3):
echo x
# bug #3583
proc foo(f: (iterator(): int)) =
for i in f(): echo i
let fIt = iterator(): int = yield 70
foo fIt