merged branch overloading-for-macros

This commit is contained in:
Zahary Karadjov
2012-03-19 12:06:38 +02:00
39 changed files with 366 additions and 218 deletions

View File

@@ -227,6 +227,9 @@ type
sfInnerProc, # proc is an inner proc
sfThread, # proc will run as a thread
# variable is a thread variable
sfInline # forced-inline procs
sfImmediate, # macro or template is immediately expanded without
# considering any possible overloads
sfCompileTime, # proc can be evaluated at compile time
sfMerge, # proc can be merged with itself
sfDeadCodeElim, # dead code elimination for the module is turned on
@@ -602,7 +605,8 @@ type
# the poor naming choices in the standard library.
const
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter, skModule}
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter,
skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
tyGenericParam}

View File

@@ -567,6 +567,19 @@ proc StrTableRawInsert(data: var TSymSeq, n: PSym) =
assert(data[h] == nil)
data[h] = n
proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
assert prevSym.name.h == newSym.name.h
var h: THash = prevSym.name.h and high(data)
while data[h] != nil:
if data[h] == prevSym:
data[h] = newSym
return
h = nextTry(h, high(data))
assert false
proc SymTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
SymTabReplaceRaw(t.data, prevSym, newSym)
proc StrTableEnlarge(t: var TStrTable) =
var n: TSymSeq
newSeq(n, len(t.data) * growthFactor)

View File

@@ -10,7 +10,8 @@
proc leftAppearsOnRightSide(le, ri: PNode): bool =
if le != nil:
for i in 1 .. <ri.len:
if le.isPartOf(ri[i]) != arNo: return true
let r = ri[i]
if isPartOf(le, r) != arNo: return true
proc hasNoInit(call: PNode): bool {.inline.} =
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags

View File

@@ -164,7 +164,7 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
result = nil
if result != nil and result.kind == skStub: loadStub(result)
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
@@ -174,7 +174,7 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
dec(o.stackPtr)
if o.stackPtr < 0: break
result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], ident)
of nkSym:
of nkSym:
result = n.sym
o.mode = oimDone
of nkDotExpr:
@@ -204,6 +204,13 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
Incl(o.inSymChoice, result.id)
else: nil
if result != nil and result.kind == skStub: loadStub(result)
proc lastOverloadScope*(o: TOverloadIter): int =
case o.mode
of oimNoQualifier: result = o.stackPtr
of oimSelfModule: result = ModuleTablePos
of oimOtherModule: result = ImportTablePos
else: result = -1
proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case o.mode

View File

@@ -26,8 +26,9 @@ const
wNoStackFrame, wError, wDiscardable, wNoInit}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
templatePragmas* = {wImmediate}
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
@@ -451,6 +452,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, sym.name.s))
of wExtern: setExternName(sym, expectStrLit(c, it))
of wImmediate:
if sym.kind notin {skTemplate, skMacro}: invalidPragma(it)
incl(sym.flags, sfImmediate)
of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, sym.name.s))
of wImportObjC:

View File

@@ -10,11 +10,11 @@
# This module implements the semantic checking pass.
import
strutils, hashes, lists, options, lexer, ast, astalgo, trees, treetab,
ast, strutils, hashes, lists, options, lexer, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
magicsys, parser, nversion, semdata, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest,
semthreads, intsets, transf, evals, idgen, aliases
magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
suggest, semthreads, intsets, transf, evals, idgen, aliases
proc semPass*(): TPass
# implementation
@@ -75,17 +75,20 @@ proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
include semtempl
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
GlobalError(n.info, errConstExprExpected)
return nil
proc evalTypedExpr(c: PContext, e: PNode): PNode =
result = getConstExpr(c.module, e)
if result == nil:
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
GlobalError(n.info, errConstExprExpected)
if result == nil or result.kind == nkEmpty:
GlobalError(e.info, errConstExprExpected)
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
GlobalError(n.info, errConstExprExpected)
return nil
result = evalTypedExpr(c, e)
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
result = semConstExpr(c, n)

View File

@@ -8,6 +8,7 @@
#
## This module implements semantic checking for calls.
# included from sem.nim
proc sameMethodDispatcher(a, b: PSym): bool =
result = false
@@ -17,70 +18,78 @@ proc sameMethodDispatcher(a, b: PSym): bool =
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
result = true
proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
initialBinding: PNode): PNode =
var
o: TOverloadIter
x, y, z: TCandidate
#Message(n.info, warnUser, renderTree(n))
var sym = initOverloadIter(o, c, f)
result = nil
if sym == nil: return
initCandidate(x, sym, initialBinding)
initCandidate(y, sym, initialBinding)
while sym != nil:
if sym.kind in filter:
initCandidate(z, sym, initialBinding)
z.calleeSym = sym
matches(c, n, z)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
case x.state
of csEmpty, csNoMatch: x = z
of csMatch:
var cmp = cmpCandidates(x, z)
if cmp < 0: x = z # z is better than x
elif cmp == 0: y = z # z is as good as x
else: nil
sym = nextOverloadIter(o, c, f)
if x.state == csEmpty:
# no overloaded proc found
# do not generate an error yet; the semantic checking will check for
# an overloaded () operator
elif y.state == csMatch and cmpCandidates(x, y) == 0 and
not sameMethodDispatcher(x.calleeSym, y.calleeSym):
if x.state != csMatch:
InternalError(n.info, "x.state is not csMatch")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
x.calleeSym.Name.s])
else:
# only one valid interpretation found:
markUsed(n, x.calleeSym)
if x.calleeSym.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty:
# a generic proc!
x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
x.callee = x.calleeSym.typ
result = x.call
result.sons[0] = newSymNode(x.calleeSym)
result.typ = x.callee.sons[0]
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
# process the bindings once:
proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds): TCandidate =
var initialBinding: PNode
var f = n.sons[0]
if f.kind == nkBracketExpr:
# fill in the bindings:
initialBinding = f
f = f.sons[0]
else:
else:
initialBinding = nil
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
var
o: TOverloadIter
alt, z: TCandidate
template best: expr = result
#Message(n.info, warnUser, renderTree(n))
var sym = initOverloadIter(o, c, f)
var symScope = o.lastOverloadScope
if sym == nil: return
initCandidate(best, sym, initialBinding, symScope)
initCandidate(alt, sym, initialBinding, symScope)
while sym != nil:
if sym.kind in filter:
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
z.calleeSym = sym
matches(c, n, orig, z)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
case best.state
of csEmpty, csNoMatch: best = z
of csMatch:
var cmp = cmpCandidates(best, z)
if cmp < 0: best = z # x is better than the best so far
elif cmp == 0: alt = z # x is as good as the best so far
else: nil
sym = nextOverloadIter(o, c, f)
if best.state == csEmpty:
# no overloaded proc found
# do not generate an error yet; the semantic checking will check for
# an overloaded () operator
elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
if best.state != csMatch:
InternalError(n.info, "x.state is not csMatch")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
best.calleeSym.Name.s])
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
assert x.state == csMatch
var finalCallee = x.calleeSym
markUsed(n, finalCallee)
if finalCallee.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
# a generic proc!
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
result = x.call
result.sons[0] = newSymNode(finalCallee)
result.typ = finalCallee.typ.sons[0]
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode =
var r = resolveOverloads(c, n, nOrig, filter)
if r.state == csMatch: result = semResolvedCall(c, n, r)
proc explicitGenericInstError(n: PNode): PNode =
LocalError(n.info, errCannotInstantiateX, renderTree(n))
result = n

View File

@@ -73,7 +73,7 @@ type
userPragmas*: TStrTable
evalContext*: PEvalContext
slurpedFiles*: seq[string]
var
gGenericsCache: PGenericsCache # save for modularity

View File

@@ -8,6 +8,7 @@
#
# this module does the semantic checking for expressions
# included from sem.nim
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s)
@@ -103,7 +104,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
if s.ast == nil: InternalError(n.info, "no default for")
result = semExpr(c, s.ast)
of skType:
if efAllowType notin flags: GlobalError(n.info, errATypeHasNoValue)
if efAllowType notin flags:
GlobalError(n.info, errATypeHasNoValue)
markUsed(n, s)
result = newSymNode(s, n.info)
else:
@@ -245,17 +247,17 @@ proc semIs(c: PContext, n: PNode): PNode =
else:
GlobalError(n.info, errXExpectsTwoArguments, "is")
proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - 1):
proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
a.sons[1] = semExprWithType(c, a.sons[1])
a.sons[1] = semExprWithType(c, a.sons[1], {efAllowType})
a.typ = a.sons[1].typ
else:
n.sons[i] = semExprWithType(c, a)
else:
n.sons[i] = semExprWithType(c, a, {efAllowType})
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded:
var par = getIdent("()")
@@ -514,25 +516,32 @@ proc semStaticExpr(c: PContext, n: PNode): PNode =
if result.isNil:
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
flags: TExprFlags): PNode =
proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
flags: TExprFlags): PNode =
if efWantIterator in flags:
result = semDirectCall(c, n, {skIterator})
result = semOverloadedCall(c, n, nOrig, {skIterator})
elif efInTypeOf in flags:
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
result = semDirectCall(c, n, {skIterator, skProc, skMethod, skConverter})
result = semOverloadedCall(c, n, nOrig, {skIterator, skProc, skMethod, skConverter, skMacro, skTemplate})
else:
result = semDirectCall(c, n, {skProc, skMethod, skConverter})
result = semOverloadedCall(c, n, nOrig, {skProc, skMethod, skConverter, skMacro, skTemplate})
if result != nil:
if result.sons[0].kind != nkSym:
InternalError("semDirectCallAnalyseEffects")
var callee = result.sons[0].sym
if (callee.kind == skIterator) and (callee.id == c.p.owner.id):
GlobalError(n.info, errRecursiveDependencyX, callee.name.s)
if sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * callee.flags != {}:
incl(c.p.owner.flags, sfSideEffect)
let callee = result.sons[0].sym
case callee.kind
of skMacro, skTemplate: nil
else:
if (callee.kind == skIterator) and (callee.id == c.p.owner.id):
GlobalError(n.info, errRecursiveDependencyX, callee.name.s)
if sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * callee.flags != {}:
incl(c.p.owner.flags, sfSideEffect)
proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
flags: TExprFlags): PNode =
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil
var prc = n.sons[0]
@@ -548,13 +557,14 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return semExpr(c, result, flags)
else:
n.sons[0] = semExpr(c, n.sons[0])
let nOrig = n.copyTree
semOpAux(c, n)
var t: PType = nil
if (n.sons[0].typ != nil): t = skipTypes(n.sons[0].typ, abstractInst)
if (t != nil) and (t.kind == tyProc):
var m: TCandidate
initCandidate(m, t)
matches(c, n, m)
matches(c, n, nOrig, m)
if m.state != csMatch:
var msg = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1):
@@ -575,7 +585,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# the old ``prc`` (which is likely an nkIdent) has to be restored:
if result == nil:
n.sons[0] = prc
result = semDirectCallAnalyseEffects(c, n, flags)
nOrig.sons[0] = prc
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil:
GlobalError(n.info, errExprXCannotBeCalled,
renderTree(n, {renderNoComments}))
@@ -587,15 +598,21 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this seems to be a hotspot in the compiler!
let nOrig = n.copyTree
semOpAux(c, n)
result = semDirectCallAnalyseEffects(c, n, flags)
if result == nil:
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil:
result = overloadedCallOpr(c, n)
if result == nil: GlobalError(n.Info, errGenerated, getNotFoundError(c, n))
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if result.sons[0].sym.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
let callee = result.sons[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, nOrig, callee)
else:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
result = evalAtCompileTime(c, result)
proc buildStringify(c: PContext, arg: PNode): PNode =
@@ -734,7 +751,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.typ = ty
markUsed(n, f)
return
elif efAllowType notin flags:
elif efAllowType notin flags:
GlobalError(n.sons[0].info, errATypeHasNoValue)
return
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
@@ -852,16 +869,16 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# overloaded [] operator:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
proc propertyWriteAccess(c: PContext, n, a: PNode): PNode =
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerAcc(a[1])
result = newNodeI(nkCall, n.info)
addSon(result, newIdentNode(getIdent(id.s & '='), n.info))
let setterId = newIdentNode(getIdent(id.s & '='), n.info)
# a[0] is already checked for semantics, that does ``builtinFieldAccess``
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes?
addSon(result, a[0])
addSon(result, semExpr(c, n[1]))
result = semDirectCallAnalyseEffects(c, result, {})
let aOrig = nOrig[0]
result = newNode(nkCall, n.info, sons = @[setterId, a[0], semExpr(c, n[1])])
let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
result = semDirectCallAnalyseEffects(c, result, orig, {})
if result != nil:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
@@ -898,9 +915,10 @@ proc semAsgn(c: PContext, n: PNode): PNode =
of nkDotExpr:
# r.f = x
# --> `f=` (r, x)
let nOrig = n.copyTree
a = builtinFieldAccess(c, a, {efLValue})
if a == nil:
return propertyWriteAccess(c, n, n[0])
return propertyWriteAccess(c, n, nOrig, a)
of nkBracketExpr:
# a[i] = x
# --> `[]=`(a, i, x)
@@ -1275,8 +1293,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
if s != nil:
case s.kind
of skMacro: result = semMacroExpr(c, n, s)
of skTemplate: result = semTemplateExpr(c, n, s)
of skMacro:
if false and sfImmediate notin s.flags: # XXX not yet enabled
result = semDirectOp(c, n, flags)
else:
result = semMacroExpr(c, n, s)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semTemplateExpr(c, n, s)
of skType:
# XXX think about this more (``set`` procs)
if n.len == 2:

View File

@@ -8,6 +8,7 @@
#
## this module does the semantic checking of statements
# included from sem.nim
proc semCommand(c: PContext, n: PNode): PNode =
result = semExprNoType(c, n)
@@ -690,8 +691,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n.sons[genericParamsPos] = gp
# check for semantics again:
semParamList(c, n.sons[ParamsPos], nil, s)
# XXX: obsoleted - happens in semParamList
# addParams(c, s.typ.n)
else:
s.typ = newTypeS(tyProc, c)
addSon(s.typ, nil)

View File

@@ -7,6 +7,8 @@
# distribution, for details about the copyright.
#
# included from sem.nim
proc isExpr(n: PNode): bool =
# returns true if ``n`` looks like an expression
case n.kind
@@ -54,11 +56,6 @@ proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode =
else: arg = copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
LocalError(n.info, errWrongNumberOfArguments)
elif not (s.typ.sons[i].kind in {tyTypeDesc, tyStmt, tyExpr}):
# concrete type means semantic checking for argument:
# XXX This is horrible! Better make semantic checking use some kind
# of fixpoint iteration ...
arg = fitNode(c, s.typ.sons[i], semExprWithType(c, arg))
addSon(result, arg)
proc evalTemplate*(c: PContext, n: PNode, sym: PSym): PNode =
@@ -167,9 +164,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# check parameter list:
pushOwner(s)
openScope(c.tab)
n.sons[namePos] = newSymNode(s) # check that no pragmas exist:
if n.sons[pragmasPos].kind != nkEmpty:
LocalError(n.info, errNoPragmasAllowedForX, "template")
n.sons[namePos] = newSymNode(s)
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], templatePragmas)
# check that no generic parameters exist:
if n.sons[genericParamsPos].kind != nkEmpty:
LocalError(n.info, errNoGenericParamsAllowedForX, "template")
@@ -185,8 +182,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# use ``stmt`` as implicit result type
s.typ.sons[0] = newTypeS(tyStmt, c)
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
# XXX: obsoleted - happens in semParamList #
# addParams(c, s.typ.n) # resolve parameters:
var toBind = initIntSet()
n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], false, toBind)
if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
@@ -198,5 +193,10 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
result = n
if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s)
# add identifier of template as a last step to not allow recursive templates:
addInterfaceDecl(c, s)
let curScope = c.tab.tos - 1
var proto = SearchForProc(c, s, curScope)
if proto == nil:
addInterfaceOverloadableSymAt(c, s, curScope)
else:
SymTabReplace(c.tab.stack[curScope], proto, s)

View File

@@ -8,6 +8,7 @@
#
# 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:

View File

@@ -17,6 +17,7 @@ import
type
TCandidateState* = enum
csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object
exactMatches*: int
subtypeMatches: int
@@ -26,6 +27,7 @@ type
state*: TCandidateState
callee*: PType # may not be nil!
calleeSym*: PSym # may be nil
calleeScope: int # may be -1 for unknown scope
call*: PNode # modified call
bindings*: TIdTable # maps types to types
baseTypeMatch: bool # needed for conversions from T to openarray[T]
@@ -35,7 +37,7 @@ type
isNone, isConvertible, isIntConv, isSubtype,
isGeneric,
isEqual
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
c.exactMatches = 0
c.subtypeMatches = 0
@@ -59,9 +61,10 @@ proc put(t: var TIdTable, key, val: PType) {.inline.} =
IdentEq(val.sym.name, "TTable"):
assert false
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode) =
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) =
initCandidateAux(c, callee.typ)
c.calleeSym = callee
c.calleeScope = calleeScope
initIdTable(c.bindings)
if binding != nil:
var typeParams = callee.ast[genericParamsPos]
@@ -93,6 +96,9 @@ proc cmpCandidates*(a, b: TCandidate): int =
result = a.intConvMatches - b.intConvMatches
if result != 0: return
result = a.convMatches - b.convMatches
if result != 0: return
if (a.calleeScope != -1) and (b.calleeScope != -1):
result = a.calleeScope - b.calleeScope
proc writeMatches(c: TCandidate) =
Writeln(stdout, "exact matches: " & $c.exactMatches)
@@ -101,10 +107,10 @@ proc writeMatches(c: TCandidate) =
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
Writeln(stdout, "generic matches: " & $c.genericMatches)
proc getNotFoundError*(c: PContext, n: PNode): string =
# Gives a detailed error message; this is separated from semDirectCall,
# as semDirectCall is already pretty slow (and we need this information only
# in case of an error).
proc getNotFoundError*(c: PContext, n: PNode): string =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
result = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1):
#debug(n.sons[i].typ)
@@ -507,7 +513,10 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
return
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode =
arg, argOrig: PNode): PNode =
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate} and
f.kind in {tyExpr, tyStmt, tyTypeDesc}:
return argOrig
var r = typeRel(m.bindings, f, a)
case r
of isConvertible:
@@ -547,9 +556,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
result = userConvMatch(c, m, base(f), a, arg)
proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode =
arg, argOrig: PNode): PNode =
if arg == nil or arg.kind != nkSymChoice:
result = ParamTypesMatchAux(c, m, f, a, arg)
result = ParamTypesMatchAux(c, m, f, a, arg, argOrig)
else:
# CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement
@@ -591,29 +600,29 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
else:
# only one valid interpretation found:
markUsed(arg, arg.sons[best].sym)
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best])
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best], argOrig)
proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, a, arg)
result = paramTypesMatch(c, m, f, a, arg, nil)
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, n.typ, n)
result = paramTypesMatch(c, m, f, n.typ, n, nil)
proc argtypeMatches*(c: PContext, f, a: PType): bool =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, a, ast.emptyNode) != nil
result = paramTypesMatch(c, m, f, a, ast.emptyNode, nil) != nil
proc setSon(father: PNode, at: int, son: PNode) =
if sonsLen(father) <= at: setlen(father.sons, at + 1)
father.sons[at] = son
proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
marker: var TIntSet) =
proc matchesAux*(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var TIntSet) =
var f = 1 # iterates over formal parameters
var a = 1 # iterates over the actual given arguments
m.state = csMatch # until proven otherwise
@@ -623,7 +632,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
addSon(m.call, copyTree(n.sons[0]))
var container: PNode = nil # constructed container
var formal: PSym = nil
while a < sonsLen(n):
while a < n.len:
if n.sons[a].kind == nkExprEqExpr:
# named param
# check if m.callee has such a param:
@@ -642,8 +651,8 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
m.state = csNoMatch
return
m.baseTypeMatch = false
var arg = ParamTypesMatch(c, m, formal.typ,
n.sons[a].typ, n.sons[a].sons[1])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a].sons[1], nOrig.sons[a].sons[1])
if arg == nil:
m.state = csNoMatch
return
@@ -666,9 +675,10 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
copyTree(n.sons[a]), m, c))
else:
addSon(m.call, copyTree(n.sons[a]))
elif formal != nil:
elif formal != nil:
m.baseTypeMatch = false
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if (arg != nil) and m.baseTypeMatch and (container != nil):
addSon(container, arg)
else:
@@ -687,7 +697,8 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
m.state = csNoMatch
return
m.baseTypeMatch = false
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if arg == nil:
m.state = csNoMatch
return
@@ -703,14 +714,14 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
inc(a)
inc(f)
proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) =
proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# for 'suggest' support:
var marker = initIntSet()
matchesAux(c, n, m, marker)
matchesAux(c, n, nOrig, m, marker)
proc matches*(c: PContext, n: PNode, m: var TCandidate) =
proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
var marker = initIntSet()
matchesAux(c, n, m, marker)
matchesAux(c, n, nOrig, m, marker)
if m.state == csNoMatch: return
# check that every formal parameter got a value:
var f = 1

View File

@@ -46,7 +46,7 @@ proc suggestField(s: PSym) =
if filterSym(s):
OutWriteln(SymToStr(s, isLocal=true, sectionSuggest))
template wholeSymTab(cond, section: expr) =
template wholeSymTab(cond, section: expr) {.immediate.} =
for i in countdown(c.tab.tos-1, 0):
for it in items(c.tab.stack[i]):
if cond:
@@ -79,20 +79,18 @@ proc nameFits(c: PContext, s: PSym, n: PNode): bool =
else: return false
result = opr.id == s.name.id
proc argsFit(c: PContext, candidate: PSym, n: PNode): bool =
proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
case candidate.kind
of skProc, skIterator, skMethod:
of OverloadableSyms:
var m: TCandidate
initCandidate(m, candidate, nil)
sigmatch.partialMatch(c, n, m)
sigmatch.partialMatch(c, n, nOrig, m)
result = m.state != csNoMatch
of skTemplate, skMacro:
result = true
else:
result = false
proc suggestCall(c: PContext, n: PNode) =
wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n),
proc suggestCall(c: PContext, n, nOrig: PNode) =
wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
sectionContext)
proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
@@ -227,7 +225,7 @@ proc suggestExpr*(c: PContext, node: PNode) =
var x = safeSemExpr(c, n.sons[i])
if x.kind == nkEmpty or x.typ == nil: break
addSon(a, x)
suggestCall(c, a)
suggestCall(c, a, n)
if optDef in gGlobalOptions:
var n = findClosestSym(fuzzySemCheck(c, node))

View File

@@ -36,7 +36,7 @@ type
wColon, wColonColon, wEquals, wDot, wDotDot,
wStar, wMinus,
wMagic, wThread, wFinal, wProfiler, wObjChecks,
wImportCpp, wImportObjC,
wImmediate, wImportCpp, wImportObjC,
wImportCompilerProc,
wImportc, wExportc, wExtern, wIncompleteStruct,
wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader,
@@ -85,7 +85,7 @@ const
"*", "-",
"magic", "thread", "final", "profiler", "objchecks",
"importcpp", "importobjc",
"immediate", "importcpp", "importobjc",
"importcompilerproc", "importc", "exportc", "extern", "incompletestruct",
"align", "nodecl", "pure", "volatile", "register", "sideeffect",
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",

View File

@@ -1,6 +1,6 @@
# All and any
template all(container, cond: expr): expr =
template all(container, cond: expr): expr {.immediate.} =
block:
var result = true
for it in items(container):
@@ -9,7 +9,7 @@ template all(container, cond: expr): expr =
break
result
template any(container, cond: expr): expr =
template any(container, cond: expr): expr {.immediate.} =
block:
var result = false
for it in items(container):

View File

@@ -50,7 +50,7 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool): seq[T] =
## Returns all items in a sequence that fulfilled the predicate.
accumulateResult(filter(seq1, pred))
template filterIt*(seq1, pred: expr): expr =
template filterIt*(seq1, pred: expr): expr {.immediate.} =
## Finds a specific item in a sequence as long as the
## predicate returns true. The predicate needs to be an expression
## containing ``it``: ``filterIt("abcxyz", it == 'x')``.

View File

@@ -17,15 +17,15 @@ type
proc `==` *(a, b: TColor): bool {.borrow.}
## compares two colors.
template extract(a: TColor, r, g, b: expr) =
template extract(a: TColor, r, g, b: expr) {.immediate.}=
var r = a.int shr 16 and 0xff
var g = a.int shr 8 and 0xff
var b = a.int and 0xff
template rawRGB(r, g, b: expr): expr =
template rawRGB(r, g, b: int): expr =
TColor(r shl 16 or g shl 8 or b)
template colorOp(op: expr) =
template colorOp(op: expr) {.immediate.} =
extract(a, ar, ag, ab)
extract(b, br, bg, bb)
result = rawRGB(op(ar, br), op(ag, bg), op(ab, bb))

View File

@@ -242,12 +242,12 @@ proc UnixToNativePath*(path: string): string {.
inc(i)
when defined(windows):
template wrapUnary(varname, winApiProc, arg: expr) =
template wrapUnary(varname, winApiProc, arg: expr) {.immediate.} =
var tmp = allocWideCString(arg)
var varname = winApiProc(tmp)
dealloc tmp
template wrapBinary(varname, winApiProc, arg, arg2: expr) =
template wrapBinary(varname, winApiProc, arg, arg2: expr) {.immediate.} =
var tmp2 = allocWideCString(arg)
var varname = winApiProc(tmp2, arg2)
dealloc tmp2

View File

@@ -624,15 +624,15 @@ proc `<` *[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.}
proc `<` *[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.}
proc `<` *(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.}
template `!=` * (x, y: expr): expr =
template `!=` * (x, y: expr): expr {.immediate.} =
## unequals operator. This is a shorthand for ``not (x == y)``.
not (x == y)
template `>=` * (x, y: expr): expr =
template `>=` * (x, y: expr): expr {.immediate.} =
## "is greater or equals" operator. This is the same as ``y <= x``.
y <= x
template `>` * (x, y: expr): expr =
template `>` * (x, y: expr): expr {.immediate.} =
## "is greater" operator. This is the same as ``y < x``.
y < x
@@ -655,11 +655,11 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
## is achieved by reversing the parameters for ``contains``; ``in`` then
## passes its arguments in reverse order.
template `in` * (x, y: expr): expr = contains(y, x)
template `not_in` * (x, y: expr): expr = not contains(y, x)
template `in` * (x, y: expr): expr {.immediate.} = contains(y, x)
template `not_in` * (x, y: expr): expr {.immediate.} = not contains(y, x)
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
template `is_not` *(x, y: expr): expr = not (x is y)
template `is_not` *(x, y: expr): expr {.immediate.} = not (x is y)
proc `of` *[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.}
@@ -842,7 +842,7 @@ proc quit*(errorcode: int = QuitSuccess) {.
## It does *not* call the garbage collector to free all the memory,
## unless a quit procedure calls ``GC_collect``.
template sysAssert(cond, msg: expr) =
template sysAssert(cond: bool, msg: string) =
when defined(useSysAssert):
if not cond:
echo "[SYSASSERT] ", msg
@@ -1090,11 +1090,11 @@ proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.}
## swaps the values `a` and `b`. This is often more efficient than
## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms.
template `>=%` *(x, y: expr): expr = y <=% x
template `>=%` *(x, y: expr): expr {.immediate.} = y <=% x
## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) >= unsigned(y)``.
template `>%` *(x, y: expr): expr = y <% x
template `>%` *(x, y: expr): expr {.immediate.} = y <% x
## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) > unsigned(y)``.
@@ -1590,7 +1590,7 @@ proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo", noSideEffect.}
## Unlike other IO operations this is guaranteed to be thread-safe as
## ``echo`` is very often used for debugging convenience.
template newException*(exceptn, message: expr): expr =
template newException*(exceptn: typeDesc, message: string): expr =
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
## to `message`. Returns the new exception object.
block: # open a new scope
@@ -2033,7 +2033,7 @@ proc `[]`*(s: string, x: TSlice[int]): string {.inline.} =
## slice operation for strings. Negative indexes are supported.
result = s.substr(x.a-|s, x.b-|s)
template spliceImpl(s, a, L, b: expr): stmt =
template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
# make room for additional elements or cut:
var slen = s.len
var shift = b.len - L
@@ -2176,7 +2176,7 @@ proc InstantiationInfo*(index = -1): tuple[filename: string, line: int] {.
proc raiseAssert(msg: string) {.noinline.} =
raise newException(EAssertionFailed, msg)
template assert*(cond: expr, msg = "") =
template assert*(cond: bool, msg = "") =
## provides a means to implement `programming by contracts`:idx: in Nimrod.
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
## raises an ``EAssertionFailure`` exception. However, the compiler may
@@ -2188,7 +2188,7 @@ template assert*(cond: expr, msg = "") =
if not cond:
raiseAssert(astToStr(cond) & ' ' & msg)
template doAssert*(cond: expr, msg = "") =
template doAssert*(cond: bool, msg = "") =
## same as `assert` but is always turned on and not affected by the
## ``--assertions`` command line switch.
bind raiseAssert, InstantiationInfo

View File

@@ -251,7 +251,7 @@ when defined(endb):
dbgAborting: bool # whether the debugger wants to abort
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
template processSignal(s, action: expr) =
template processSignal(s, action: expr) {.immediate.} =
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
elif s == SIGSEGV:
action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")

View File

@@ -170,7 +170,7 @@ when traceGC:
cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n",
e, z, y)
template gcTrace(cell, state: expr): stmt =
template gcTrace(cell, state: expr): stmt {.immediate.} =
when traceGC: traceCell(cell, state)
# -----------------------------------------------------------------------------

View File

@@ -1284,9 +1284,9 @@ type # This is the system-independent thread info struc
TProcedure* = proc ()
type TEventSeq = set[TEventKind]
template evconv(procName: expr, ptrName: typeDesc, assertions: TEventSeq): stmt =
template evconv(procName: expr, ptrName: typeDesc, assertions: TEventSeq): stmt {.immediate.} =
proc `procName`*(event: PEvent): ptrName =
assert(assertions.contains(event.kind))
assert(contains(assertions, event.kind))
result = cast[ptrName](event)
evconv(EvActive, PActiveEvent, {ACTIVEEVENT})

View File

@@ -1,8 +1,6 @@
from sdl import PSurface
discard SDL.CreateRGBSurface(SDL.SWSURFACE, 23, 34,
discard SDL.CreateRGBSurface(SDL.SWSURFACE, 23, 34,
32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xff000000'i32)

29
tests/compile/tredef.nim Normal file
View File

@@ -0,0 +1,29 @@
template foo(a: int, b: string) = nil
foo(1, "test")
proc bar(a: int, b: string) = nil
bar(1, "test")
template foo(a: int, b: string) = bar(a, b)
foo(1, "test")
block:
proc bar(a: int, b: string) = nil
template foo(a: int, b: string) = nil
foo(1, "test")
bar(1, "test")
proc baz =
proc foo(a: int, b: string) = nil
proc foo(b: string) =
template bar(a: int, b: string) = nil
bar(1, "test")
foo("test")
block:
proc foo(b: string) = nil
foo("test")
foo(1, "test")
baz()

View File

@@ -1,6 +1,6 @@
# Test if the new table constructor syntax works:
template ignoreExpr(e: expr): stmt =
template ignoreExpr(e: expr): stmt {.immediate.} =
nil
# test first class '..' syntactical citizen:

View File

@@ -26,13 +26,13 @@ echo(ha)
# Test identifier generation:
template prefix(name: expr): expr = `"hu" name`
template prefix(name: expr): expr {.immediate.} = `"hu" name`
var `hu "XYZ"` = "yay"
echo prefix(XYZ)
template typedef(name: expr, typ: typeDesc) =
template typedef(name: expr, typ: typeDesc) {.immediate.} =
type
`T name`* = typ
`P name`* = ref `T name`

View File

@@ -1,7 +1,7 @@
template `:=`(name, val: expr): stmt =
template `:=`(name, val: expr): stmt {.immediate.} =
var name = val
ha := 1 * 4
hu := "ta-da" == "ta-da"
echo ha, hu

View File

@@ -0,0 +1,9 @@
discard """
file: "tprocredef.nim"
line: 8
errormsg: "redefinition of \'foo\'"
"""
proc foo(a: int, b: string) = nil
proc foo(a: int, b: string) = nil

View File

@@ -3,10 +3,10 @@ discard """
line: 18
errormsg: "undeclared identifier: \'b\'"
"""
template declareInScope(x: expr, t: typeDesc): stmt =
template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} =
var x: t
template declareInNewScope(x: expr, t: typeDesc): stmt =
template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} =
# open a new scope:
block:
var x: t
@@ -17,5 +17,3 @@ a = 42 # works, `a` is known here
declareInNewScope(b, int)
b = 42 #ERROR_MSG undeclared identifier: 'b'

View File

@@ -1,4 +1,5 @@
discard """
disabled: true
output: '''derived class
base class
'''

View File

@@ -1,5 +1,6 @@
discard """
output: '''derived class 2
disabled: true
output: '''derived class 2
base class
'''
"""

View File

@@ -2,12 +2,12 @@ discard """
file: "tambsys.nim"
output: ""
"""
# Test ambiguous symbols
import mambsys1, mambsys2
var
v: mambsys1.TExport
mambsys2.foo(3) #OUT
# Test ambiguous symbols
import mambsys1, mambsys2
var
v: mambsys1.TExport
mambsys2.foo(3) #OUT

View File

@@ -21,7 +21,7 @@ template Comparable(typ: typeDesc): stmt =
proc `<=` * (x, y: typ): bool {.borrow.}
proc `==` * (x, y: typ): bool {.borrow.}
template DefineCurrency(typ, base: expr): stmt =
template DefineCurrency(typ, base: expr): stmt {.immediate.} =
type
typ* = distinct base
Additive(typ)

View File

@@ -6,7 +6,7 @@ discard """
var testNumber = 0
template test(opr, a, b, c: expr): stmt =
template test(opr, a, b, c: expr): stmt {.immediate.} =
# test the expression at compile and runtime
block:
const constExpr = opr(a, b)
@@ -43,5 +43,3 @@ test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32)
Echo("Success") #OUT Success

View File

@@ -1,6 +1,6 @@
discard """
file: "toverl2.nim"
output: "true012"
output: "true012innertrue"
"""
# Test new overloading resolution rules
@@ -14,14 +14,20 @@ iterator toverl2(x: int): int =
while res < x:
yield res
inc(res)
var
pp: proc (x: bool): string = toverl2
stdout.write(pp(true))
for x in toverl2(3):
stdout.write(toverl2(x))
block:
proc toverl2(x: int): string = return "inner"
stdout.write(toverl2(5))
stdout.write(true)
stdout.write("\n")
#OUT true012
#OUT true012innertrue

View File

@@ -2,7 +2,7 @@ discard """
output: "23456"
"""
template toSeq*(iter: expr): expr =
template toSeq*(iter: expr): expr {.immediate.} =
var result: seq[type(iter)] = @[]
for x in iter: add(result, x)
result

View File

@@ -1,2 +1,2 @@
import uclosures
import uclosures, utemplates

32
tests/run/utemplates.nim Normal file
View File

@@ -0,0 +1,32 @@
import unittest
template t(a: int): expr = "int"
template t(a: string): expr = "string"
test "templates can be overloaded":
check t(10) == "int"
check t("test") == "string"
test "previous definitions can be further overloaded or hidden in local scopes":
template t(a: bool): expr = "bool"
check t(true) == "bool"
check t(10) == "int"
template t(a: int): expr = "inner int"
check t(10) == "inner int"
check t("test") == "string"
test "templates can be redefined multiple times":
template customAssert(cond: bool, msg: string): stmt =
if not cond: fail(msg)
template assertion_failed(body: stmt) =
template fail(msg: string): stmt = body
assertion_failed: check msg == "first fail path"
customAssert false, "first fail path"
assertion_failed: check msg == "second fail path"
customAssert false, "second fail path"