Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
f788f603fe
27 changed files with 394 additions and 176 deletions
|
|
@ -258,7 +258,7 @@ type
|
||||||
tyGenericParam, # ``a`` in the above patterns
|
tyGenericParam, # ``a`` in the above patterns
|
||||||
tyDistinct,
|
tyDistinct,
|
||||||
tyEnum,
|
tyEnum,
|
||||||
tyOrdinal, # misnamed: should become 'tyConstraint'
|
tyOrdinal, # integer types (including enums and boolean)
|
||||||
tyArray,
|
tyArray,
|
||||||
tyObject,
|
tyObject,
|
||||||
tyTuple,
|
tyTuple,
|
||||||
|
|
@ -277,6 +277,7 @@ type
|
||||||
tyConst, tyMutable, tyVarargs,
|
tyConst, tyMutable, tyVarargs,
|
||||||
tyIter, # unused
|
tyIter, # unused
|
||||||
tyProxy # currently unused
|
tyProxy # currently unused
|
||||||
|
tyTypeClass,
|
||||||
|
|
||||||
const
|
const
|
||||||
tyPureObject* = tyTuple
|
tyPureObject* = tyTuple
|
||||||
|
|
@ -308,6 +309,8 @@ type
|
||||||
tfFromGeneric # type is an instantiation of a generic; this is needed
|
tfFromGeneric # type is an instantiation of a generic; this is needed
|
||||||
# because for instantiations of objects, structural
|
# because for instantiations of objects, structural
|
||||||
# type equality has to be used
|
# type equality has to be used
|
||||||
|
tfAll # type class requires all constraints to be met (default)
|
||||||
|
tfAny # type class requires any constraint to be met
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
@ -707,6 +710,15 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||||
var emptyNode* = newNode(nkEmpty)
|
var emptyNode* = newNode(nkEmpty)
|
||||||
# There is a single empty node that is shared! Do not overwrite it!
|
# There is a single empty node that is shared! Do not overwrite it!
|
||||||
|
|
||||||
|
proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
|
||||||
|
t.sym = s
|
||||||
|
s.typ = t
|
||||||
|
result = t
|
||||||
|
|
||||||
|
proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
|
||||||
|
t.sym = s
|
||||||
|
s.typ = t
|
||||||
|
result = s
|
||||||
|
|
||||||
const # for all kind of hash tables:
|
const # for all kind of hash tables:
|
||||||
GrowthFactor* = 2 # must be power of 2, > 0
|
GrowthFactor* = 2 # must be power of 2, > 0
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
var length = sonsLen(ri)
|
var length = sonsLen(ri)
|
||||||
for i in countup(1, length - 1):
|
for i in countup(1, length - 1):
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
|
if ri.sons[i].typ.isCompileTimeOnly: continue
|
||||||
if i < sonsLen(typ):
|
if i < sonsLen(typ):
|
||||||
assert(typ.n.sons[i].kind == nkSym)
|
assert(typ.n.sons[i].kind == nkSym)
|
||||||
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
|
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# included from cgen.nim
|
||||||
|
|
||||||
# ------------------------- Name Mangling --------------------------------
|
# ------------------------- Name Mangling --------------------------------
|
||||||
|
|
||||||
proc mangle(name: string): string =
|
proc mangle(name: string): string =
|
||||||
|
|
@ -48,6 +50,9 @@ proc mangleName(s: PSym): PRope =
|
||||||
app(result, toRope(s.id))
|
app(result, toRope(s.id))
|
||||||
s.loc.r = result
|
s.loc.r = result
|
||||||
|
|
||||||
|
proc isCompileTimeOnly(t: PType): bool =
|
||||||
|
result = t.kind in {tyTypedesc, tyExpr}
|
||||||
|
|
||||||
proc getTypeName(typ: PType): PRope =
|
proc getTypeName(typ: PType): PRope =
|
||||||
if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and
|
if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and
|
||||||
(gCmd != cmdCompileToLLVM):
|
(gCmd != cmdCompileToLLVM):
|
||||||
|
|
@ -187,6 +192,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||||
for i in countup(1, sonsLen(t.n) - 1):
|
for i in countup(1, sonsLen(t.n) - 1):
|
||||||
if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
|
if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
|
||||||
var param = t.n.sons[i].sym
|
var param = t.n.sons[i].sym
|
||||||
|
if isCompileTimeOnly(param.typ): continue
|
||||||
fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack)
|
fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack)
|
||||||
app(params, getParamTypeDesc(m, param.typ, check))
|
app(params, getParamTypeDesc(m, param.typ, check))
|
||||||
if ccgIntroducedPtr(param):
|
if ccgIntroducedPtr(param):
|
||||||
|
|
@ -206,8 +212,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||||
arr = arr.sons[0]
|
arr = arr.sons[0]
|
||||||
if i < sonsLen(t.n) - 1: app(params, ", ")
|
if i < sonsLen(t.n) - 1: app(params, ", ")
|
||||||
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
|
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
|
||||||
if params != nil: app(params, ", ")
|
|
||||||
var arr = t.sons[0]
|
var arr = t.sons[0]
|
||||||
|
if params != nil: app(params, ", ")
|
||||||
app(params, getTypeDescAux(m, arr, check))
|
app(params, getTypeDescAux(m, arr, check))
|
||||||
if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM):
|
if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM):
|
||||||
app(params, "*")
|
app(params, "*")
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,11 @@ proc GetUniqueType*(key: PType): PType =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
gCanonicalTypes[k] = key
|
gCanonicalTypes[k] = key
|
||||||
result = key
|
result = key
|
||||||
|
of tyGenericParam, tyTypeClass:
|
||||||
|
InternalError("GetUniqueType")
|
||||||
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
|
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
|
||||||
result = GetUniqueType(lastSon(key))
|
result = GetUniqueType(lastSon(key))
|
||||||
of tyArrayConstr, tyGenericInvokation, tyGenericBody, tyGenericParam,
|
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
|
||||||
tyOpenArray, tyArray, tyTuple, tySet, tyRange,
|
tyOpenArray, tyArray, tyTuple, tySet, tyRange,
|
||||||
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
||||||
# we have to do a slow linear search because types may need
|
# we have to do a slow linear search because types may need
|
||||||
|
|
|
||||||
|
|
@ -606,6 +606,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
res.loc.s = OnUnknown
|
res.loc.s = OnUnknown
|
||||||
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
||||||
var param = prc.typ.n.sons[i].sym
|
var param = prc.typ.n.sons[i].sym
|
||||||
|
if param.typ.isCompileTimeOnly: continue
|
||||||
assignParam(p, param)
|
assignParam(p, param)
|
||||||
closureSetup(p, prc)
|
closureSetup(p, prc)
|
||||||
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
|
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ proc mapType(typ: PType): TEcmasTypeKind =
|
||||||
result = etyObject
|
result = etyObject
|
||||||
of tyNil: result = etyNull
|
of tyNil: result = etyNull
|
||||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
|
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
|
||||||
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc:
|
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClass:
|
||||||
result = etyNone
|
result = etyNone
|
||||||
of tyProc: result = etyProc
|
of tyProc: result = etyProc
|
||||||
of tyCString: result = etyString
|
of tyCString: result = etyString
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
import
|
import
|
||||||
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
||||||
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
||||||
parser, ropes, rodread
|
parser, ropes, rodread, idgen
|
||||||
|
|
||||||
type
|
type
|
||||||
PStackFrame* = ref TStackFrame
|
PStackFrame* = ref TStackFrame
|
||||||
|
|
@ -843,6 +843,7 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
|
||||||
result.typ = newType(tyStmt, c.module)
|
result.typ = newType(tyStmt, c.module)
|
||||||
|
|
||||||
proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode =
|
proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode =
|
||||||
|
inc genSymBaseId
|
||||||
case templ.kind
|
case templ.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
var p = templ.sym
|
var p = templ.sym
|
||||||
|
|
@ -866,26 +867,29 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||||
a = sonsLen(n)
|
a = sonsLen(n)
|
||||||
else: a = 0
|
else: a = 0
|
||||||
var f = sonsLen(s.typ)
|
var f = s.typ.sonsLen
|
||||||
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
|
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
|
||||||
|
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
for i in countup(1, f - 1):
|
for i in countup(1, f - 1):
|
||||||
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
||||||
|
if arg == nil or arg.kind == nkEmpty:
|
||||||
|
LocalError(n.info, errWrongNumberOfArguments)
|
||||||
addSon(result, arg)
|
addSon(result, arg)
|
||||||
|
|
||||||
var evalTemplateCounter = 0
|
var evalTemplateCounter* = 0
|
||||||
# to prevent endless recursion in templates instantation
|
# to prevent endless recursion in templates instantation
|
||||||
|
|
||||||
proc evalTemplate(n: PNode, sym: PSym): PNode =
|
proc evalTemplate*(n: PNode, sym: PSym): PNode =
|
||||||
inc(evalTemplateCounter)
|
inc(evalTemplateCounter)
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > 100:
|
||||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
GlobalError(n.info, errTemplateInstantiationTooNested)
|
||||||
|
result = n
|
||||||
|
|
||||||
# replace each param by the corresponding node:
|
# replace each param by the corresponding node:
|
||||||
var args = evalTemplateArgs(n, sym)
|
var args = evalTemplateArgs(n, sym)
|
||||||
result = evalTemplateAux(sym.getBody, args, sym)
|
result = evalTemplateAux(sym.getBody, args, sym)
|
||||||
|
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
|
|
||||||
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
||||||
|
|
@ -1312,6 +1316,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > 100:
|
||||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
GlobalError(n.info, errTemplateInstantiationTooNested)
|
||||||
|
|
||||||
|
inc genSymBaseId
|
||||||
var s = newStackFrame()
|
var s = newStackFrame()
|
||||||
s.call = n
|
s.call = n
|
||||||
setlen(s.params, 2)
|
setlen(s.params, 2)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import idents, strutils, os, options
|
import idents, strutils, os, options
|
||||||
|
|
||||||
var gFrontEndId, gBackendId*: int
|
var gFrontEndId, gBackendId*, genSymBaseId*: int
|
||||||
|
|
||||||
const
|
const
|
||||||
debugIds* = false
|
debugIds* = false
|
||||||
|
|
@ -25,7 +25,7 @@ proc registerID*(id: PIdObj) =
|
||||||
when debugIDs:
|
when debugIDs:
|
||||||
if id.id == -1 or ContainsOrIncl(usedIds, id.id):
|
if id.id == -1 or ContainsOrIncl(usedIds, id.id):
|
||||||
InternalError("ID already used: " & $id.id)
|
InternalError("ID already used: " & $id.id)
|
||||||
|
|
||||||
proc getID*(): int {.inline.} =
|
proc getID*(): int {.inline.} =
|
||||||
result = gFrontEndId
|
result = gFrontEndId
|
||||||
inc(gFrontEndId)
|
inc(gFrontEndId)
|
||||||
|
|
@ -34,6 +34,9 @@ proc backendId*(): int {.inline.} =
|
||||||
result = gBackendId
|
result = gBackendId
|
||||||
inc(gBackendId)
|
inc(gBackendId)
|
||||||
|
|
||||||
|
proc genSym*(basename: string): PIdent =
|
||||||
|
result = getIdent(basename & $genSymBaseId)
|
||||||
|
|
||||||
proc setId*(id: int) {.inline.} =
|
proc setId*(id: int) {.inline.} =
|
||||||
gFrontEndId = max(gFrontEndId, id + 1)
|
gFrontEndId = max(gFrontEndId, id + 1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
||||||
renderer
|
renderer, wordrecg, idgen
|
||||||
|
|
||||||
proc considerAcc*(n: PNode): PIdent =
|
proc considerAcc*(n: PNode): PIdent =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -21,6 +21,11 @@ proc considerAcc*(n: PNode): PIdent =
|
||||||
case n.len
|
case n.len
|
||||||
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
||||||
of 1: result = considerAcc(n.sons[0])
|
of 1: result = considerAcc(n.sons[0])
|
||||||
|
of 2:
|
||||||
|
if n[0].ident.id == ord(wStar):
|
||||||
|
result = genSym(n[1].ident.s)
|
||||||
|
else:
|
||||||
|
result = getIdent(n[0].ident.s & n[1].ident.s)
|
||||||
else:
|
else:
|
||||||
var id = ""
|
var id = ""
|
||||||
for i in 0.. <n.len:
|
for i in 0.. <n.len:
|
||||||
|
|
|
||||||
|
|
@ -662,3 +662,8 @@ proc InternalError*(info: TLineInfo, errMsg: string) =
|
||||||
proc InternalError*(errMsg: string) =
|
proc InternalError*(errMsg: string) =
|
||||||
writeContext(UnknownLineInfo())
|
writeContext(UnknownLineInfo())
|
||||||
rawMessage(errInternal, errMsg)
|
rawMessage(errInternal, errMsg)
|
||||||
|
|
||||||
|
template AssertNotNil*(e: expr): expr =
|
||||||
|
if(e == nil): InternalError($InstantiationInfo())
|
||||||
|
e
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,3 +219,6 @@ proc binaryStrSearch*(x: openarray[string], y: string): int =
|
||||||
return mid
|
return mid
|
||||||
result = - 1
|
result = - 1
|
||||||
|
|
||||||
|
# Can we keep this? I'm using it all the time
|
||||||
|
template nimdbg*: expr = c.filename.endsWith"nimdbg.nim"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
|
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
|
||||||
result = semConstExpr(c, n)
|
result = semConstExpr(c, n)
|
||||||
|
|
||||||
include seminst, semcall
|
include seminst, semcall
|
||||||
|
|
||||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
|
|
|
||||||
|
|
@ -180,14 +180,16 @@ proc addToLib(lib: PLib, sym: PSym) =
|
||||||
sym.annex = lib
|
sym.annex = lib
|
||||||
|
|
||||||
proc makePtrType(c: PContext, baseType: PType): PType =
|
proc makePtrType(c: PContext, baseType: PType): PType =
|
||||||
if (baseType == nil): InternalError("makePtrType")
|
|
||||||
result = newTypeS(tyPtr, c)
|
result = newTypeS(tyPtr, c)
|
||||||
addSon(result, baseType)
|
addSon(result, baseType.AssertNotNil)
|
||||||
|
|
||||||
proc makeVarType(c: PContext, baseType: PType): PType =
|
proc makeVarType(c: PContext, baseType: PType): PType =
|
||||||
if (baseType == nil): InternalError("makeVarType")
|
|
||||||
result = newTypeS(tyVar, c)
|
result = newTypeS(tyVar, c)
|
||||||
addSon(result, baseType)
|
addSon(result, baseType.AssertNotNil)
|
||||||
|
|
||||||
|
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||||
|
result = newTypeS(tyTypeDesc, c)
|
||||||
|
result.addSon(typ.AssertNotNil)
|
||||||
|
|
||||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||||
result = newType(kind, getCurrOwner())
|
result = newType(kind, getCurrOwner())
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,12 @@
|
||||||
# this module does the semantic checking for expressions
|
# this module does the semantic checking for expressions
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
|
proc semExprOrTypedesc(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = evalTemplate(c, n, s)
|
result = evalTemplate(n, s)
|
||||||
if semCheck: result = semAfterMacroCall(c, result, s)
|
if semCheck: result = semAfterMacroCall(c, result, s)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
|
|
@ -93,6 +95,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
# if a proc accesses a global variable, it is not side effect free:
|
# if a proc accesses a global variable, it is not side effect free:
|
||||||
if sfGlobal in s.flags:
|
if sfGlobal in s.flags:
|
||||||
incl(c.p.owner.flags, sfSideEffect)
|
incl(c.p.owner.flags, sfSideEffect)
|
||||||
|
elif s.kind == skParam and s.typ.kind == tyExpr:
|
||||||
|
return s.typ.n
|
||||||
elif s.owner != c.p.owner and s.owner.kind != skModule and
|
elif s.owner != c.p.owner and s.owner.kind != skModule and
|
||||||
c.p.owner.typ != nil and not IsGenericRoutine(s.owner):
|
c.p.owner.typ != nil and not IsGenericRoutine(s.owner):
|
||||||
c.p.owner.typ.callConv = ccClosure
|
c.p.owner.typ.callConv = ccClosure
|
||||||
|
|
@ -111,7 +115,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
|
|
||||||
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
||||||
var diff = inheritanceDiff(castDest, src)
|
var diff = inheritanceDiff(castDest, src)
|
||||||
if diff == high(int):
|
if diff == high(int):
|
||||||
|
|
@ -247,16 +251,31 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
GlobalError(n.info, errXExpectsTwoArguments, "is")
|
GlobalError(n.info, errXExpectsTwoArguments, "is")
|
||||||
|
|
||||||
|
proc semExprOrTypedesc(c: PContext, n: PNode): PNode =
|
||||||
|
# XXX: Currently, semExprWithType will return the same type
|
||||||
|
# for nodes such as (100) or (int).
|
||||||
|
# This is inappropriate. The type of the first expression
|
||||||
|
# should be "int", while the type of the second one should
|
||||||
|
# be typeDesc(int).
|
||||||
|
# Ideally, this should be fixed in semExpr, but right now
|
||||||
|
# there are probably users that depend on the present behavior.
|
||||||
|
# XXX: Investigate current uses of efAllowType and fix them to
|
||||||
|
# work with tyTypeDesc.
|
||||||
|
result = semExprWithType(c, n, {efAllowType})
|
||||||
|
if result.kind == nkSym and result.sym.kind == skType and
|
||||||
|
result.typ.kind != tyTypeDesc:
|
||||||
|
result.typ = makeTypeDesc(c, result.typ)
|
||||||
|
|
||||||
proc semOpAux(c: PContext, n: PNode) =
|
proc semOpAux(c: PContext, n: PNode) =
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
||||||
var info = a.sons[0].info
|
var info = a.sons[0].info
|
||||||
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
|
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
|
||||||
a.sons[1] = semExprWithType(c, a.sons[1], {efAllowType})
|
a.sons[1] = semExprOrTypedesc(c, a.sons[1])
|
||||||
a.typ = a.sons[1].typ
|
a.typ = a.sons[1].typ
|
||||||
else:
|
else:
|
||||||
n.sons[i] = semExprWithType(c, a, {efAllowType})
|
n.sons[i] = semExprOrTypedesc(c, a)
|
||||||
|
|
||||||
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||||
# quick check if there is *any* () operator overloaded:
|
# quick check if there is *any* () operator overloaded:
|
||||||
|
|
@ -822,7 +841,7 @@ proc semDeref(c: PContext, n: PNode): PNode =
|
||||||
of tyRef, tyPtr: n.typ = t.sons[0]
|
of tyRef, tyPtr: n.typ = t.sons[0]
|
||||||
else: result = nil
|
else: result = nil
|
||||||
#GlobalError(n.sons[0].info, errCircumNeedsPointer)
|
#GlobalError(n.sons[0].info, errCircumNeedsPointer)
|
||||||
|
|
||||||
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
## returns nil if not a built-in subscript operator; also called for the
|
## returns nil if not a built-in subscript operator; also called for the
|
||||||
## checking of assignments
|
## checking of assignments
|
||||||
|
|
@ -833,7 +852,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result.add(x[0])
|
result.add(x[0])
|
||||||
return
|
return
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0], flags - {efAllowType})
|
n.sons[0] = semExprOrTypedesc(c, n.sons[0])
|
||||||
var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||||
case arr.kind
|
case arr.kind
|
||||||
of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString:
|
of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString:
|
||||||
|
|
@ -848,6 +867,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
result.typ = elemType(arr)
|
result.typ = elemType(arr)
|
||||||
#GlobalError(n.info, errIndexTypesDoNotMatch)
|
#GlobalError(n.info, errIndexTypesDoNotMatch)
|
||||||
|
of tyTypeDesc:
|
||||||
|
result = n.sons[0] # The result so far is a tyTypeDesc bound to
|
||||||
|
# a tyGenericBody. The line below will substitute
|
||||||
|
# it with the instantiated type.
|
||||||
|
result.typ.sons[0] = semTypeNode(c, n, nil).linkTo(result.sym)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
n.sons[0] = makeDeref(n.sons[0])
|
n.sons[0] = makeDeref(n.sons[0])
|
||||||
|
|
@ -1024,7 +1048,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||||
markUsed(n, expandedSym)
|
markUsed(n, expandedSym)
|
||||||
|
|
||||||
for i in countup(1, macroCall.len-1):
|
for i in countup(1, macroCall.len-1):
|
||||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {efAllowType})
|
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
||||||
|
|
||||||
# Preserve the magic symbol in order to be handled in evals.nim
|
# Preserve the magic symbol in order to be handled in evals.nim
|
||||||
n.sons[0] = newSymNode(magicSym, n.info)
|
n.sons[0] = newSymNode(magicSym, n.info)
|
||||||
|
|
@ -1287,6 +1311,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkBind:
|
of nkBind:
|
||||||
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:
|
||||||
|
var typ = semTypeNode(c, n, nil)
|
||||||
|
if typ.sym == nil:
|
||||||
|
typ = copyType(typ, typ.owner, true)
|
||||||
|
typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner))
|
||||||
|
result = newSymNode(typ.sym, n.info)
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||||
# check if it is an expression macro:
|
# check if it is an expression macro:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
if a.kind != nkSym:
|
if a.kind != nkSym:
|
||||||
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
||||||
var q = a.sym
|
var q = a.sym
|
||||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue
|
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
|
||||||
var s = newSym(skType, q.name, getCurrOwner())
|
var s = newSym(skType, q.name, getCurrOwner())
|
||||||
s.info = q.info
|
s.info = q.info
|
||||||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||||
|
|
@ -107,8 +107,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
||||||
c.threadEntries.add(s)
|
c.threadEntries.add(s)
|
||||||
|
|
||||||
template nimdbg: expr = c.filename.endsWith"nimdbg.nim"
|
|
||||||
|
|
||||||
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
|
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
|
||||||
# XXX: This is intended to replace the use of semParamList in generateInstance.
|
# XXX: This is intended to replace the use of semParamList in generateInstance.
|
||||||
# The results of semParamList's analysis are already encoded in the original
|
# The results of semParamList's analysis are already encoded in the original
|
||||||
|
|
|
||||||
|
|
@ -9,67 +9,6 @@
|
||||||
|
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
proc isExpr(n: PNode): bool =
|
|
||||||
# returns true if ``n`` looks like an expression
|
|
||||||
case n.kind
|
|
||||||
of nkIdent..nkNilLit:
|
|
||||||
result = true
|
|
||||||
of nkCall..pred(nkAsgn):
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
|
||||||
if not isExpr(n.sons[i]):
|
|
||||||
return false
|
|
||||||
result = true
|
|
||||||
else: result = false
|
|
||||||
|
|
||||||
proc isTypeDesc(n: PNode): bool =
|
|
||||||
# returns true if ``n`` looks like a type desc
|
|
||||||
case n.kind
|
|
||||||
of nkIdent, nkSym, nkType:
|
|
||||||
result = true
|
|
||||||
of nkDotExpr, nkBracketExpr:
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
|
||||||
if not isTypeDesc(n.sons[i]):
|
|
||||||
return false
|
|
||||||
result = true
|
|
||||||
of nkTypeOfExpr..nkEnumTy:
|
|
||||||
result = true
|
|
||||||
else: result = false
|
|
||||||
|
|
||||||
var evalTemplateCounter: int = 0
|
|
||||||
# to prevend endless recursion in templates instantation
|
|
||||||
|
|
||||||
proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode =
|
|
||||||
var
|
|
||||||
f, a: int
|
|
||||||
arg: PNode
|
|
||||||
f = sonsLen(s.typ)
|
|
||||||
# if the template has zero arguments, it can be called without ``()``
|
|
||||||
# `n` is then a nkSym or something similar
|
|
||||||
case n.kind
|
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
|
||||||
a = sonsLen(n)
|
|
||||||
else: a = 0
|
|
||||||
if a > f: LocalError(n.info, errWrongNumberOfArguments)
|
|
||||||
result = copyNode(n)
|
|
||||||
for i in countup(1, f - 1):
|
|
||||||
if i < a: arg = n.sons[i]
|
|
||||||
else: arg = copyTree(s.typ.n.sons[i].sym.ast)
|
|
||||||
if arg == nil or arg.kind == nkEmpty:
|
|
||||||
LocalError(n.info, errWrongNumberOfArguments)
|
|
||||||
addSon(result, arg)
|
|
||||||
|
|
||||||
proc evalTemplate*(c: PContext, n: PNode, sym: PSym): PNode =
|
|
||||||
var args: PNode
|
|
||||||
inc(evalTemplateCounter)
|
|
||||||
if evalTemplateCounter <= 100:
|
|
||||||
# replace each param by the corresponding node:
|
|
||||||
args = evalTemplateArgs(c, n, sym)
|
|
||||||
result = evalTemplateAux(sym.getBody, args, sym)
|
|
||||||
dec(evalTemplateCounter)
|
|
||||||
else:
|
|
||||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
|
||||||
result = n
|
|
||||||
|
|
||||||
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
var
|
var
|
||||||
a: PSym
|
a: PSym
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
|
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
|
||||||
if result != nil:
|
if result != nil:
|
||||||
markUsed(n, result)
|
markUsed(n, result)
|
||||||
|
if result.kind == skParam and result.typ.kind == tyTypeDesc:
|
||||||
|
return result.typ.sons[0].sym
|
||||||
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
||||||
if result.typ.kind != tyGenericParam:
|
if result.typ.kind != tyGenericParam:
|
||||||
# XXX get rid of this hack!
|
# XXX get rid of this hack!
|
||||||
|
|
@ -470,42 +472,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result.n = newNodeI(nkRecList, n.info)
|
result.n = newNodeI(nkRecList, n.info)
|
||||||
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym)
|
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym)
|
||||||
|
|
||||||
proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
|
|
||||||
cl: var TIntSet): PType =
|
|
||||||
result = t
|
|
||||||
if t == nil: return
|
|
||||||
if ContainsOrIncl(cl, t.id): return
|
|
||||||
case t.kind
|
|
||||||
of tyGenericBody:
|
|
||||||
result = newTypeS(tyGenericInvokation, c)
|
|
||||||
addSon(result, t)
|
|
||||||
for i in countup(0, sonsLen(t) - 2):
|
|
||||||
if t.sons[i].kind != tyGenericParam:
|
|
||||||
InternalError("addTypeVarsOfGenericBody")
|
|
||||||
# do not declare ``TKey`` twice:
|
|
||||||
#if not ContainsOrIncl(cl, t.sons[i].sym.ident.id):
|
|
||||||
var s = copySym(t.sons[i].sym)
|
|
||||||
s.position = sonsLen(genericParams)
|
|
||||||
if s.typ == nil or s.typ.kind != tyGenericParam:
|
|
||||||
InternalError("addTypeVarsOfGenericBody 2")
|
|
||||||
addDecl(c, s)
|
|
||||||
addSon(genericParams, newSymNode(s))
|
|
||||||
addSon(result, t.sons[i])
|
|
||||||
of tyGenericInst:
|
|
||||||
var L = sonsLen(t) - 1
|
|
||||||
t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
|
|
||||||
of tyGenericInvokation:
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
|
||||||
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
|
|
||||||
else:
|
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
|
||||||
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
|
|
||||||
|
|
||||||
proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
|
|
||||||
result = semTypeNode(c, n, nil)
|
|
||||||
if genericParams != nil and sonsLen(genericParams) == 0:
|
|
||||||
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
|
|
||||||
|
|
||||||
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||||
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
|
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
|
||||||
let nn = getSysSym"PNimrodNode"
|
let nn = getSysSym"PNimrodNode"
|
||||||
|
|
@ -515,8 +481,43 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||||
else:
|
else:
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
|
|
||||||
proc isTypeClass(c: PContext, t: PType): bool =
|
proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
||||||
return t.kind in {tyExpr}
|
tuple[typ: PType, id: PIdent] =
|
||||||
|
# if typ is not-nil, the param should be turned into a generic param
|
||||||
|
# if id is not nil, the generic param will bind just once (see below)
|
||||||
|
case paramType.kind:
|
||||||
|
of tyExpr:
|
||||||
|
if procKind notin {skTemplate, skMacro}:
|
||||||
|
if paramType.sonsLen == 0:
|
||||||
|
# proc(a, b: expr)
|
||||||
|
# no constraints, treat like generic param
|
||||||
|
result.typ = newTypeS(tyGenericParam, c)
|
||||||
|
else:
|
||||||
|
# proc(a: expr{string}, b: expr{nkLambda})
|
||||||
|
# overload on compile time values and AST trees
|
||||||
|
result.typ = newTypeS(tyExpr, c)
|
||||||
|
result.typ.sons = paramType.sons
|
||||||
|
of tyTypeDesc:
|
||||||
|
if procKind notin {skTemplate, skMacro}:
|
||||||
|
result.typ = newTypeS(tyTypeDesc, c)
|
||||||
|
result.typ.sons = paramType.sons
|
||||||
|
of tyDistinct:
|
||||||
|
# type T1 = distinct expr
|
||||||
|
# type S1 = distinct Sortable
|
||||||
|
# proc x(a, b: T1, c, d: S1)
|
||||||
|
# This forces bindOnce behavior for the type class, equivalent to
|
||||||
|
# proc x[T, S](a, b: T, c, d: S)
|
||||||
|
result = paramTypeClass(c, paramType.lastSon, procKind)
|
||||||
|
result.id = paramType.sym.name
|
||||||
|
of tyGenericBody:
|
||||||
|
# type Foo[T] = object
|
||||||
|
# proc x(a: Foo, b: Foo)
|
||||||
|
result.typ = newTypeS(tyTypeClass, c)
|
||||||
|
result.typ.addSon(paramType)
|
||||||
|
result.id = paramType.sym.name # bindOnce by default
|
||||||
|
of tyTypeClass:
|
||||||
|
result.typ = copyType(paramType, getCurrOwner(), false)
|
||||||
|
else: nil
|
||||||
|
|
||||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
prev: PType, kind: TSymKind): PType =
|
prev: PType, kind: TSymKind): PType =
|
||||||
|
|
@ -546,9 +547,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
hasDefault = a.sons[length-1].kind != nkEmpty
|
hasDefault = a.sons[length-1].kind != nkEmpty
|
||||||
|
|
||||||
if hasType:
|
if hasType:
|
||||||
typ = paramType(c, a.sons[length-2], genericParams, cl)
|
typ = semTypeNode(c, a.sons[length-2], nil)
|
||||||
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
|
|
||||||
# debug a.sons[length-2][0][1]
|
|
||||||
if hasDefault:
|
if hasDefault:
|
||||||
def = semExprWithType(c, a.sons[length-1])
|
def = semExprWithType(c, a.sons[length-1])
|
||||||
# check type compability between def.typ and typ:
|
# check type compability between def.typ and typ:
|
||||||
|
|
@ -566,40 +566,46 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var arg = newSymS(skParam, a.sons[j], c)
|
var arg = newSymS(skParam, a.sons[j], c)
|
||||||
arg.typ = typ
|
var endingType = typ
|
||||||
if kind notin {skTemplate, skMacro} and isTypeClass(c, typ):
|
var (typeClass, paramTypId) = paramTypeClass(c, typ, kind)
|
||||||
let typeClassParamId = getIdent(":tcls_" & $i & "_" & $j)
|
if typeClass != nil:
|
||||||
|
if paramTypId == nil: paramTypId = getIdent(arg.name.s & ":type")
|
||||||
if genericParams == nil:
|
if genericParams == nil:
|
||||||
# genericParams is nil when the proc is being instantiated
|
# genericParams is nil when the proc is being instantiated
|
||||||
# the resolved type will be in scope then
|
# the resolved type will be in scope then
|
||||||
var s = SymtabGet(c.tab, typeClassParamId)
|
endingType = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
|
||||||
arg.typ = s.typ
|
|
||||||
else:
|
else:
|
||||||
var s = newSym(skType, typeClassParamId, getCurrOwner())
|
block addImplicitGeneric:
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
# is this a bindOnce type class already present in the param list?
|
||||||
s.typ.sym = s
|
for i in countup(0, genericParams.len - 1):
|
||||||
s.position = genericParams.len
|
if genericParams.sons[i].sym.name == paramTypId:
|
||||||
genericParams.addSon(newSymNode(s))
|
endingType = genericParams.sons[i].typ
|
||||||
arg.typ = s.typ
|
break addImplicitGeneric
|
||||||
|
|
||||||
|
var s = newSym(skType, paramTypId, getCurrOwner())
|
||||||
|
s.typ = typeClass
|
||||||
|
s.typ.sym = s
|
||||||
|
s.position = genericParams.len
|
||||||
|
genericParams.addSon(newSymNode(s))
|
||||||
|
endingType = typeClass
|
||||||
|
|
||||||
|
arg.typ = endingType
|
||||||
arg.position = counter
|
arg.position = counter
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||||
if ContainsOrIncl(check, arg.name.id):
|
if ContainsOrIncl(check, arg.name.id):
|
||||||
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
||||||
addSon(result.n, newSymNode(arg))
|
addSon(result.n, newSymNode(arg))
|
||||||
addSon(result, typ)
|
addSon(result, endingType)
|
||||||
addParamOrResult(c, arg, kind)
|
addParamOrResult(c, arg, kind)
|
||||||
|
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
var r = paramType(c, n.sons[0], genericParams, cl)
|
var r = semTypeNode(c, n.sons[0], nil)
|
||||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||||
# compiler only checks for 'nil':
|
# compiler only checks for 'nil':
|
||||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||||
result.sons[0] = r
|
result.sons[0] = r
|
||||||
res.typ = result.sons[0]
|
res.typ = result.sons[0]
|
||||||
#if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
|
|
||||||
# debug result
|
|
||||||
|
|
||||||
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
|
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
@ -666,9 +672,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
|
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
|
||||||
result = instGenericContainer(c, n, result)
|
result = instGenericContainer(c, n, result)
|
||||||
|
|
||||||
proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType =
|
proc semTypeFromMacro(c: PContext, n: PNode): PType =
|
||||||
# Expands a macro or template until a type is returned
|
# Expands a macro or template until a type is returned
|
||||||
# results in GlobalError if the macro expands to something different
|
# results in GlobalError if the macro expands to something different
|
||||||
|
var sym = expectMacroOrTemplateCall(c, n)
|
||||||
markUsed(n, sym)
|
markUsed(n, sym)
|
||||||
case sym.kind
|
case sym.kind
|
||||||
of skMacro:
|
of skMacro:
|
||||||
|
|
@ -678,7 +685,7 @@ proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType =
|
||||||
else:
|
else:
|
||||||
GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
||||||
|
|
||||||
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)
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -691,9 +698,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
else: GlobalError(n.info, errTypeExpected)
|
else: GlobalError(n.info, errTypeExpected)
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
# expand macros and templates
|
let op = n.sons[0].ident.id
|
||||||
var expandedSym = expectMacroOrTemplateCall(c, n)
|
if op in {ord(wAnd), ord(wOr)}:
|
||||||
result = semExpandToType(c, n, expandedSym)
|
var
|
||||||
|
t1 = semTypeNode(c, n.sons[1], nil)
|
||||||
|
t2 = semTypeNode(c, n.sons[2], nil)
|
||||||
|
|
||||||
|
if t1 == nil: GlobalError(n.sons[1].info, errTypeExpected)
|
||||||
|
elif t2 == nil: GlobalError(n.sons[2].info, errTypeExpected)
|
||||||
|
else:
|
||||||
|
result = newTypeS(tyTypeClass, c)
|
||||||
|
result.addSon(t1)
|
||||||
|
result.addSon(t2)
|
||||||
|
result.flags.incl(if op == ord(wAnd): tfAll else: tfAny)
|
||||||
|
else:
|
||||||
|
result = semTypeFromMacro(c, n)
|
||||||
|
of nkCurlyExpr:
|
||||||
|
result = semTypeNode(c, n.sons[0], nil)
|
||||||
|
if result != nil:
|
||||||
|
result = copyType(result, getCurrOwner(), false)
|
||||||
|
for i in countup(1, n.len - 1):
|
||||||
|
result.addSon(semTypeNode(c, n.sons[i], nil))
|
||||||
of nkWhenStmt:
|
of nkWhenStmt:
|
||||||
var whenResult = semWhen(c, n, false)
|
var whenResult = semWhen(c, n, false)
|
||||||
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
||||||
|
|
@ -794,7 +819,7 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
else: GlobalError(m.info, errTypeExpected)
|
else: GlobalError(m.info, errTypeExpected)
|
||||||
|
|
||||||
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
||||||
result = newTypeS(tyOrdinal, c)
|
result = newTypeS(tyTypeClass, c)
|
||||||
result.addSon(newTypeS(k, c))
|
result.addSon(newTypeS(k, c))
|
||||||
|
|
||||||
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
case t.kind
|
case t.kind
|
||||||
|
of tyTypeClass: nil
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
result = lookupTypeVar(cl, t)
|
result = lookupTypeVar(cl, t)
|
||||||
if result.kind == tyGenericInvokation:
|
if result.kind == tyGenericInvokation:
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ type
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible, isIntConv, isSubtype,
|
isNone, isConvertible, isIntConv, isSubtype,
|
||||||
isGeneric,
|
isGeneric
|
||||||
isEqual
|
isEqual
|
||||||
|
|
||||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||||
|
|
@ -208,10 +208,32 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
var y = a.n.sons[i].sym
|
var y = a.n.sons[i].sym
|
||||||
if x.name.id != y.name.id: return isNone
|
if x.name.id != y.name.id: return isNone
|
||||||
|
|
||||||
proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
result = isNone
|
for i in countup(0, f.sonsLen - 1):
|
||||||
if f.kind == a.kind: result = isGeneric
|
let son = f.sons[i]
|
||||||
|
var match = son.kind == a.kind
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
case son.kind
|
||||||
|
of tyGenericBody:
|
||||||
|
if a.kind == tyGenericInst and a.sons[0] == son:
|
||||||
|
match = true
|
||||||
|
put(mapping, f, a)
|
||||||
|
of tyTypeClass:
|
||||||
|
match = matchTypeClass(mapping, son, a) == isGeneric
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
if tfAny in f.flags:
|
||||||
|
if match == true:
|
||||||
|
return isGeneric
|
||||||
|
else:
|
||||||
|
if match == false:
|
||||||
|
return isNone
|
||||||
|
|
||||||
|
# if the loop finished without returning, either all constraints matched
|
||||||
|
# or none of them matched.
|
||||||
|
result = if tfAny in f.flags: isNone else: isGeneric
|
||||||
|
|
||||||
proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||||
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
||||||
|
|
@ -261,7 +283,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
assert(a != nil)
|
assert(a != nil)
|
||||||
if a.kind == tyGenericInst and
|
if a.kind == tyGenericInst and
|
||||||
skipTypes(f, {tyVar}).kind notin {
|
skipTypes(f, {tyVar}).kind notin {
|
||||||
tyGenericBody, tyGenericInvokation, tyGenericParam}:
|
tyGenericBody, tyGenericInvokation,
|
||||||
|
tyGenericParam, tyTypeClass }:
|
||||||
return typeRel(mapping, f, lastSon(a))
|
return typeRel(mapping, f, lastSon(a))
|
||||||
if a.kind == tyVar and f.kind != tyVar:
|
if a.kind == tyVar and f.kind != tyVar:
|
||||||
return typeRel(mapping, f, a.sons[0])
|
return typeRel(mapping, f, a.sons[0])
|
||||||
|
|
@ -340,11 +363,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
result = typeRel(mapping, f.sons[0], a.sons[0])
|
result = typeRel(mapping, f.sons[0], a.sons[0])
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
else: nil
|
else: nil
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if f.sons[0].kind != tyGenericParam:
|
if isOrdinalType(a):
|
||||||
# some constraint:
|
|
||||||
result = constraintRel(mapping, f.sons[0], a)
|
|
||||||
elif isOrdinalType(a):
|
|
||||||
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||||
result = typeRel(mapping, f.sons[0], x)
|
result = typeRel(mapping, f.sons[0], x)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
|
|
@ -415,7 +435,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
let ff = lastSon(f)
|
let ff = lastSon(f)
|
||||||
if ff != nil: result = typeRel(mapping, ff, a)
|
if ff != nil: result = typeRel(mapping, ff, a)
|
||||||
of tyGenericInvokation:
|
of tyGenericInvokation:
|
||||||
assert(f.sons[0].kind == tyGenericBody)
|
assert(f.sons[0].kind == tyGenericBody)
|
||||||
if a.kind == tyGenericInvokation:
|
if a.kind == tyGenericInvokation:
|
||||||
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
|
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
|
||||||
|
|
@ -463,7 +483,19 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(mapping, x, a) # check if it fits
|
result = typeRel(mapping, x, a) # check if it fits
|
||||||
of tyExpr, tyStmt, tyTypeDesc:
|
of tyTypeClass:
|
||||||
|
result = matchTypeClass(mapping, f, a)
|
||||||
|
if result == isGeneric: put(mapping, f, a)
|
||||||
|
of tyTypeDesc:
|
||||||
|
if a.kind == tyTypeDesc:
|
||||||
|
if f.sonsLen == 0:
|
||||||
|
result = isGeneric
|
||||||
|
else:
|
||||||
|
result = matchTypeClass(mapping, f, a.sons[0])
|
||||||
|
if result == isGeneric: put(mapping, f, a)
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
of tyExpr, tyStmt:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else: internalError("typeRel(" & $f.kind & ')')
|
else: internalError("typeRel(" & $f.kind & ')')
|
||||||
|
|
||||||
|
|
@ -506,9 +538,34 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
arg, argOrig: PNode): PNode =
|
arg, argOrig: PNode): PNode =
|
||||||
var r = typeRel(m.bindings, f, a)
|
var r: TTypeRelation
|
||||||
|
if f.kind == tyExpr:
|
||||||
|
if f.sonsLen == 0:
|
||||||
|
r = isGeneric
|
||||||
|
else:
|
||||||
|
let match = matchTypeClass(m.bindings, f, a)
|
||||||
|
if match != isGeneric: r = isNone
|
||||||
|
else:
|
||||||
|
# XXX: Ideally, this should happen much earlier somewhere near
|
||||||
|
# semOpAux, but to do that, we need to be able to query the
|
||||||
|
# overload set to determine whether compile-time value is expected
|
||||||
|
# for the param before entering the full-blown sigmatch algorithm.
|
||||||
|
# This is related to the immediate pragma since querying the
|
||||||
|
# overload set could help there too.
|
||||||
|
var evaluated = c.semConstExpr(c, arg)
|
||||||
|
if evaluated != nil:
|
||||||
|
r = isGeneric
|
||||||
|
arg.typ = newTypeS(tyExpr, c)
|
||||||
|
arg.typ.n = evaluated
|
||||||
|
|
||||||
|
if r == isGeneric:
|
||||||
|
put(m.bindings, f, arg.typ)
|
||||||
|
else:
|
||||||
|
r = typeRel(m.bindings, f, a)
|
||||||
|
|
||||||
case r
|
case r
|
||||||
of isConvertible:
|
of isConvertible:
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
|
|
|
||||||
|
|
@ -429,7 +429,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
result = generateThunk(c, x, dest).ptransnode
|
result = generateThunk(c, x, dest).ptransnode
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyGenericParam, tyOrdinal:
|
of tyGenericParam, tyOrdinal, tyTypeClass:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
# happens sometimes for generated assignments, etc.
|
# happens sometimes for generated assignments, etc.
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,13 @@ proc enumHasHoles*(t: PType): bool
|
||||||
const
|
const
|
||||||
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
||||||
tyConst, tyMutable}
|
tyConst, tyMutable}
|
||||||
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
|
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
|
||||||
tyConst, tyMutable}
|
tyConst, tyMutable}
|
||||||
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
|
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
|
||||||
tyConst, tyMutable}
|
tyConst, tyMutable}
|
||||||
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||||
tyConst, tyMutable}
|
tyConst, tyMutable}
|
||||||
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable}
|
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal}
|
||||||
|
|
||||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
|
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
|
||||||
|
|
||||||
|
|
@ -383,7 +383,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
"int16", "int32", "int64", "float", "float32", "float64", "float128",
|
"int16", "int32", "int64", "float", "float32", "float64", "float128",
|
||||||
|
|
||||||
"uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ",
|
"uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ",
|
||||||
"!", "varargs[$1]", "iter[$1]", "proxy[$1]"]
|
"!", "varargs[$1]", "iter[$1]", "proxy[$1]", "TypeClass" ]
|
||||||
var t = typ
|
var t = typ
|
||||||
result = ""
|
result = ""
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
|
|
@ -729,9 +729,11 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
while a.kind == tyDistinct: a = a.sons[0]
|
while a.kind == tyDistinct: a = a.sons[0]
|
||||||
if a.kind != b.kind: return false
|
if a.kind != b.kind: return false
|
||||||
case a.Kind
|
case a.Kind
|
||||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||||
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc:
|
tyInt..tyBigNum, tyStmt:
|
||||||
result = true
|
result = true
|
||||||
|
of tyExpr:
|
||||||
|
result = ExprStructuralEquivalent(a.n, b.n)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
IfFastObjectTypeCheckFailed(a, b):
|
IfFastObjectTypeCheckFailed(a, b):
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
|
|
@ -748,8 +750,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
result = sameTuple(a, b, c)
|
result = sameTuple(a, b, c)
|
||||||
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
|
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
|
||||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
|
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
|
||||||
tyOrdinal, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter:
|
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
||||||
|
tyOrdinal, tyTypeDesc, tyTypeClass:
|
||||||
if sonsLen(a) == sonsLen(b):
|
if sonsLen(a) == sonsLen(b):
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -845,7 +848,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
result = typeAllowedAux(marker, t.sons[0], skResult)
|
result = typeAllowedAux(marker, t.sons[0], skResult)
|
||||||
of tyExpr, tyStmt, tyTypeDesc:
|
of tyExpr, tyStmt, tyTypeDesc:
|
||||||
result = true
|
result = true
|
||||||
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
|
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation, tyTypeClass:
|
||||||
result = false #InternalError('shit found');
|
result = false #InternalError('shit found');
|
||||||
of tyEmpty, tyNil:
|
of tyEmpty, tyNil:
|
||||||
result = kind == skConst
|
result = kind == skConst
|
||||||
|
|
|
||||||
|
|
@ -2177,7 +2177,7 @@ proc InstantiationInfo*(index = -1): tuple[filename: string, line: int] {.
|
||||||
## This is only useful for advanced meta programming. See the implementation
|
## This is only useful for advanced meta programming. See the implementation
|
||||||
## of `assert` for an example.
|
## of `assert` for an example.
|
||||||
|
|
||||||
proc raiseAssert(msg: string) {.noinline.} =
|
proc raiseAssert*(msg: string) {.noinline.} =
|
||||||
raise newException(EAssertionFailed, msg)
|
raise newException(EAssertionFailed, msg)
|
||||||
|
|
||||||
template assert*(cond: bool, msg = "") =
|
template assert*(cond: bool, msg = "") =
|
||||||
|
|
@ -2186,7 +2186,7 @@ template assert*(cond: bool, msg = "") =
|
||||||
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
||||||
## not generate any code at all for ``assert`` if it is advised to do so.
|
## not generate any code at all for ``assert`` if it is advised to do so.
|
||||||
## Use ``assert`` for debugging purposes only.
|
## Use ``assert`` for debugging purposes only.
|
||||||
bind raiseAssert, InstantiationInfo
|
bind InstantiationInfo
|
||||||
when compileOption("assertions"):
|
when compileOption("assertions"):
|
||||||
{.line.}:
|
{.line.}:
|
||||||
if not cond:
|
if not cond:
|
||||||
|
|
@ -2195,11 +2195,33 @@ template assert*(cond: bool, msg = "") =
|
||||||
template doAssert*(cond: bool, msg = "") =
|
template doAssert*(cond: bool, msg = "") =
|
||||||
## same as `assert` but is always turned on and not affected by the
|
## same as `assert` but is always turned on and not affected by the
|
||||||
## ``--assertions`` command line switch.
|
## ``--assertions`` command line switch.
|
||||||
bind raiseAssert, InstantiationInfo
|
bind InstantiationInfo
|
||||||
{.line: InstantiationInfo().}:
|
{.line: InstantiationInfo().}:
|
||||||
if not cond:
|
if not cond:
|
||||||
raiseAssert(astToStr(cond) & ' ' & msg)
|
raiseAssert(astToStr(cond) & ' ' & msg)
|
||||||
|
|
||||||
|
template onFailedAssert*(msg: expr, code: stmt): stmt =
|
||||||
|
## Sets an assertion failure handler that will intercept any assert statements
|
||||||
|
## following `onFailedAssert` in the current lexical scope.
|
||||||
|
## Can be defined multiple times in a single function.
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
##
|
||||||
|
## proc example(x: int): TErrorCode =
|
||||||
|
## onFailedAssert(msg):
|
||||||
|
## log msg
|
||||||
|
## return E_FAIL
|
||||||
|
##
|
||||||
|
## assert(...)
|
||||||
|
##
|
||||||
|
## onFailedAssert(msg):
|
||||||
|
## raise newException(EMyException, msg)
|
||||||
|
##
|
||||||
|
## assert(...)
|
||||||
|
##
|
||||||
|
template raiseAssert(msgIMPL: string): stmt =
|
||||||
|
let `msg` = msgIMPL
|
||||||
|
code
|
||||||
|
|
||||||
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
||||||
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
||||||
|
|
|
||||||
12
tests/compile/tgensym.nim
Normal file
12
tests/compile/tgensym.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
template hygienic(val: expr) =
|
||||||
|
var `*x` = val
|
||||||
|
stdout.write `*x`
|
||||||
|
|
||||||
|
var x = 100
|
||||||
|
|
||||||
|
hygienic 1
|
||||||
|
hygienic 2
|
||||||
|
hygienic 3
|
||||||
|
|
||||||
|
echo x
|
||||||
|
|
||||||
34
tests/compile/ttypeclasses.nim
Normal file
34
tests/compile/ttypeclasses.nim
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
type
|
||||||
|
TFoo[T] = object
|
||||||
|
val: T
|
||||||
|
|
||||||
|
T1 = distinct expr
|
||||||
|
T2 = distinct expr
|
||||||
|
|
||||||
|
proc takesExpr(x, y) =
|
||||||
|
echo x, y
|
||||||
|
|
||||||
|
proc same(x, y: T1) =
|
||||||
|
echo x, y
|
||||||
|
|
||||||
|
proc takesFoo(x, y: TFoo) =
|
||||||
|
echo x.val, y.val
|
||||||
|
|
||||||
|
proc takes2Types(x,y: T1, z: T2) =
|
||||||
|
echo x, y, z
|
||||||
|
|
||||||
|
takesExpr(1, 2)
|
||||||
|
takesExpr(1, "xxx")
|
||||||
|
takesExpr[bool, int](true, 0)
|
||||||
|
|
||||||
|
same(1, 2)
|
||||||
|
same("test", "test")
|
||||||
|
|
||||||
|
var f: TFoo[int]
|
||||||
|
f.val = 10
|
||||||
|
|
||||||
|
takesFoo(f, f)
|
||||||
|
|
||||||
|
takes2Types(1, 1, "string")
|
||||||
|
takes2Types[string, int]("test", "test", 1)
|
||||||
|
|
||||||
17
tests/run/tmemoization.nim
Normal file
17
tests/run/tmemoization.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
msg: "test 1\ntest 2"
|
||||||
|
output: "TEST 1\nTEST 2\nTEST 2"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
proc foo(s: expr{string}): string =
|
||||||
|
static: echo s
|
||||||
|
|
||||||
|
const R = s.toUpper
|
||||||
|
return R
|
||||||
|
|
||||||
|
echo foo("test 1")
|
||||||
|
echo foo("test 2")
|
||||||
|
echo foo("test " & $2)
|
||||||
|
|
||||||
35
tests/run/ttypedesc1.nim
Normal file
35
tests/run/ttypedesc1.nim
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo[T, U] = object
|
||||||
|
x: T
|
||||||
|
y: U
|
||||||
|
|
||||||
|
proc foo(T: typedesc{float}, a: expr): string =
|
||||||
|
result = "float " & $(a.len > 5)
|
||||||
|
|
||||||
|
proc foo(T: typedesc{TFoo}, a: int): string =
|
||||||
|
result = "TFoo " & $(a)
|
||||||
|
|
||||||
|
proc foo(T: typedesc{int or bool}): string =
|
||||||
|
var a: T
|
||||||
|
a = 10
|
||||||
|
result = "int or bool " & ($a)
|
||||||
|
|
||||||
|
template foo(T: typedesc{seq}): expr = "seq"
|
||||||
|
|
||||||
|
test "types can be used as proc params":
|
||||||
|
check foo(TFoo[int, float], 1000) == "TFoo 1000"
|
||||||
|
|
||||||
|
var f = 10.0
|
||||||
|
check foo(float, "long string") == "float true"
|
||||||
|
check foo(type(f), [1, 2, 3]) == "float false"
|
||||||
|
|
||||||
|
check foo(int) == "int or bool 10"
|
||||||
|
|
||||||
|
check foo(seq[int]) == "seq"
|
||||||
|
check foo(seq[TFoo[bool, string]]) == "seq"
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc foo(T: typedesc{seq}, s: T) = nil
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue