Merge branch 'devel' of https://github.com/Araq/Nimrod into devel

This commit is contained in:
Araq 2014-03-07 22:28:48 +01:00
commit dd216755ff
33 changed files with 310 additions and 112 deletions

View file

@ -469,7 +469,8 @@ type
skResult, # special 'result' variable skResult, # special 'result' variable
skProc, # a proc skProc, # a proc
skMethod, # a method skMethod, # a method
skIterator, # an iterator skIterator, # an inline iterator
skClosureIterator, # a resumable closure iterator
skConverter, # a type converter skConverter, # a type converter
skMacro, # a macro skMacro, # a macro
skTemplate, # a template; currently also misused for user-defined skTemplate, # a template; currently also misused for user-defined
@ -485,8 +486,8 @@ type
TSymKinds* = set[TSymKind] TSymKinds* = set[TSymKind]
const const
routineKinds* = {skProc, skMethod, skIterator, skConverter, routineKinds* = {skProc, skMethod, skIterator, skClosureIterator,
skMacro, skTemplate} skConverter, skMacro, skTemplate}
tfIncompleteStruct* = tfVarargs tfIncompleteStruct* = tfVarargs
tfUncheckedArray* = tfVarargs tfUncheckedArray* = tfVarargs
tfUnion* = tfNoSideEffect tfUnion* = tfNoSideEffect
@ -822,8 +823,8 @@ type
# the poor naming choices in the standard library. # the poor naming choices in the standard library.
const const
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter, OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
skModule, skTemplate, skMacro} skConverter, skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody, GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
tyGenericParam} tyGenericParam}
@ -845,7 +846,8 @@ const
tyTuple, tySequence} tyTuple, tySequence}
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence, NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
tyProc, tyString, tyError} tyProc, tyString, tyError}
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
skIterator, skClosureIterator,
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub} skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
nfDotSetter, nfDotField, nfDotSetter, nfDotField,
@ -871,7 +873,10 @@ const
nkStrKinds* = {nkStrLit..nkTripleStrLit} nkStrKinds* = {nkStrLit..nkTripleStrLit}
skLocalVars* = {skVar, skLet, skForVar, skParam, skResult} skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter} skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skClosureIterator,
skMethod, skConverter}
skIterators* = {skIterator, skClosureIterator}
lfFullExternalName* = lfParamCopy # \ lfFullExternalName* = lfParamCopy # \
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been # only used when 'gCmd == cmdPretty': Indicates that the symbol has been
@ -1481,8 +1486,7 @@ proc originatingModule*(s: PSym): PSym =
while result.kind != skModule: result = result.owner while result.kind != skModule: result = result.owner
proc isRoutine*(s: PSym): bool {.inline.} = proc isRoutine*(s: PSym): bool {.inline.} =
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod, result = s.kind in skProcKinds
skConverter}
proc hasPattern*(s: PSym): bool {.inline.} = proc hasPattern*(s: PSym): bool {.inline.} =
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty

View file

@ -1803,7 +1803,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else: else:
genProc(p.module, sym) genProc(p.module, sym)
putLocIntoDest(p, d, sym.loc) putLocIntoDest(p, d, sym.loc)
of skProc, skConverter, skIterator: of skProc, skConverter, skIterators:
genProc(p.module, sym) genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil: if sym.loc.r == nil or sym.loc.t == nil:
internalError(n.info, "expr: proc not init " & sym.name.s) internalError(n.info, "expr: proc not init " & sym.name.s)

View file

@ -863,7 +863,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
res.add(t.sons[i].strVal) res.add(t.sons[i].strVal)
of nkSym: of nkSym:
var sym = t.sons[i].sym var sym = t.sons[i].sym
if sym.kind in {skProc, skIterator, skMethod}: if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
var a: TLoc var a: TLoc
initLocExpr(p, t.sons[i], a) initLocExpr(p, t.sons[i], a)
res.add(rdLoc(a).ropeToStr) res.add(rdLoc(a).ropeToStr)

View file

@ -69,7 +69,7 @@ proc mangleName(s: PSym): PRope =
if result == nil: if result == nil:
if gCmd == cmdCompileToLLVM: if gCmd == cmdCompileToLLVM:
case s.kind case s.kind
of skProc, skMethod, skConverter, skConst, skIterator: of skProc, skMethod, skConverter, skConst, skIterators:
result = ~"@" result = ~"@"
of skVar, skForVar, skResult, skLet: of skVar, skForVar, skResult, skLet:
if sfGlobal in s.flags: result = ~"@" if sfGlobal in s.flags: result = ~"@"

View file

@ -705,7 +705,7 @@ proc cgsym(m: BModule, name: string): PRope =
var sym = magicsys.getCompilerProc(name) var sym = magicsys.getCompilerProc(name)
if sym != nil: if sym != nil:
case sym.kind case sym.kind
of skProc, skMethod, skConverter, skIterator: genProc(m, sym) of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym) of skVar, skResult, skLet: genVarPrototype(m, sym)
of skType: discard getTypeDesc(m, sym.typ) of skType: discard getTypeDesc(m, sym.typ)
else: internalError("cgsym: " & name) else: internalError("cgsym: " & name)
@ -1192,7 +1192,7 @@ proc nullify[T](arr: var T) =
for i in low(arr)..high(arr): for i in low(arr)..high(arr):
arr[i] = nil arr[i] = nil
proc resetModule*(m: var BModule) = proc resetModule*(m: BModule) =
# between two compilations in CAAS mode, we can throw # between two compilations in CAAS mode, we can throw
# away all the data that was written to disk # away all the data that was written to disk
initLinkedList(m.headerFiles) initLinkedList(m.headerFiles)

View file

@ -146,7 +146,7 @@ proc newProc*(prc: PSym, module: BModule): BProc =
result.nestedTryStmts = @[] result.nestedTryStmts = @[]
result.finallySafePoints = @[] result.finallySafePoints = @[]
iterator cgenModules*: var BModule = iterator cgenModules*: BModule =
for i in 0..high(gModules): for i in 0..high(gModules):
# ultimately, we are iterating over the file ids here. # ultimately, we are iterating over the file ids here.
# some "files" won't have an associated cgen module (like stdin) # some "files" won't have an associated cgen module (like stdin)

View file

@ -366,7 +366,7 @@ proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
proc genSection(d: PDoc, kind: TSymKind) = proc genSection(d: PDoc, kind: TSymKind) =
const sectionNames: array[skModule..skTemplate, string] = [ const sectionNames: array[skModule..skTemplate, string] = [
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods", "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
"Iterators", "Converters", "Macros", "Templates" "Iterators", "Iterators", "Converters", "Macros", "Templates"
] ]
if d.section[kind] == nil: return if d.section[kind] == nil: return
var title = sectionNames[kind].toRope var title = sectionNames[kind].toRope

View file

@ -103,7 +103,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
internalError(n.info, "importSymbol: 2") internalError(n.info, "importSymbol: 2")
# for an enumeration we have to add all identifiers # for an enumeration we have to add all identifiers
case s.kind case s.kind
of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter: of skProcKinds:
# for a overloadable syms add all overloaded routines # for a overloadable syms add all overloaded routines
var it: TIdentIter var it: TIdentIter
var e = initIdentIter(it, fromMod.tab, s.name) var e = initIdentIter(it, fromMod.tab, s.name)

View file

@ -1154,7 +1154,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
proc isIndirect(v: PSym): bool = proc isIndirect(v: PSym): bool =
result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and
v.kind notin {skProc, skConverter, skMethod, skIterator} v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
proc genVarInit(p: PProc, v: PSym, n: PNode) = proc genVarInit(p: PProc, v: PSym, n: PNode) =
var var

View file

@ -232,7 +232,7 @@ proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
initIdNodeTable(result.localsToAccess) initIdNodeTable(result.localsToAccess)
initIdTable(result.localsToEnv) initIdTable(result.localsToEnv)
initIdTable(result.lambdasToEnv) initIdTable(result.lambdasToEnv)
result.isIter = fn.kind == skIterator and fn.typ.callConv == ccClosure result.isIter = fn.kind == skClosureIterator
if result.isIter: initIterContext(result, fn) if result.isIter: initIterContext(result, fn)
proc newInnerContext(fn: PSym): PInnerContext = proc newInnerContext(fn: PSym): PInnerContext =
@ -292,8 +292,7 @@ proc newCall(a, b: PSym): PNode =
result.add newSymNode(b) result.add newSymNode(b)
proc isInnerProc(s, outerProc: PSym): bool {.inline.} = proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
result = (s.kind in {skProc, skMethod, skConverter} or result = s.kind in {skProc, skMethod, skConverter, skClosureIterator} and
s.kind == skIterator and s.typ.callConv == ccClosure) and
s.skipGenericOwner == outerProc s.skipGenericOwner == outerProc
#s.typ.callConv == ccClosure #s.typ.callConv == ccClosure
@ -653,7 +652,7 @@ proc outerProcSons(o: POuterContext, n: 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))
let iter = n.sym let iter = n.sym
assert iter.kind == skIterator assert iter.kind == skClosureIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ) result = newNodeIT(nkStmtListExpr, n.info, n.typ)
@ -679,7 +678,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
var closure = PEnv(idTableGet(o.lambdasToEnv, local)) var closure = PEnv(idTableGet(o.lambdasToEnv, local))
if local.kind == skIterator and local.typ.callConv == ccClosure: if local.kind == skClosureIterator:
# consider: [i1, i2, i1] Since we merged the iterator's closure # consider: [i1, i2, i1] Since we merged the iterator's closure
# with the captured owning variables, we need to generate the # with the captured owning variables, we need to generate the
# closure generation code again: # closure generation code again:
@ -843,10 +842,10 @@ 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 == skClosureIterator:
# createClosure() # createClosure()
let iter = call[0].sym let iter = call[0].sym
assert iter.kind == skIterator assert iter.kind == skClosureIterator
env = copySym(getHiddenParam(iter)) env = copySym(getHiddenParam(iter))
var v = newNodeI(nkVarSection, body.info) var v = newNodeI(nkVarSection, body.info)

View file

@ -109,7 +109,7 @@ type
proc getSymRepr*(s: PSym): string = proc getSymRepr*(s: PSym): string =
case s.kind case s.kind
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s) of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
else: result = s.name.s else: result = s.name.s
proc ensureNoMissingOrUnusedSymbols(scope: PScope) = proc ensureNoMissingOrUnusedSymbols(scope: PScope) =

View file

@ -776,6 +776,17 @@ proc implictPragmas*(c: PContext, sym: PSym, n: PNode,
addToLib(lib, sym) addToLib(lib, sym)
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s) if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil:
return false
for p in n.sons:
var key = if p.kind == nkExprColonExpr: p[0] else: p
if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
return true
return false
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return if n == nil: return
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):

View file

@ -64,7 +64,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
errors[errors.len - 1].add("\n " & err) errors[errors.len - 1].add("\n " & err)
if z.state == csMatch: if z.state == csMatch:
# little hack so that iterators are preferred over everything else: # little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200) if sym.kind in skIterators: inc(z.exactMatches, 200)
case best.state case best.state
of csEmpty, csNoMatch: best = z of csEmpty, csNoMatch: best = z
of csMatch: of csMatch:
@ -289,8 +289,9 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = newNodeI(a.kind, n.info) result = newNodeI(a.kind, n.info)
for i in countup(0, len(a)-1): for i in countup(0, len(a)-1):
var candidate = a.sons[i].sym var candidate = a.sons[i].sym
if candidate.kind in {skProc, skMethod, skConverter, skIterator}: if candidate.kind in {skProc, skMethod, skConverter,
# if suffices that the candidate has the proper number of generic skIterator, skClosureIterator}:
# it suffices that the candidate has the proper number of generic
# type parameters: # type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1: if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
result.add(explicitGenericSym(c, n, candidate)) result.add(explicitGenericSym(c, n, candidate))

View file

@ -274,7 +274,7 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt;
addSonSkipIntLit(result, intType) # basetype of range addSonSkipIntLit(result, intType) # basetype of range
proc markIndirect*(c: PContext, s: PSym) {.inline.} = proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skConverter, skMethod, skIterator}: if s.kind in {skProc, skConverter, skMethod, skIterator, skClosureIterator}:
incl(s.flags, sfAddrTaken) incl(s.flags, sfAddrTaken)
# XXX add to 'c' for global analysis # XXX add to 'c' for global analysis

View file

@ -323,11 +323,6 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
result = newIntNode(nkIntLit, ord(t.kind == tyProc and result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and t.callConv == ccClosure and
tfIterator notin t.flags)) tfIterator notin t.flags))
of "iterator":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator in t.flags))
else: else:
var t2 = n[2].typ.skipTypes({tyTypeDesc}) var t2 = n[2].typ.skipTypes({tyTypeDesc})
let lifted = liftParamType(c, skType, newNodeI(nkArgList, n.info), let lifted = liftParamType(c, skType, newNodeI(nkArgList, n.info),
@ -662,11 +657,11 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
if flags*{efInTypeof, efWantIterator} != {}: if flags*{efInTypeof, efWantIterator} != {}:
# consider: 'for x in pReturningArray()' --> we don't want the restriction # consider: 'for x in pReturningArray()' --> we don't want the restriction
# to 'skIterator' anymore; skIterator is preferred in sigmatch already for # to 'skIterators' anymore; skIterators are preferred in sigmatch already
# typeof support. # for typeof support.
# for ``type(countup(1,3))``, see ``tests/ttoseq``. # for ``type(countup(1,3))``, see ``tests/ttoseq``.
result = semOverloadedCall(c, n, nOrig, result = semOverloadedCall(c, n, nOrig,
{skProc, skMethod, skConverter, skMacro, skTemplate, skIterator}) {skProc, skMethod, skConverter, skMacro, skTemplate}+skIterators)
else: else:
result = semOverloadedCall(c, n, nOrig, result = semOverloadedCall(c, n, nOrig,
{skProc, skMethod, skConverter, skMacro, skTemplate}) {skProc, skMethod, skConverter, skMacro, skTemplate})
@ -679,7 +674,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
case callee.kind case callee.kind
of skMacro, skTemplate: discard of skMacro, skTemplate: discard
else: else:
if (callee.kind == skIterator) and (callee.id == c.p.owner.id): if (callee.kind in skIterators) and (callee.id == c.p.owner.id):
localError(n.info, errRecursiveDependencyX, callee.name.s) localError(n.info, errRecursiveDependencyX, callee.name.s)
if sfNoSideEffect notin callee.flags: if sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * callee.flags != {}: if {sfImportc, sfSideEffect} * callee.flags != {}:
@ -1193,7 +1188,7 @@ proc semReturn(c: PContext, n: PNode): PNode =
result = n result = n
checkSonsLen(n, 1) checkSonsLen(n, 1)
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or
(c.p.owner.kind == skIterator and c.p.owner.typ.callConv == ccClosure): c.p.owner.kind == skClosureIterator:
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
# transform ``return expr`` to ``result = expr; return`` # transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil: if c.p.resultSym != nil:
@ -1258,7 +1253,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
proc semYield(c: PContext, n: PNode): PNode = proc semYield(c: PContext, n: PNode): PNode =
result = n result = n
checkSonsLen(n, 1) checkSonsLen(n, 1)
if c.p.owner == nil or c.p.owner.kind != skIterator: if c.p.owner == nil or c.p.owner.kind notin skIterators:
localError(n.info, errYieldNotAllowedHere) localError(n.info, errYieldNotAllowedHere)
elif c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline: elif c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline:
localError(n.info, errYieldNotAllowedInTryStmt) localError(n.info, errYieldNotAllowedInTryStmt)
@ -1266,9 +1261,11 @@ proc semYield(c: PContext, n: PNode): PNode =
n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility: n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
var restype = c.p.owner.typ.sons[0] var restype = c.p.owner.typ.sons[0]
if restype != nil: if restype != nil:
n.sons[0] = fitNode(c, restype, n.sons[0]) let adjustedRes = if c.p.owner.kind == skIterator: restype.base
else: restype
n.sons[0] = fitNode(c, adjustedRes, n.sons[0])
if n.sons[0].typ == nil: internalError(n.info, "semYield") if n.sons[0].typ == nil: internalError(n.info, "semYield")
semYieldVarResult(c, n, restype) semYieldVarResult(c, n, adjustedRes)
else: else:
localError(n.info, errCannotReturnExpr) localError(n.info, errCannotReturnExpr)
elif c.p.owner.typ.sons[0] != nil: elif c.p.owner.typ.sons[0] != nil:
@ -1828,7 +1825,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
var s = lookUp(c, n) var s = lookUp(c, n)
semCaptureSym(s, c.p.owner) semCaptureSym(s, c.p.owner)
result = semSym(c, n, s, flags) result = semSym(c, n, s, flags)
if s.kind in {skProc, skMethod, skIterator, skConverter}: if s.kind in {skProc, skMethod, skConverter}+skIterators:
#performProcvarCheck(c, n, s) #performProcvarCheck(c, n, s)
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
if result.kind == nkSym: if result.kind == nkSym:
@ -1884,7 +1881,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
message(n.info, warnDeprecated, "bind") message(n.info, warnDeprecated, "bind")
result = semExpr(c, n.sons[0], flags) result = semExpr(c, n.sons[0], flags)
of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy: of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy:
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
result.typ = makeTypeDesc(c, typ) result.typ = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info) #result = symNodeFromType(c, typ, n.info)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
@ -1918,7 +1915,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
localError(n.info, errUseQualifier, s.name.s) localError(n.info, errUseQualifier, s.name.s)
elif s.magic == mNone: result = semDirectOp(c, n, flags) elif s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags) else: result = semMagic(c, n, s, flags)
of skProc, skMethod, skConverter, skIterator: of skProc, skMethod, skConverter, skIterators:
if s.magic == mNone: result = semDirectOp(c, n, flags) if s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags) else: result = semMagic(c, n, s, flags)
else: else:
@ -1942,7 +1939,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkBracketExpr: of nkBracketExpr:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared}) var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: if s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators:
# type parameters: partial generic specialization # type parameters: partial generic specialization
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
result = explicitGenericInstantiation(c, n, s) result = explicitGenericInstantiation(c, n, s)

View file

@ -42,7 +42,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skUnknown: of skUnknown:
# Introduced in this pass! Leave it as an identifier. # Introduced in this pass! Leave it as an identifier.
result = n result = n
of skProc, skMethod, skIterator, skConverter: of skProc, skMethod, skIterators, skConverter:
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skTemplate: of skTemplate:
if macroToExpand(s): if macroToExpand(s):
@ -141,7 +141,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# symbol lookup ... # symbol lookup ...
of skUnknown, skParam: of skUnknown, skParam:
# Leave it as an identifier. # Leave it as an identifier.
of skProc, skMethod, skIterator, skConverter: of skProc, skMethod, skIterators, skConverter:
result.sons[0] = symChoice(c, n.sons[0], s, scOption) result.sons[0] = symChoice(c, n.sons[0], s, scOption)
first = 1 first = 1
of skGenericParam: of skGenericParam:

View file

@ -76,8 +76,8 @@ proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
proc semProcvarCheck(c: PContext, n: PNode) = proc semProcvarCheck(c: PContext, n: PNode) =
let n = n.skipConv let n = n.skipConv
if n.kind == nkSym and n.sym.kind in {skProc, skMethod, skIterator, if n.kind == nkSym and n.sym.kind in {skProc, skMethod, skConverter,
skConverter}: skIterator, skClosureIterator}:
performProcvarCheck(c, n, n.sym) performProcvarCheck(c, n, n.sym)
proc semProc(c: PContext, n: PNode): PNode proc semProc(c: PContext, n: PNode): PNode
@ -616,7 +616,8 @@ proc symForVar(c: PContext, n: PNode): PSym =
proc semForVars(c: PContext, n: PNode): PNode = proc semForVars(c: PContext, n: PNode): PNode =
result = n result = n
var length = sonsLen(n) var length = sonsLen(n)
var iter = skipTypes(n.sons[length-2].typ, {tyGenericInst}) let iterBase = n.sons[length-2].typ.skipTypes({tyIter})
var iter = skipTypes(iterBase, {tyGenericInst})
# length == 3 means that there is one for loop variable # length == 3 means that there is one for loop variable
# and thus no tuple unpacking: # and thus no tuple unpacking:
if iter.kind != tyTuple or length == 3: if iter.kind != tyTuple or length == 3:
@ -626,7 +627,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
# BUGFIX: don't use `iter` here as that would strip away # BUGFIX: don't use `iter` here as that would strip away
# the ``tyGenericInst``! See ``tests/compile/tgeneric.nim`` # the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
# for an example: # for an example:
v.typ = n.sons[length-2].typ v.typ = iterBase
n.sons[0] = newSymNode(v) n.sons[0] = newSymNode(v)
if sfGenSym notin v.flags: addForVarDecl(c, v) if sfGenSym notin v.flags: addForVarDecl(c, v)
else: else:
@ -664,7 +665,7 @@ proc semFor(c: PContext, n: PNode): PNode =
# first class iterator: # first class iterator:
result = semForVars(c, n) result = semForVars(c, n)
elif call.kind notin nkCallKinds or call.sons[0].kind != nkSym or elif call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
call.sons[0].sym.kind != skIterator: call.sons[0].sym.kind notin skIterators:
if length == 3: if length == 3:
n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2]) n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
elif length == 4: elif length == 4:
@ -997,8 +998,7 @@ proc activate(c: PContext, n: PNode) =
discard discard
proc maybeAddResult(c: PContext, s: PSym, n: PNode) = proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
if s.typ.sons[0] != nil and if s.typ.sons[0] != nil and s.kind != skIterator:
(s.kind != skIterator or s.typ.callConv == ccClosure):
addResult(c, s.typ.sons[0], n.info, s.kind) addResult(c, s.typ.sons[0], n.info, s.kind)
addResultNode(c, n) addResultNode(c, n)
@ -1073,12 +1073,12 @@ 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: if s.kind in skIterators:
s.typ.flags.incl(tfIterator) 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:
if s.kind == skIterator and isAnon: s.typ.callConv = ccClosure if s.kind == skClosureIterator: s.typ.callConv = ccClosure
else: s.typ.callConv = lastOptionEntry(c).defaultCC 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
@ -1138,7 +1138,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n.sons[bodyPos] = transformBody(c.module, semBody, s) n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c) popProcCon(c)
else: else:
if s.typ.sons[0] != nil and kind != skIterator: if s.typ.sons[0] != nil and kind notin skIterators:
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
var toBind = initIntSet() var toBind = initIntSet()
n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind) n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind)
@ -1165,7 +1165,10 @@ proc determineType(c: PContext, s: PSym) =
discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType) discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType)
proc semIterator(c: PContext, n: PNode): PNode = proc semIterator(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skIterator, iteratorPragmas) let kind = if hasPragma(n[pragmasPos], wClosure) or
n[namePos].kind == nkEmpty: skClosureIterator
else: skIterator
result = semProcAux(c, n, kind, iteratorPragmas)
var s = result.sons[namePos].sym var s = result.sons[namePos].sym
var t = s.typ var t = s.typ
if t.sons[0] == nil and s.typ.callConv != ccClosure: if t.sons[0] == nil and s.typ.callConv != ccClosure:

View file

@ -171,7 +171,7 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skUnknown: of skUnknown:
# Introduced in this pass! Leave it as an identifier. # Introduced in this pass! Leave it as an identifier.
result = n result = n
of skProc, skMethod, skIterator, skConverter, skTemplate, skMacro: of OverloadableSyms:
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skGenericParam: of skGenericParam:
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
@ -348,7 +348,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkMethodDef: of nkMethodDef:
result = semRoutineInTemplBody(c, n, skMethod) result = semRoutineInTemplBody(c, n, skMethod)
of nkIteratorDef: of nkIteratorDef:
result = semRoutineInTemplBody(c, n, skIterator) result = semRoutineInTemplBody(c, n, n[namePos].sym.kind)
of nkTemplateDef: of nkTemplateDef:
result = semRoutineInTemplBody(c, n, skTemplate) result = semRoutineInTemplBody(c, n, skTemplate)
of nkMacroDef: of nkMacroDef:

View file

@ -711,6 +711,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
for i in 0 .. paramType.sonsLen - 2: for i in 0 .. paramType.sonsLen - 2:
result.rawAddSon newTypeS(tyAnything, c) result.rawAddSon newTypeS(tyAnything, c)
# result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true)) # result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true))
if paramType.lastSon.kind == tyUserTypeClass:
result.kind = tyUserTypeClassInst
result.rawAddSon paramType.lastSon
return addImplicitGeneric(result)
result = instGenericContainer(c, paramType.sym.info, result, result = instGenericContainer(c, paramType.sym.info, result,
allowMetaTypes = true) allowMetaTypes = true)
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result]) result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
@ -845,8 +851,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
n.sons[0].info) n.sons[0].info)
if lifted != nil: r = lifted if lifted != nil: r = lifted
r.flags.incl tfRetType r.flags.incl tfRetType
result.sons[0] = skipIntLit(r) r = skipIntLit(r)
res.typ = result.sons[0] if kind == skIterator: r = newTypeWithSons(c, tyIter, @[r])
result.sons[0] = r
res.typ = r
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -951,6 +959,23 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
let typ = semTypeNode(c, n, nil) let typ = semTypeNode(c, n, nil)
result.sons.safeAdd(typ) result.sons.safeAdd(typ)
proc semProcTypeWithScope(c: PContext, n: PNode,
prev: PType, kind: TSymKind): PType =
checkSonsLen(n, 2)
openScope(c)
result = semProcTypeNode(c, n.sons[0], nil, prev, kind)
# dummy symbol for `pragma`:
var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c)
s.typ = result
if n.sons[1].kind == nkEmpty or n.sons[1].len == 0:
if result.callConv == ccDefault:
result.callConv = ccClosure
#Message(n.info, warnImplicitClosure, renderTree(n))
else:
pragma(c, s, n.sons[1], procTypePragmas)
when useEffectSystem: setEffectsForProcType(result, n.sons[1])
closeScope(c)
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil result = nil
if gCmd == cmdIdeTools: suggestExpr(c, n) if gCmd == cmdIdeTools: suggestExpr(c, n)
@ -959,7 +984,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkTypeOfExpr: of nkTypeOfExpr:
# for ``type(countup(1,3))``, see ``tests/ttoseq``. # for ``type(countup(1,3))``, see ``tests/ttoseq``.
checkSonsLen(n, 1) checkSonsLen(n, 1)
result = semExprWithType(c, n.sons[0], {efInTypeof}).typ result = semExprWithType(c, n.sons[0], {efInTypeof}).typ.skipTypes({tyIter})
of nkPar: of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else: else:
@ -1073,27 +1098,18 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
var base = semTypeNode(c, n.sons[0], nil) var base = semTypeNode(c, n.sons[0], nil)
result.rawAddSon(base) result.rawAddSon(base)
result.flags.incl tfHasStatic result.flags.incl tfHasStatic
of nkProcTy, nkIteratorTy: of nkIteratorTy:
if n.sonsLen == 0:
result = newConstraint(c, tyIter)
else:
result = semProcTypeWithScope(c, n, prev, skClosureIterator)
result.flags.incl(tfIterator)
result.callConv = ccClosure
of nkProcTy:
if n.sonsLen == 0: if n.sonsLen == 0:
result = newConstraint(c, tyProc) result = newConstraint(c, tyProc)
else: else:
checkSonsLen(n, 2) result = semProcTypeWithScope(c, n, prev, skProc)
openScope(c)
result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
# dummy symbol for `pragma`:
var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
s.typ = result
if n.sons[1].kind == nkEmpty or n.sons[1].len == 0:
if result.callConv == ccDefault:
result.callConv = ccClosure
#Message(n.info, warnImplicitClosure, renderTree(n))
else:
pragma(c, s, n.sons[1], procTypePragmas)
when useEffectSystem: setEffectsForProcType(result, n.sons[1])
closeScope(c)
if n.kind == nkIteratorTy:
result.flags.incl(tfIterator)
result.callConv = ccClosure
of nkEnumTy: result = semEnum(c, n, prev) of nkEnumTy: result = semEnum(c, n, prev)
of nkType: result = n.typ of nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev) of nkStmtListType: result = semStmtListType(c, n, prev)

View file

@ -410,7 +410,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
return isNone return isNone
when useEffectSystem: when useEffectSystem:
if not compatibleEffects(f, a): return isNone if not compatibleEffects(f, a): return isNone
of tyNil: result = f.allowsNil of tyNil:
result = f.allowsNil
of tyIter:
if tfIterator in f.flags: result = typeRel(c, f.base, a.base)
else: discard else: discard
proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
@ -922,13 +925,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else: else:
result = isNone result = isNone
of tyIter:
if a.kind == tyIter or
(a.kind == tyProc and tfIterator in a.flags):
result = typeRel(c, f.base, a.base)
else:
result = isNone
of tyStmt: of tyStmt:
result = isGeneric result = isGeneric
of tyProxy: of tyProxy:
result = isEqual result = isEqual
else: internalError("typeRel: " & $f.kind) else: internalAssert false
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
var m: TCandidate var m: TCandidate
@ -1138,7 +1148,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
z.calleeSym = m.calleeSym z.calleeSym = m.calleeSym
var best = -1 var best = -1
for i in countup(0, sonsLen(arg) - 1): for i in countup(0, sonsLen(arg) - 1):
if arg.sons[i].sym.kind in {skProc, skIterator, skMethod, skConverter}: if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
copyCandidate(z, m) copyCandidate(z, m)
var r = typeRel(z, f, arg.sons[i].typ) var r = typeRel(z, f, arg.sons[i].typ)
if r != isNone: if r != isNone:

View file

@ -113,7 +113,7 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
result[1] = ri result[1] = ri
proc transformSymAux(c: PTransf, n: PNode): PNode = proc transformSymAux(c: PTransf, n: PNode): PNode =
#if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure: #if n.sym.kind == skClosureIterator:
# return liftIterSym(n) # return liftIterSym(n)
var b: PNode var b: PNode
var tc = c.transCon var tc = c.transCon
@ -434,7 +434,6 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
var length = sonsLen(n) var length = sonsLen(n)
var call = n.sons[length - 2] var call = n.sons[length - 2]
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
call.sons[0].typ.callConv == ccClosure or
call.sons[0].sym.kind != skIterator: call.sons[0].sym.kind != skIterator:
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
return lambdalifting.liftForLoop(n).PTransNode return lambdalifting.liftForLoop(n).PTransNode
@ -454,7 +453,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
var newC = newTransCon(getCurrOwner(c)) var newC = newTransCon(getCurrOwner(c))
newC.forStmt = n newC.forStmt = n
newC.forLoopBody = loopBody newC.forLoopBody = loopBody
if iter.kind != skIterator: internalError(call.info, "transformFor") internalAssert iter.kind == skIterator
# generate access statements for the parameters (unless they are constant) # generate access statements for the parameters (unless they are constant)
pushTransCon(c, newC) pushTransCon(c, newC)
for i in countup(1, sonsLen(call) - 1): for i in countup(1, sonsLen(call) - 1):
@ -741,7 +740,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
var c = openTransf(module, "") var c = openTransf(module, "")
result = processTransf(c, n, prc) result = processTransf(c, n, prc)
result = liftLambdas(prc, result) result = liftLambdas(prc, result)
#if prc.kind == skIterator and prc.typ.callConv == ccClosure: #if prc.kind == skClosureIterator:
# result = lambdalifting.liftIterator(prc, result) # result = lambdalifting.liftIterator(prc, result)
incl(result.flags, nfTransf) incl(result.flags, nfTransf)
when useEffectSystem: trackProc(prc, result) when useEffectSystem: trackProc(prc, result)

View file

@ -1247,7 +1247,7 @@ proc computeSize(typ: PType): BiggestInt =
proc getReturnType*(s: PSym): PType = proc getReturnType*(s: PSym): PType =
# Obtains the return type of a iterator/proc/macro/template # Obtains the return type of a iterator/proc/macro/template
assert s.kind in {skProc, skTemplate, skMacro, skIterator} assert s.kind in skProcKinds
result = s.typ.sons[0] result = s.typ.sons[0]
proc getSize(typ: PType): BiggestInt = proc getSize(typ: PType): BiggestInt =

View file

@ -1330,7 +1330,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
case s.kind case s.kind
of skVar, skForVar, skTemp, skLet, skParam, skResult: of skVar, skForVar, skTemp, skLet, skParam, skResult:
genRdVar(c, n, dest, flags) genRdVar(c, n, dest, flags)
of skProc, skConverter, skMacro, skTemplate, skMethod, skIterator: of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators:
# 'skTemplate' is only allowed for 'getAst' support: # 'skTemplate' is only allowed for 'getAst' support:
if sfImportc in s.flags: c.importcSym(n.info, s) if sfImportc in s.flags: c.importcSym(n.info, s)
genLit(c, n, dest) genLit(c, n, dest)

View file

@ -279,8 +279,8 @@ skForVar
col 7: "" col 7: ""
skIterator skIterator, skClosureIterator
---------- -----------------------------
The fourth column will be the empty string if the iterator is being The fourth column will be the empty string if the iterator is being
defined, since at that point in the file the parser hasn't processed defined, since at that point in the file the parser hasn't processed

View file

@ -3481,7 +3481,7 @@ Declarative type classes are written in the following form:
c.len is ordinal c.len is ordinal
items(c) is iterator items(c) is iterator
for value in c: for value in c:
type(value) is T value.type is T
The type class will be matched if: The type class will be matched if:

View file

@ -88,7 +88,7 @@ type
nskUnknown, nskConditional, nskDynLib, nskParam, nskUnknown, nskConditional, nskDynLib, nskParam,
nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet, nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet,
nskConst, nskResult, nskConst, nskResult,
nskProc, nskMethod, nskIterator, nskProc, nskMethod, nskIterator, nskClosureIterator,
nskConverter, nskMacro, nskTemplate, nskField, nskConverter, nskMacro, nskTemplate, nskField,
nskEnumField, nskForVar, nskLabel, nskEnumField, nskForVar, nskLabel,
nskStub nskStub

View file

@ -373,5 +373,8 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
# define GC_GUARD # define GC_GUARD
#endif #endif
/* Test to see if nimrod and the C compiler agrees on the size of a pointer.
On disagreement, your C compiler will say something like:
"error: 'assert_numbits' declared as an array with a negative size" */
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1]; typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
#endif #endif

View file

@ -1164,6 +1164,14 @@ when not defined(nimrodVM):
## from it before writing to it is undefined behaviour! ## from it before writing to it is undefined behaviour!
## The allocated memory belongs to its allocating thread! ## The allocated memory belongs to its allocating thread!
## Use `allocShared` to allocate from a shared heap. ## Use `allocShared` to allocate from a shared heap.
proc alloc*(T: typedesc, size = 1): ptr T {.inline.} =
## allocates a new memory block with at least ``T.sizeof * size``
## bytes. The block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is not initialized, so reading
## from it before writing to it is undefined behaviour!
## The allocated memory belongs to its allocating thread!
## Use `allocShared` to allocate from a shared heap.
cast[ptr T](alloc(T.sizeof * size))
proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].} proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].}
## allocates a new memory block with at least ``size`` bytes. The ## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or ## block has to be freed with ``realloc(block, 0)`` or
@ -1171,14 +1179,31 @@ when not defined(nimrodVM):
## containing zero, so it is somewhat safer than ``alloc``. ## containing zero, so it is somewhat safer than ``alloc``.
## The allocated memory belongs to its allocating thread! ## The allocated memory belongs to its allocating thread!
## Use `allocShared0` to allocate from a shared heap. ## Use `allocShared0` to allocate from a shared heap.
proc realloc*(p: pointer, newsize: int): pointer {.noconv, rtl, tags: [].} proc alloc0*(T: typedesc, size = 1): ptr T {.inline.} =
## allocates a new memory block with at least ``T.sizeof * size``
## bytes. The block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is initialized with all bytes
## containing zero, so it is somewhat safer than ``alloc``.
## The allocated memory belongs to its allocating thread!
## Use `allocShared0` to allocate from a shared heap.
cast[ptr T](alloc0(T.sizeof * size))
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [].}
## grows or shrinks a given memory block. If p is **nil** then a new ## grows or shrinks a given memory block. If p is **nil** then a new
## memory block is returned. In either way the block has at least ## memory block is returned. In either way the block has at least
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil** ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
## ``realloc`` calls ``dealloc(p)``. In other cases the block has to ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
## be freed with ``dealloc``. ## be freed with ``dealloc``.
## The allocated memory belongs to its allocating thread! ## The allocated memory belongs to its allocating thread!
## Use `reallocShared` to reallocate from a shared heap. ## Use `reallocShared` to reallocate from a shared heap.
proc reallocType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
## grows or shrinks a given memory block. If p is **nil** then a new
## memory block is returned. In either way the block has at least
## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not
## **nil** ``realloc`` calls ``dealloc(p)``. In other cases the block
## has to be freed with ``dealloc``. The allocated memory belongs to
## its allocating thread!
## Use `reallocShared` to reallocate from a shared heap.
cast[ptr T](realloc(p, T.sizeof * newSize))
proc dealloc*(p: pointer) {.noconv, rtl, tags: [].} proc dealloc*(p: pointer) {.noconv, rtl, tags: [].}
## frees the memory allocated with ``alloc``, ``alloc0`` or ## frees the memory allocated with ``alloc``, ``alloc0`` or
## ``realloc``. This procedure is dangerous! If one forgets to ## ``realloc``. This procedure is dangerous! If one forgets to
@ -1187,25 +1212,45 @@ when not defined(nimrodVM):
## or other memory may be corrupted. ## or other memory may be corrupted.
## The freed memory must belong to its allocating thread! ## The freed memory must belong to its allocating thread!
## Use `deallocShared` to deallocate from a shared heap. ## Use `deallocShared` to deallocate from a shared heap.
proc allocShared*(size: int): pointer {.noconv, rtl.} proc allocShared*(size: int): pointer {.noconv, rtl.}
## allocates a new memory block on the shared heap with at ## allocates a new memory block on the shared heap with at
## least ``size`` bytes. The block has to be freed with ## least ``size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
## is not initialized, so reading from it before writing to it is ## is not initialized, so reading from it before writing to it is
## undefined behaviour! ## undefined behaviour!
proc allocShared*(T: typedesc, size: int): ptr T {.inline.} =
## allocates a new memory block on the shared heap with at
## least ``T.sizeof * size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
## is not initialized, so reading from it before writing to it is
## undefined behaviour!
cast[ptr T](allocShared(T.sizeof * size))
proc allocShared0*(size: int): pointer {.noconv, rtl.} proc allocShared0*(size: int): pointer {.noconv, rtl.}
## allocates a new memory block on the shared heap with at ## allocates a new memory block on the shared heap with at
## least ``size`` bytes. The block has to be freed with ## least ``size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
## The block is initialized with all bytes ## The block is initialized with all bytes
## containing zero, so it is somewhat safer than ``allocShared``. ## containing zero, so it is somewhat safer than ``allocShared``.
proc reallocShared*(p: pointer, newsize: int): pointer {.noconv, rtl.} proc allocShared0*(T: typedesc, size: int): ptr T {.inline.} =
## allocates a new memory block on the shared heap with at
## least ``T.sizeof * size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
## The block is initialized with all bytes
## containing zero, so it is somewhat safer than ``allocShared``.
cast[ptr T](allocShared(T.sizeof * size))
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl.}
## grows or shrinks a given memory block on the heap. If p is **nil** ## grows or shrinks a given memory block on the heap. If p is **nil**
## then a new memory block is returned. In either way the block has at least ## then a new memory block is returned. In either way the block has at
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil** ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
## ``reallocShared`` calls ``deallocShared(p)``. In other cases the ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
## block has to be freed with ``deallocShared``. ## block has to be freed with ``deallocShared``.
proc reallocSharedType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
## grows or shrinks a given memory block on the heap. If p is **nil**
## then a new memory block is returned. In either way the block has at
## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is
## not **nil** ``reallocShared`` calls ``deallocShared(p)``. In other
## cases the block has to be freed with ``deallocShared``.
cast[ptr T](reallocShared(p, T.sizeof * newSize))
proc deallocShared*(p: pointer) {.noconv, rtl.} proc deallocShared*(p: pointer) {.noconv, rtl.}
## frees the memory allocated with ``allocShared``, ``allocShared0`` or ## frees the memory allocated with ``allocShared``, ``allocShared0`` or
## ``reallocShared``. This procedure is dangerous! If one forgets to ## ``reallocShared``. This procedure is dangerous! If one forgets to

View file

@ -299,12 +299,12 @@ proc open*(address: string, server: bool, mode: TConnectionMode = conDEALER,
else: else:
if connect(result.s, address) != 0'i32: zmqError() if connect(result.s, address) != 0'i32: zmqError()
proc close*(c: var TConnection) = proc close*(c: TConnection) =
## closes the connection. ## closes the connection.
if close(c.s) != 0'i32: zmqError() if close(c.s) != 0'i32: zmqError()
if term(c.c) != 0'i32: zmqError() if term(c.c) != 0'i32: zmqError()
proc send*(c: var TConnection, msg: string) = proc send*(c: TConnection, msg: string) =
## sends a message over the connection. ## sends a message over the connection.
var m: TMsg var m: TMsg
if msg_init(m, msg.len) != 0'i32: zmqError() if msg_init(m, msg.len) != 0'i32: zmqError()
@ -312,7 +312,7 @@ proc send*(c: var TConnection, msg: string) =
if send(c.s, m, 0'i32) != 0'i32: zmqError() if send(c.s, m, 0'i32) != 0'i32: zmqError()
discard msg_close(m) discard msg_close(m)
proc receive*(c: var TConnection): string = proc receive*(c: TConnection): string =
## receives a message from a connection. ## receives a message from a connection.
var m: TMsg var m: TMsg
if msg_init(m) != 0'i32: zmqError() if msg_init(m) != 0'i32: zmqError()
@ -320,4 +320,3 @@ proc receive*(c: var TConnection): string =
result = newString(msg_size(m)) result = newString(msg_size(m))
copyMem(addr(result[0]), msg_data(m), result.len) copyMem(addr(result[0]), msg_data(m), result.len)
discard msg_close(m) discard msg_close(m)

View file

@ -8,7 +8,7 @@ discard """
""" """
proc factory(a, b: int): iterator (): int = proc factory(a, b: int): iterator (): int =
iterator foo(): int = iterator foo(): int {.closure.} =
var x = a var x = a
while x <= b: while x <= b:
yield x yield x

View file

@ -0,0 +1,43 @@
discard """
output: '''1
2
3
4
5
6
a
b
t
e
s
t
'''
"""
template accept(e: expr) =
static: assert compiles(e)
template reject(e: expr) =
static: assert(not compiles(e))
type
Container[T] = generic C
C.len is Ordinal
items(c) is iterator
for value in C:
value.type is T
proc takesIntContainer(c: Container[int]) =
for e in c: echo e
takesIntContainer(@[1, 2, 3])
reject takesIntContainer(@["x", "y"])
proc takesContainer(c: Container) =
for e in c: echo e
takesContainer(@[4, 5, 6])
takesContainer(@["a", "b"])
takesContainer "test"
reject takesContainer(10)

45
tests/system/alloc.nim Normal file
View file

@ -0,0 +1,45 @@
var x: ptr int
x = cast[ptr int](alloc(7))
assert x != nil
x = alloc(int, 3)
assert x != nil
x.dealloc()
x = alloc0(int, 4)
assert cast[ptr array[4, int]](x)[0] == 0
assert cast[ptr array[4, int]](x)[1] == 0
assert cast[ptr array[4, int]](x)[2] == 0
assert cast[ptr array[4, int]](x)[3] == 0
x = cast[ptr int](x.realloc(2))
assert x != nil
x = x.reallocType(4)
assert x != nil
x.dealloc()
x = cast[ptr int](allocShared(100))
assert x != nil
deallocShared(x)
x = allocShared(int, 3)
assert x != nil
x.deallocShared()
x = allocShared0(int, 3)
assert x != nil
assert cast[ptr array[3, int]](x)[0] == 0
assert cast[ptr array[3, int]](x)[1] == 0
assert cast[ptr array[3, int]](x)[2] == 0
x = cast[ptr int](reallocShared(x, 2))
assert x != nil
x = reallocType(x, 12)
assert x != nil
x = reallocSharedType(x, 1)
assert x != nil
x.deallocShared()

View file

@ -1,5 +1,5 @@
discard """ discard """
output: "true true false yes" output: '''true true false yes'''
""" """
proc IsVoid[T](): string = proc IsVoid[T](): string =
@ -11,3 +11,26 @@ proc IsVoid[T](): string =
const x = int is int const x = int is int
echo x, " ", float is float, " ", float is string, " ", IsVoid[void]() echo x, " ", float is float, " ", float is string, " ", IsVoid[void]()
template yes(e: expr): stmt =
static: assert e
template no(e: expr): stmt =
static: assert(not e)
var s = @[1, 2, 3]
yes s.items is iterator
no s.items is proc
yes s.items is iterator: int
no s.items is iterator: float
yes s.items is iterator: TNumber
no s.items is iterator: object
type
Iter[T] = iterator: T
yes s.items is Iter[TNumber]
no s.items is Iter[float]