Merge ../Nim into devel
This commit is contained in:
commit
9c3c48a6d0
22 changed files with 455 additions and 102 deletions
|
|
@ -90,3 +90,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimnode")
|
defineSymbol("nimnode")
|
||||||
defineSymbol("nimnomagic64")
|
defineSymbol("nimnomagic64")
|
||||||
defineSymbol("nimvarargstyped")
|
defineSymbol("nimvarargstyped")
|
||||||
|
defineSymbol("nimtypedescfixed")
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
|
||||||
var params = routine.ast.sons[paramsPos]
|
var params = routine.ast.sons[paramsPos]
|
||||||
# -1 is correct here as param.position is 0 based but we have at position 0
|
# -1 is correct here as param.position is 0 based but we have at position 0
|
||||||
# some nkEffect node:
|
# some nkEffect node:
|
||||||
param.position = params.len-1
|
param.position = routine.typ.n.len-1
|
||||||
addSon(params, newSymNode(param))
|
addSon(params, newSymNode(param))
|
||||||
incl(routine.typ.flags, tfCapturesEnv)
|
incl(routine.typ.flags, tfCapturesEnv)
|
||||||
assert sfFromGeneric in param.flags
|
assert sfFromGeneric in param.flags
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,15 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||||
else:
|
else:
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
proc createDestructorCall(c: PContext, s: PSym): PNode =
|
||||||
|
let varTyp = s.typ
|
||||||
|
if varTyp == nil or sfGlobal in s.flags: return
|
||||||
|
let destructableT = instantiateDestructor(c, varTyp)
|
||||||
|
if destructableT != nil:
|
||||||
|
let call = semStmt(c, newNode(nkCall, s.info, @[
|
||||||
|
useSym(destructableT.destructor), useSym(s)]))
|
||||||
|
result = newNode(nkDefer, s.info, @[call])
|
||||||
|
|
||||||
proc insertDestructors(c: PContext,
|
proc insertDestructors(c: PContext,
|
||||||
varSection: PNode): tuple[outer, inner: PNode] =
|
varSection: PNode): tuple[outer, inner: PNode] =
|
||||||
# Accepts a var or let section.
|
# Accepts a var or let section.
|
||||||
|
|
|
||||||
|
|
@ -2259,7 +2259,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkStaticStmt:
|
of nkStaticStmt:
|
||||||
result = semStaticStmt(c, n)
|
result = semStaticStmt(c, n)
|
||||||
of nkDefer:
|
of nkDefer:
|
||||||
localError(n.info, errGenerated, "'defer' not allowed in this context")
|
n.sons[0] = semExpr(c, n.sons[0])
|
||||||
|
if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]):
|
||||||
|
localError(n.info, errGenerated, "'defer' takes a 'void' expression")
|
||||||
|
#localError(n.info, errGenerated, "'defer' not allowed in this context")
|
||||||
else:
|
else:
|
||||||
localError(n.info, errInvalidExpressionX,
|
localError(n.info, errInvalidExpressionX,
|
||||||
renderTree(n, {renderNoComments}))
|
renderTree(n, {renderNoComments}))
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,9 @@ type
|
||||||
proc semGenericStmt(c: PContext, n: PNode,
|
proc semGenericStmt(c: PContext, n: PNode,
|
||||||
flags: TSemGenericFlags, ctx: var GenericCtx): PNode
|
flags: TSemGenericFlags, ctx: var GenericCtx): PNode
|
||||||
|
|
||||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||||
flags: TSemGenericFlags,
|
flags: TSemGenericFlags,
|
||||||
ctx: var GenericCtx): PNode =
|
ctx: var GenericCtx): PNode =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
result = semGenericStmt(c, n, flags, ctx)
|
result = semGenericStmt(c, n, flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
@ -73,7 +73,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||||
result = semGenericStmt(c, result, {}, ctx)
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
if s.typ != nil and s.typ.kind == tyStatic:
|
if s.typ != nil and s.typ.kind == tyStatic:
|
||||||
if s.typ.n != nil:
|
if s.typ.n != nil:
|
||||||
result = s.typ.n
|
result = s.typ.n
|
||||||
|
|
@ -85,18 +85,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||||
of skParam:
|
of skParam:
|
||||||
result = n
|
result = n
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
of skType:
|
of skType:
|
||||||
if (s.typ != nil) and
|
if (s.typ != nil) and
|
||||||
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
|
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
result = newSymNodeTypeDesc(s, n.info)
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
else:
|
else:
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
|
|
||||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
ctx: var GenericCtx): PNode =
|
ctx: var GenericCtx): PNode =
|
||||||
result = n
|
result = n
|
||||||
let ident = considerQuotedIdent(n)
|
let ident = considerQuotedIdent(n)
|
||||||
|
|
@ -118,13 +118,13 @@ proc newDot(n, b: PNode): PNode =
|
||||||
result.add(n.sons[0])
|
result.add(n.sons[0])
|
||||||
result.add(b)
|
result.add(b)
|
||||||
|
|
||||||
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
ctx: var GenericCtx; isMacro: var bool): PNode =
|
ctx: var GenericCtx; isMacro: var bool): PNode =
|
||||||
assert n.kind == nkDotExpr
|
assert n.kind == nkDotExpr
|
||||||
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
||||||
|
|
||||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||||
|
|
||||||
var s = qualifiedLookUp(c, n, luf)
|
var s = qualifiedLookUp(c, n, luf)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
result = semGenericStmtSymbol(c, n, s, ctx)
|
result = semGenericStmtSymbol(c, n, s, ctx)
|
||||||
|
|
@ -141,18 +141,20 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
elif s.name.id in ctx.toMixin:
|
elif s.name.id in ctx.toMixin:
|
||||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||||
else:
|
else:
|
||||||
let sym = semGenericStmtSymbol(c, n, s, ctx)
|
let syms = semGenericStmtSymbol(c, n, s, ctx)
|
||||||
if sym.kind == nkSym:
|
if syms.kind == nkSym:
|
||||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
let choice = symChoice(c, n, s, scForceOpen)
|
||||||
|
choice.kind = nkClosedSymChoice
|
||||||
|
result = newDot(result, choice)
|
||||||
else:
|
else:
|
||||||
result = newDot(result, sym)
|
result = newDot(result, syms)
|
||||||
|
|
||||||
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||||
let s = newSymS(skUnknown, getIdentNode(n), c)
|
let s = newSymS(skUnknown, getIdentNode(n), c)
|
||||||
addPrelimDecl(c, s)
|
addPrelimDecl(c, s)
|
||||||
styleCheckDef(n.info, s, kind)
|
styleCheckDef(n.info, s, kind)
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode,
|
proc semGenericStmt(c: PContext, n: PNode,
|
||||||
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
|
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
|
||||||
result = n
|
result = n
|
||||||
#if gCmd == cmdIdeTools: suggestStmt(c, n)
|
#if gCmd == cmdIdeTools: suggestStmt(c, n)
|
||||||
|
|
@ -181,16 +183,16 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
|
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
|
||||||
of nkMixinStmt:
|
of nkMixinStmt:
|
||||||
result = semMixinStmt(c, n, ctx.toMixin)
|
result = semMixinStmt(c, n, ctx.toMixin)
|
||||||
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
|
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
|
||||||
# check if it is an expression macro:
|
# check if it is an expression macro:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
let fn = n.sons[0]
|
let fn = n.sons[0]
|
||||||
var s = qualifiedLookUp(c, fn, {})
|
var s = qualifiedLookUp(c, fn, {})
|
||||||
if s == nil and withinMixin notin flags and
|
if s == nil and withinMixin notin flags and
|
||||||
fn.kind in {nkIdent, nkAccQuoted} and
|
fn.kind in {nkIdent, nkAccQuoted} and
|
||||||
considerQuotedIdent(fn).id notin ctx.toMixin:
|
considerQuotedIdent(fn).id notin ctx.toMixin:
|
||||||
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
||||||
|
|
||||||
var first = 0
|
var first = 0
|
||||||
var mixinContext = false
|
var mixinContext = false
|
||||||
if s != nil:
|
if s != nil:
|
||||||
|
|
@ -220,7 +222,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
# we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
|
# we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
|
||||||
# the famous "undeclared identifier: it" bug:
|
# the famous "undeclared identifier: it" bug:
|
||||||
mixinContext = true
|
mixinContext = true
|
||||||
of skUnknown, skParam:
|
of skUnknown, skParam:
|
||||||
# Leave it as an identifier.
|
# Leave it as an identifier.
|
||||||
discard
|
discard
|
||||||
of skProc, skMethod, skIterators, skConverter:
|
of skProc, skMethod, skIterators, skConverter:
|
||||||
|
|
@ -230,9 +232,9 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||||
styleCheckUse(fn.info, s)
|
styleCheckUse(fn.info, s)
|
||||||
first = 1
|
first = 1
|
||||||
of skType:
|
of skType:
|
||||||
# bad hack for generics:
|
# bad hack for generics:
|
||||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||||
styleCheckUse(fn.info, s)
|
styleCheckUse(fn.info, s)
|
||||||
first = 1
|
first = 1
|
||||||
|
|
@ -244,34 +246,34 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||||
first = 1
|
first = 1
|
||||||
# Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
# Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
||||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||||
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
||||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||||
for i in countup(first, sonsLen(result) - 1):
|
for i in countup(first, sonsLen(result) - 1):
|
||||||
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
||||||
of nkIfStmt:
|
of nkIfStmt:
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
|
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
|
||||||
of nkWhenStmt:
|
of nkWhenStmt:
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx)
|
n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx)
|
||||||
of nkWhileStmt:
|
of nkWhileStmt:
|
||||||
openScope(c)
|
openScope(c)
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
of nkCaseStmt:
|
of nkCaseStmt:
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
|
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
|
||||||
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]
|
||||||
checkMinSonsLen(a, 1)
|
checkMinSonsLen(a, 1)
|
||||||
var L = sonsLen(a)
|
var L = sonsLen(a)
|
||||||
for j in countup(0, L-2):
|
for j in countup(0, L-2):
|
||||||
a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
|
a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
|
||||||
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
of nkForStmt, nkParForStmt:
|
of nkForStmt, nkParForStmt:
|
||||||
var L = sonsLen(n)
|
var L = sonsLen(n)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
||||||
|
|
@ -279,27 +281,27 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
addTempDecl(c, n.sons[i], skForVar)
|
addTempDecl(c, n.sons[i], skForVar)
|
||||||
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
addTempDecl(c, n.sons[0], skLabel)
|
addTempDecl(c, n.sons[0], skLabel)
|
||||||
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
of nkTryStmt:
|
of nkTryStmt:
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
|
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
|
||||||
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]
|
||||||
checkMinSonsLen(a, 1)
|
checkMinSonsLen(a, 1)
|
||||||
var L = sonsLen(a)
|
var L = sonsLen(a)
|
||||||
for j in countup(0, L-2):
|
for j in countup(0, L-2):
|
||||||
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
|
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
|
||||||
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||||
of nkVarSection, nkLetSection:
|
of nkVarSection, nkLetSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
|
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
var L = sonsLen(a)
|
var L = sonsLen(a)
|
||||||
|
|
@ -307,49 +309,49 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
|
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
|
||||||
of nkGenericParams:
|
of nkGenericParams:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
var L = sonsLen(a)
|
var L = sonsLen(a)
|
||||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||||
# do not perform symbol lookup for default expressions
|
# do not perform symbol lookup for default expressions
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
addTempDecl(c, getIdentNode(a.sons[j]), skType)
|
addTempDecl(c, getIdentNode(a.sons[j]), skType)
|
||||||
of nkConstSection:
|
of nkConstSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkConstDef): illFormedAst(a)
|
if (a.kind != nkConstDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
|
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
|
||||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
||||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
||||||
of nkTypeSection:
|
of nkTypeSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
addTempDecl(c, getIdentNode(a.sons[0]), skType)
|
addTempDecl(c, getIdentNode(a.sons[0]), skType)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
if a.sons[1].kind != nkEmpty:
|
if a.sons[1].kind != nkEmpty:
|
||||||
openScope(c)
|
openScope(c)
|
||||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
|
a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
|
||||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
else:
|
else:
|
||||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
||||||
of nkEnumTy:
|
of nkEnumTy:
|
||||||
if n.sonsLen > 0:
|
if n.sonsLen > 0:
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
var a: PNode
|
var a: PNode
|
||||||
case n.sons[i].kind
|
case n.sons[i].kind
|
||||||
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
||||||
|
|
@ -360,26 +362,26 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
discard
|
discard
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||||
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 != nkIdentDefs): illFormedAst(a)
|
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
var L = sonsLen(a)
|
var L = sonsLen(a)
|
||||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
|
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||||
nkIteratorDef, nkLambdaKinds:
|
nkIteratorDef, nkLambdaKinds:
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
if n.sons[namePos].kind != nkEmpty:
|
if n.sons[namePos].kind != nkEmpty:
|
||||||
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
|
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
||||||
flags, ctx)
|
flags, ctx)
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
if n.sons[paramsPos].kind != nkEmpty:
|
||||||
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
||||||
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
|
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
|
||||||
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
||||||
|
|
@ -394,7 +396,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode): PNode =
|
proc semGenericStmt(c: PContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,15 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
|
||||||
else:
|
else:
|
||||||
result.add identDefs
|
result.add identDefs
|
||||||
|
|
||||||
|
proc addDefer(c: PContext; result: var PNode; s: PSym) =
|
||||||
|
let deferDestructorCall = createDestructorCall(c, s)
|
||||||
|
if deferDestructorCall != nil:
|
||||||
|
if result.kind != nkStmtList:
|
||||||
|
let oldResult = result
|
||||||
|
result = newNodeI(nkStmtList, result.info)
|
||||||
|
result.add oldResult
|
||||||
|
result.add deferDestructorCall
|
||||||
|
|
||||||
proc isDiscardUnderscore(v: PSym): bool =
|
proc isDiscardUnderscore(v: PSym): bool =
|
||||||
if v.name.s == "_":
|
if v.name.s == "_":
|
||||||
v.flags.incl(sfGenSym)
|
v.flags.incl(sfGenSym)
|
||||||
|
|
@ -469,6 +478,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
if def.kind == nkPar: v.ast = def[j]
|
if def.kind == nkPar: v.ast = def[j]
|
||||||
v.typ = tup.sons[j]
|
v.typ = tup.sons[j]
|
||||||
b.sons[j] = newSymNode(v)
|
b.sons[j] = newSymNode(v)
|
||||||
|
addDefer(c, result, v)
|
||||||
checkNilable(v)
|
checkNilable(v)
|
||||||
if sfCompileTime in v.flags: hasCompileTime = true
|
if sfCompileTime in v.flags: hasCompileTime = true
|
||||||
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
||||||
|
|
@ -1371,7 +1381,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
for i in countup(0, length - 1):
|
for i in countup(0, length - 1):
|
||||||
let k = n.sons[i].kind
|
let k = n.sons[i].kind
|
||||||
case k
|
case k
|
||||||
of nkFinally, nkExceptBranch, nkDefer:
|
of nkFinally, nkExceptBranch:
|
||||||
# stand-alone finally and except blocks are
|
# stand-alone finally and except blocks are
|
||||||
# transformed into regular try blocks:
|
# transformed into regular try blocks:
|
||||||
#
|
#
|
||||||
|
|
@ -1424,21 +1434,13 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||||
case n.sons[i].kind
|
case n.sons[i].kind
|
||||||
of nkVarSection, nkLetSection:
|
|
||||||
let (outer, inner) = insertDestructors(c, n.sons[i])
|
|
||||||
if outer != nil:
|
|
||||||
n.sons[i] = outer
|
|
||||||
var rest = newNode(nkStmtList, n.info, n.sons[i+1 .. length-1])
|
|
||||||
inner.addSon(semStmtList(c, rest, flags))
|
|
||||||
n.sons.setLen(i+1)
|
|
||||||
return
|
|
||||||
of LastBlockStmts:
|
of LastBlockStmts:
|
||||||
for j in countup(i + 1, length - 1):
|
for j in countup(i + 1, length - 1):
|
||||||
case n.sons[j].kind
|
case n.sons[j].kind
|
||||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
||||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||||
else: discard
|
else: discard
|
||||||
if result.len == 1:
|
if result.len == 1 and result.sons[0].kind != nkDefer:
|
||||||
result = result.sons[0]
|
result = result.sons[0]
|
||||||
when defined(nimfix):
|
when defined(nimfix):
|
||||||
if result.kind == nkCommentStmt and not result.comment.isNil and
|
if result.kind == nkCommentStmt and not result.comment.isNil and
|
||||||
|
|
|
||||||
|
|
@ -184,10 +184,25 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||||
else:
|
else:
|
||||||
let ident = getIdentNode(c, n)
|
let ident = getIdentNode(c, n)
|
||||||
if not isTemplParam(c, ident):
|
if not isTemplParam(c, ident):
|
||||||
let local = newGenSym(k, ident, c)
|
# fix #2670, consider:
|
||||||
addPrelimDecl(c.c, local)
|
#
|
||||||
styleCheckDef(n.info, local)
|
# when b:
|
||||||
replaceIdentBySym(n, newSymNode(local, n.info))
|
# var a = "hi"
|
||||||
|
# else:
|
||||||
|
# var a = 5
|
||||||
|
# echo a
|
||||||
|
#
|
||||||
|
# We need to ensure that both 'a' produce the same gensym'ed symbol.
|
||||||
|
# So we need only check the *current* scope.
|
||||||
|
let s = localSearchInScope(c.c, considerQuotedIdent ident)
|
||||||
|
if s != nil and s.owner == c.owner and sfGenSym in s.flags:
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
replaceIdentBySym(n, newSymNode(s, n.info))
|
||||||
|
else:
|
||||||
|
let local = newGenSym(k, ident, c)
|
||||||
|
addPrelimDecl(c.c, local)
|
||||||
|
styleCheckDef(n.info, local)
|
||||||
|
replaceIdentBySym(n, newSymNode(local, n.info))
|
||||||
else:
|
else:
|
||||||
replaceIdentBySym(n, ident)
|
replaceIdentBySym(n, ident)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
# * converts "continue" to "break"; disambiguates "break"
|
# * converts "continue" to "break"; disambiguates "break"
|
||||||
# * introduces method dispatchers
|
# * introduces method dispatchers
|
||||||
# * performs lambda lifting for closure support
|
# * performs lambda lifting for closure support
|
||||||
|
# * transforms 'defer' into a 'try finally' statement
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||||
|
|
@ -44,6 +45,7 @@ type
|
||||||
inlining: int # > 0 if we are in inlining context (copy vars)
|
inlining: int # > 0 if we are in inlining context (copy vars)
|
||||||
nestedProcs: int # > 0 if we are in a nested proc
|
nestedProcs: int # > 0 if we are in a nested proc
|
||||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||||
|
deferDetected: bool
|
||||||
PTransf = ref TTransfContext
|
PTransf = ref TTransfContext
|
||||||
|
|
||||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||||
|
|
@ -680,6 +682,14 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
|
when false:
|
||||||
|
var oldDeferAnchor: PNode
|
||||||
|
if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
|
||||||
|
nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
|
||||||
|
nkBlockStmt, nkBlockExpr}:
|
||||||
|
oldDeferAnchor = c.deferAnchor
|
||||||
|
c.deferAnchor = n
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = transformSym(c, n)
|
result = transformSym(c, n)
|
||||||
|
|
@ -712,13 +722,36 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformFor(c, n)
|
result = transformFor(c, n)
|
||||||
of nkParForStmt:
|
of nkParForStmt:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of nkCaseStmt: result = transformCase(c, n)
|
of nkCaseStmt:
|
||||||
|
result = transformCase(c, n)
|
||||||
|
of nkWhileStmt: result = transformWhile(c, n)
|
||||||
|
of nkBlockStmt, nkBlockExpr:
|
||||||
|
result = transformBlock(c, n)
|
||||||
|
of nkDefer:
|
||||||
|
c.deferDetected = true
|
||||||
|
result = transformSons(c, n)
|
||||||
|
when false:
|
||||||
|
let deferPart = newNodeI(nkFinally, n.info)
|
||||||
|
deferPart.add n.sons[0]
|
||||||
|
let tryStmt = newNodeI(nkTryStmt, n.info)
|
||||||
|
if c.deferAnchor.isNil:
|
||||||
|
tryStmt.add c.root
|
||||||
|
c.root = tryStmt
|
||||||
|
result = PTransNode(tryStmt)
|
||||||
|
else:
|
||||||
|
# modify the corresponding *action*, don't rely on nkStmtList:
|
||||||
|
let L = c.deferAnchor.len-1
|
||||||
|
tryStmt.add c.deferAnchor.sons[L]
|
||||||
|
c.deferAnchor.sons[L] = tryStmt
|
||||||
|
result = newTransNode(nkCommentStmt, n.info, 0)
|
||||||
|
tryStmt.addSon(deferPart)
|
||||||
|
# disable the original 'defer' statement:
|
||||||
|
n.kind = nkCommentStmt
|
||||||
of nkContinueStmt:
|
of nkContinueStmt:
|
||||||
result = PTransNode(newNodeI(nkBreakStmt, n.info))
|
result = PTransNode(newNodeI(nkBreakStmt, n.info))
|
||||||
var labl = c.contSyms[c.contSyms.high]
|
var labl = c.contSyms[c.contSyms.high]
|
||||||
add(result, PTransNode(newSymNode(labl)))
|
add(result, PTransNode(newSymNode(labl)))
|
||||||
of nkBreakStmt: result = transformBreak(c, n)
|
of nkBreakStmt: result = transformBreak(c, n)
|
||||||
of nkWhileStmt: result = transformWhile(c, n)
|
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
result = transformCall(c, n)
|
result = transformCall(c, n)
|
||||||
of nkAddr, nkHiddenAddr:
|
of nkAddr, nkHiddenAddr:
|
||||||
|
|
@ -754,8 +787,6 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformYield(c, n)
|
result = transformYield(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of nkBlockStmt, nkBlockExpr:
|
|
||||||
result = transformBlock(c, n)
|
|
||||||
of nkIdentDefs, nkConstDef:
|
of nkIdentDefs, nkConstDef:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
# XXX comment handling really sucks:
|
# XXX comment handling really sucks:
|
||||||
|
|
@ -764,6 +795,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
of nkClosure: return PTransNode(n)
|
of nkClosure: return PTransNode(n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
when false:
|
||||||
|
if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
|
||||||
var cnst = getConstExpr(c.module, PNode(result))
|
var cnst = getConstExpr(c.module, PNode(result))
|
||||||
# we inline constants if they are not complex constants:
|
# we inline constants if they are not complex constants:
|
||||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||||
|
|
@ -785,12 +818,52 @@ proc openTransf(module: PSym, filename: string): PTransf =
|
||||||
result.breakSyms = @[]
|
result.breakSyms = @[]
|
||||||
result.module = module
|
result.module = module
|
||||||
|
|
||||||
|
proc flattenStmts(n: PNode) =
|
||||||
|
var goOn = true
|
||||||
|
while goOn:
|
||||||
|
goOn = false
|
||||||
|
for i in 0..<n.len:
|
||||||
|
let it = n[i]
|
||||||
|
if it.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
|
n.sons[i..i] = it.sons[0..<it.len]
|
||||||
|
goOn = true
|
||||||
|
|
||||||
|
proc liftDeferAux(n: PNode) =
|
||||||
|
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
|
flattenStmts(n)
|
||||||
|
var goOn = true
|
||||||
|
while goOn:
|
||||||
|
goOn = false
|
||||||
|
let last = n.len-1
|
||||||
|
for i in 0..last:
|
||||||
|
if n.sons[i].kind == nkDefer:
|
||||||
|
let deferPart = newNodeI(nkFinally, n.sons[i].info)
|
||||||
|
deferPart.add n.sons[i].sons[0]
|
||||||
|
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
||||||
|
var body = newNodeI(n.kind, n.sons[i].info)
|
||||||
|
if i < last:
|
||||||
|
body.sons = n.sons[(i+1)..last]
|
||||||
|
tryStmt.addSon(body)
|
||||||
|
tryStmt.addSon(deferPart)
|
||||||
|
n.sons[i] = tryStmt
|
||||||
|
n.sons.setLen(i+1)
|
||||||
|
n.typ = n.sons[i].typ
|
||||||
|
goOn = true
|
||||||
|
break
|
||||||
|
for i in 0..n.safeLen-1:
|
||||||
|
liftDeferAux(n.sons[i])
|
||||||
|
|
||||||
|
template liftDefer(c, root) =
|
||||||
|
if c.deferDetected:
|
||||||
|
liftDeferAux(root)
|
||||||
|
|
||||||
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||||
if nfTransf in n.flags or prc.kind in {skTemplate}:
|
if nfTransf in n.flags or prc.kind in {skTemplate}:
|
||||||
result = n
|
result = n
|
||||||
else:
|
else:
|
||||||
var c = openTransf(module, "")
|
var c = openTransf(module, "")
|
||||||
result = processTransf(c, n, prc)
|
result = processTransf(c, n, prc)
|
||||||
|
liftDefer(c, result)
|
||||||
result = liftLambdas(prc, result)
|
result = liftLambdas(prc, result)
|
||||||
#if prc.kind == skClosureIterator:
|
#if prc.kind == skClosureIterator:
|
||||||
# result = lambdalifting.liftIterator(prc, result)
|
# result = lambdalifting.liftIterator(prc, result)
|
||||||
|
|
@ -805,6 +878,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
var c = openTransf(module, "")
|
var c = openTransf(module, "")
|
||||||
result = processTransf(c, n, module)
|
result = processTransf(c, n, module)
|
||||||
|
liftDefer(c, result)
|
||||||
result = liftLambdasForTopLevel(module, result)
|
result = liftLambdasForTopLevel(module, result)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
when useEffectSystem: trackTopLevelStmt(module, result)
|
when useEffectSystem: trackTopLevelStmt(module, result)
|
||||||
|
|
@ -815,4 +889,5 @@ proc transformExpr*(module: PSym, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
var c = openTransf(module, "")
|
var c = openTransf(module, "")
|
||||||
result = processTransf(c, n, module)
|
result = processTransf(c, n, module)
|
||||||
|
liftDefer(c, result)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
|
|
|
||||||
|
|
@ -432,7 +432,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
assert regs[rb].kind == rkNode
|
assert regs[rb].kind == rkNode
|
||||||
let nb = regs[rb].node
|
let nb = regs[rb].node
|
||||||
case nb.kind
|
case nb.kind
|
||||||
of nkCharLit..nkInt64Lit:
|
of nkCharLit..nkUInt64Lit:
|
||||||
ensureKind(rkInt)
|
ensureKind(rkInt)
|
||||||
regs[ra].intVal = nb.intVal
|
regs[ra].intVal = nb.intVal
|
||||||
of nkFloatLit..nkFloat64Lit:
|
of nkFloatLit..nkFloat64Lit:
|
||||||
|
|
|
||||||
|
|
@ -66,12 +66,14 @@ Running tests
|
||||||
You can run the tests with
|
You can run the tests with
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
./koch tests
|
./koch tests
|
||||||
|
|
||||||
which will run a good subset of tests. Some tests may fail. If you
|
which will run a good subset of tests. Some tests may fail. If you
|
||||||
only want to see the output of failing tests, go for
|
only want to see the output of failing tests, go for
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
./koch tests --failing all
|
./koch tests --failing all
|
||||||
|
|
||||||
You can also run only a single category of tests. A category is a subdirectory
|
You can also run only a single category of tests. A category is a subdirectory
|
||||||
|
|
@ -79,6 +81,7 @@ in the ``tests`` directory. There are a couple of special categories; for a
|
||||||
list of these, see ``tests/testament/categories.nim``, at the bottom.
|
list of these, see ``tests/testament/categories.nim``, at the bottom.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
./koch tests c lib
|
./koch tests c lib
|
||||||
|
|
||||||
Comparing tests
|
Comparing tests
|
||||||
|
|
@ -92,6 +95,7 @@ reference test. You'll also need to the commit id, because that's what
|
||||||
the tester needs to know in order to compare the two.
|
the tester needs to know in order to compare the two.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
git checkout devel
|
git checkout devel
|
||||||
DEVEL_COMMIT=$(git rev-parse HEAD)
|
DEVEL_COMMIT=$(git rev-parse HEAD)
|
||||||
./koch tests
|
./koch tests
|
||||||
|
|
@ -99,6 +103,7 @@ the tester needs to know in order to compare the two.
|
||||||
Then switch over to your changes and run the tester again.
|
Then switch over to your changes and run the tester again.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
git checkout your-changes
|
git checkout your-changes
|
||||||
./koch tests
|
./koch tests
|
||||||
|
|
||||||
|
|
@ -106,6 +111,7 @@ Then you can ask the tester to create a ``testresults.html`` which will
|
||||||
tell you if any new tests passed/failed.
|
tell you if any new tests passed/failed.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
./koch --print html $DEVEL_COMMIT
|
./koch --print html $DEVEL_COMMIT
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,10 @@ proc `$`*[A, B](t: Table[A, B]): string =
|
||||||
## The `$` operator for hash tables.
|
## The `$` operator for hash tables.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
|
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
|
||||||
|
## returns true iff `key` is in the table `t`.
|
||||||
|
result = t[].hasKey(key)
|
||||||
|
|
||||||
template equalsImpl() =
|
template equalsImpl() =
|
||||||
if s.counter == t.counter:
|
if s.counter == t.counter:
|
||||||
# different insertion orders mean different 'data' seqs, so we have
|
# different insertion orders mean different 'data' seqs, so we have
|
||||||
|
|
@ -293,10 +297,6 @@ proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
|
||||||
## returns true iff `key` is in the table, otherwise inserts `value`.
|
## returns true iff `key` is in the table, otherwise inserts `value`.
|
||||||
t[].hasKeyOrPut(key, val)
|
t[].hasKeyOrPut(key, val)
|
||||||
|
|
||||||
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
|
|
||||||
## returns true iff `key` is in the table `t`.
|
|
||||||
result = t[].hasKey(key)
|
|
||||||
|
|
||||||
proc contains*[A, B](t: TableRef[A, B], key: A): bool =
|
proc contains*[A, B](t: TableRef[A, B], key: A): bool =
|
||||||
## alias of `hasKey` for use with the `in` operator.
|
## alias of `hasKey` for use with the `in` operator.
|
||||||
return hasKey[A, B](t, key)
|
return hasKey[A, B](t, key)
|
||||||
|
|
|
||||||
|
|
@ -608,29 +608,29 @@ proc newJArray*(): JsonNode =
|
||||||
proc getStr*(n: JsonNode, default: string = ""): string =
|
proc getStr*(n: JsonNode, default: string = ""): string =
|
||||||
## Retrieves the string value of a `JString JsonNode`.
|
## Retrieves the string value of a `JString JsonNode`.
|
||||||
##
|
##
|
||||||
## Returns ``default`` if ``n`` is not a ``JString``.
|
## Returns ``default`` if ``n`` is not a ``JString``, or if ``n`` is nil.
|
||||||
if n.kind != JString: return default
|
if n.isNil or n.kind != JString: return default
|
||||||
else: return n.str
|
else: return n.str
|
||||||
|
|
||||||
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
|
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
|
||||||
## Retrieves the int value of a `JInt JsonNode`.
|
## Retrieves the int value of a `JInt JsonNode`.
|
||||||
##
|
##
|
||||||
## Returns ``default`` if ``n`` is not a ``JInt``.
|
## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
|
||||||
if n.kind != JInt: return default
|
if n.isNil or n.kind != JInt: return default
|
||||||
else: return n.num
|
else: return n.num
|
||||||
|
|
||||||
proc getFNum*(n: JsonNode, default: float = 0.0): float =
|
proc getFNum*(n: JsonNode, default: float = 0.0): float =
|
||||||
## Retrieves the float value of a `JFloat JsonNode`.
|
## Retrieves the float value of a `JFloat JsonNode`.
|
||||||
##
|
##
|
||||||
## Returns ``default`` if ``n`` is not a ``JFloat``.
|
## Returns ``default`` if ``n`` is not a ``JFloat``, or if ``n`` is nil.
|
||||||
if n.kind != JFloat: return default
|
if n.isNil or n.kind != JFloat: return default
|
||||||
else: return n.fnum
|
else: return n.fnum
|
||||||
|
|
||||||
proc getBVal*(n: JsonNode, default: bool = false): bool =
|
proc getBVal*(n: JsonNode, default: bool = false): bool =
|
||||||
## Retrieves the bool value of a `JBool JsonNode`.
|
## Retrieves the bool value of a `JBool JsonNode`.
|
||||||
##
|
##
|
||||||
## Returns ``default`` if ``n`` is not a ``JBool``.
|
## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil.
|
||||||
if n.kind != JBool: return default
|
if n.isNil or n.kind != JBool: return default
|
||||||
else: return n.bval
|
else: return n.bval
|
||||||
|
|
||||||
proc getFields*(n: JsonNode,
|
proc getFields*(n: JsonNode,
|
||||||
|
|
@ -638,15 +638,15 @@ proc getFields*(n: JsonNode,
|
||||||
seq[tuple[key: string, val: JsonNode]] =
|
seq[tuple[key: string, val: JsonNode]] =
|
||||||
## Retrieves the key, value pairs of a `JObject JsonNode`.
|
## Retrieves the key, value pairs of a `JObject JsonNode`.
|
||||||
##
|
##
|
||||||
## Returns ``default`` if ``n`` is not a ``JObject``.
|
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
|
||||||
if n.kind != JObject: return default
|
if n.isNil or n.kind != JObject: return default
|
||||||
else: return n.fields
|
else: return n.fields
|
||||||
|
|
||||||
proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
|
proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
|
||||||
## Retrieves the int value of a `JArray JsonNode`.
|
## Retrieves the int value of a `JArray JsonNode`.
|
||||||
##
|
##
|
||||||
## Returns ``default`` if ``n`` is not a ``JArray``.
|
## Returns ``default`` if ``n`` is not a ``JArray``, or if ``n`` is nil.
|
||||||
if n.kind != JArray: return default
|
if n.isNil or n.kind != JArray: return default
|
||||||
else: return n.elems
|
else: return n.elems
|
||||||
|
|
||||||
proc `%`*(s: string): JsonNode =
|
proc `%`*(s: string): JsonNode =
|
||||||
|
|
|
||||||
|
|
@ -1052,6 +1052,117 @@ proc parse*(value, layout: string): TimeInfo =
|
||||||
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
|
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
# Leap year calculations are adapted from:
|
||||||
|
# from http://www.codeproject.com/Articles/7358/Ultra-fast-Algorithms-for-Working-with-Leap-Years
|
||||||
|
# The dayOfTheWeek procs are adapated from:
|
||||||
|
# from http://stason.org/TULARC/society/calendars/2-5-What-day-of-the-week-was-2-August-1953.html
|
||||||
|
|
||||||
|
# Note: for leap years, start date is assumed to be 1 AD.
|
||||||
|
# counts the number of leap years up to January 1st of a given year.
|
||||||
|
# Keep in mind that if specified year is a leap year, the leap day
|
||||||
|
# has not happened before January 1st of that year.
|
||||||
|
proc countLeapYears(yearSpan: int): int =
|
||||||
|
(((yearSpan - 1) / 4) - ((yearSpan - 1) / 100) + ((yearSpan - 1)/400)).int
|
||||||
|
|
||||||
|
proc countDays(yearSpan: int): int =
|
||||||
|
(yearSpan - 1) * 365 + countLeapYears(yearSpan)
|
||||||
|
|
||||||
|
proc countYears(daySpan: int): int =
|
||||||
|
# counts the number of years spanned by a given number of days.
|
||||||
|
((daySpan - countLeapYears(daySpan div 365)) div 365)
|
||||||
|
|
||||||
|
proc countYearsAndDays(daySpan: int): tuple[years: int, days: int] =
|
||||||
|
# counts the number of years spanned by a given number of days and the remainder as days.
|
||||||
|
let days = daySpan - countLeapYears(daySpan div 365)
|
||||||
|
result.years = days div 365
|
||||||
|
result.days = days mod 365
|
||||||
|
|
||||||
|
const
|
||||||
|
secondsInMin = 60
|
||||||
|
secondsInHour = 60*60
|
||||||
|
secondsInDay = 60*60*24
|
||||||
|
epochStartYear = 1970
|
||||||
|
|
||||||
|
proc getDayOfWeek*(day, month, year: int): WeekDay =
|
||||||
|
## Returns the day of the week enum from day, month and year.
|
||||||
|
# Day & month start from one.
|
||||||
|
let
|
||||||
|
a = (14 - month) div 12
|
||||||
|
y = year - a
|
||||||
|
m = month + (12*a) - 2
|
||||||
|
d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7
|
||||||
|
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct
|
||||||
|
# for the WeekDay type.
|
||||||
|
if d == 0: return dSun
|
||||||
|
result = (d-1).WeekDay
|
||||||
|
|
||||||
|
proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
|
||||||
|
## Returns the day of the week enum from day, month and year, according to the Julian calender.
|
||||||
|
# Day & month start from one.
|
||||||
|
let
|
||||||
|
a = (14 - month) div 12
|
||||||
|
y = year - a
|
||||||
|
m = month + (12*a) - 2
|
||||||
|
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
|
||||||
|
result = d.WeekDay
|
||||||
|
|
||||||
|
proc timeToTimeInfo*(t: Time): TimeInfo =
|
||||||
|
## Converts a Time to TimeInfo.
|
||||||
|
let
|
||||||
|
daysSinceEpoch = t.int div secondsInDay
|
||||||
|
(yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
|
||||||
|
daySeconds = t.int mod secondsInDay
|
||||||
|
|
||||||
|
y = yearsSinceEpoch + epochStartYear
|
||||||
|
|
||||||
|
var
|
||||||
|
mon = mJan
|
||||||
|
days = daysRemaining
|
||||||
|
daysInMonth = getDaysInMonth(mon, y)
|
||||||
|
|
||||||
|
# calculate month and day remainder
|
||||||
|
while days > daysInMonth and mon <= mDec:
|
||||||
|
days -= daysInMonth
|
||||||
|
mon.inc
|
||||||
|
daysInMonth = getDaysInMonth(mon, y)
|
||||||
|
|
||||||
|
let
|
||||||
|
yd = daysRemaining
|
||||||
|
m = mon # month is zero indexed enum
|
||||||
|
md = days
|
||||||
|
# NB: month is zero indexed but dayOfWeek expects 1 indexed.
|
||||||
|
wd = getDayOfWeek(days, mon.int + 1, y).Weekday
|
||||||
|
h = daySeconds div secondsInHour + 1
|
||||||
|
mi = (daySeconds mod secondsInHour) div secondsInMin
|
||||||
|
s = daySeconds mod secondsInMin
|
||||||
|
result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s)
|
||||||
|
|
||||||
|
proc timetoTimeInterval*(t: Time): TimeInterval =
|
||||||
|
## Converts a Time to a TimeInterval.
|
||||||
|
var
|
||||||
|
daysSinceEpoch = t.int div secondsInDay
|
||||||
|
(yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
|
||||||
|
daySeconds = t.int mod secondsInDay
|
||||||
|
|
||||||
|
result.years = yearsSinceEpoch + epochStartYear
|
||||||
|
|
||||||
|
var
|
||||||
|
mon = mJan
|
||||||
|
days = daysRemaining
|
||||||
|
daysInMonth = getDaysInMonth(mon, result.years)
|
||||||
|
|
||||||
|
# calculate month and day remainder
|
||||||
|
while days > daysInMonth and mon <= mDec:
|
||||||
|
days -= daysInMonth
|
||||||
|
mon.inc
|
||||||
|
daysInMonth = getDaysInMonth(mon, result.years)
|
||||||
|
|
||||||
|
result.months = mon.int + 1 # month is 1 indexed int
|
||||||
|
result.days = days
|
||||||
|
result.hours = daySeconds div secondsInHour + 1
|
||||||
|
result.minutes = (daySeconds mod secondsInHour) div secondsInMin
|
||||||
|
result.seconds = daySeconds mod secondsInMin
|
||||||
|
# Milliseconds not available from Time
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
# $ date --date='@2147483647'
|
# $ date --date='@2147483647'
|
||||||
|
|
@ -1137,3 +1248,18 @@ when isMainModule:
|
||||||
assert "15:04:00" in $s.parse(f)
|
assert "15:04:00" in $s.parse(f)
|
||||||
when not defined(testing):
|
when not defined(testing):
|
||||||
echo "Kitchen: " & $s.parse(f)
|
echo "Kitchen: " & $s.parse(f)
|
||||||
|
var ti = timeToTimeInfo(getTime())
|
||||||
|
echo "Todays date after decoding: ", ti
|
||||||
|
var tint = timeToTimeInterval(getTime())
|
||||||
|
echo "Todays date after decoding to interval: ", tint
|
||||||
|
# checking dayOfWeek matches known days
|
||||||
|
assert getDayOfWeek(21, 9, 1900) == dFri
|
||||||
|
assert getDayOfWeek(1, 1, 1970) == dThu
|
||||||
|
assert getDayOfWeek(21, 9, 1970) == dMon
|
||||||
|
assert getDayOfWeek(1, 1, 2000) == dSat
|
||||||
|
assert getDayOfWeek(1, 1, 2021) == dFri
|
||||||
|
# Julian tests
|
||||||
|
assert getDayOfWeekJulian(21, 9, 1900) == dFri
|
||||||
|
assert getDayOfWeekJulian(21, 9, 1970) == dMon
|
||||||
|
assert getDayOfWeekJulian(1, 1, 2000) == dSat
|
||||||
|
assert getDayOfWeekJulian(1, 1, 2021) == dFri
|
||||||
|
|
|
||||||
|
|
@ -285,7 +285,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
|
||||||
|
|
||||||
result = getAst(rewrite(checked, checked.lineinfo, checked.toStrLit))
|
result = getAst(rewrite(checked, checked.lineinfo, checked.toStrLit))
|
||||||
|
|
||||||
template require*(conditions: stmt): stmt {.immediate, dirty.} =
|
template require*(conditions: stmt): stmt {.immediate.} =
|
||||||
## Same as `check` except any failed test causes the program to quit
|
## Same as `check` except any failed test causes the program to quit
|
||||||
## immediately. Any teardown statements are not executed and the failed
|
## immediately. Any teardown statements are not executed and the failed
|
||||||
## test output is not generated.
|
## test output is not generated.
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ proc new*(T: typedesc): auto =
|
||||||
## reference to it as result value.
|
## reference to it as result value.
|
||||||
##
|
##
|
||||||
## When ``T`` is a ref type then the resulting type will be ``T``,
|
## When ``T`` is a ref type then the resulting type will be ``T``,
|
||||||
## otherwise it will be ``ref T``.
|
## otherwise it will be ``ref T``.
|
||||||
when (T is ref):
|
when (T is ref):
|
||||||
var r: T
|
var r: T
|
||||||
else:
|
else:
|
||||||
|
|
@ -577,6 +577,9 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
|
||||||
## that one never needs to know ``x``'s size. As a special semantic rule,
|
## that one never needs to know ``x``'s size. As a special semantic rule,
|
||||||
## ``x`` may also be a type identifier (``sizeof(int)`` is valid).
|
## ``x`` may also be a type identifier (``sizeof(int)`` is valid).
|
||||||
|
|
||||||
|
when defined(nimtypedescfixed):
|
||||||
|
proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.}
|
||||||
|
|
||||||
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
||||||
## unary ``<`` that can be used for nice looking excluding ranges:
|
## unary ``<`` that can be used for nice looking excluding ranges:
|
||||||
##
|
##
|
||||||
|
|
@ -1500,7 +1503,7 @@ when not defined(nimrodVM):
|
||||||
## containing zero, so it is somewhat safer than ``createU``.
|
## containing zero, so it is somewhat safer than ``createU``.
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `createShared` to allocate from a shared heap.
|
## Use `createShared` to allocate from a shared heap.
|
||||||
cast[ptr T](alloc0(T.sizeof * size))
|
cast[ptr T](alloc0(sizeof(T) * size))
|
||||||
proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
|
proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
|
||||||
benign.}
|
benign.}
|
||||||
## grows or shrinks a given memory block. If p is **nil** then a new
|
## grows or shrinks a given memory block. If p is **nil** then a new
|
||||||
|
|
|
||||||
47
tests/destructor/tdestructor3.nim
Normal file
47
tests/destructor/tdestructor3.nim
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
discard """
|
||||||
|
output: '''assign
|
||||||
|
destroy
|
||||||
|
destroy
|
||||||
|
destroy Foo: 5
|
||||||
|
5
|
||||||
|
destroy Foo: 123
|
||||||
|
123'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #2821
|
||||||
|
{.experimental.}
|
||||||
|
|
||||||
|
type T = object
|
||||||
|
|
||||||
|
proc `=`(lhs: var T, rhs: T) =
|
||||||
|
echo "assign"
|
||||||
|
|
||||||
|
proc `=destroy`(v: var T) =
|
||||||
|
echo "destroy"
|
||||||
|
|
||||||
|
block:
|
||||||
|
var v1 : T
|
||||||
|
var v2 : T = v1
|
||||||
|
|
||||||
|
|
||||||
|
# bug #1632
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo = object of RootObj
|
||||||
|
x: int
|
||||||
|
|
||||||
|
proc `=destroy`(a: var Foo) =
|
||||||
|
echo "destroy Foo: " & $a.x
|
||||||
|
|
||||||
|
template toFooPtr(a: int{lit}): ptr Foo =
|
||||||
|
var temp = Foo(x:a)
|
||||||
|
temp.addr
|
||||||
|
|
||||||
|
proc test(a: ptr Foo) =
|
||||||
|
echo a[].x
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
test(toFooPtr(5))
|
||||||
|
test(toFooPtr(123))
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''hi
|
output: '''hi
|
||||||
hi'''
|
hi
|
||||||
|
1
|
||||||
|
hi
|
||||||
|
2
|
||||||
|
B
|
||||||
|
A'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #1742
|
# bug #1742
|
||||||
|
|
@ -16,3 +21,23 @@ import strutils
|
||||||
let x = try: parseInt("133a")
|
let x = try: parseInt("133a")
|
||||||
except: -1
|
except: -1
|
||||||
finally: echo "hi"
|
finally: echo "hi"
|
||||||
|
|
||||||
|
|
||||||
|
template atFuncEnd =
|
||||||
|
defer:
|
||||||
|
echo "A"
|
||||||
|
defer:
|
||||||
|
echo "B"
|
||||||
|
|
||||||
|
template testB(): expr =
|
||||||
|
let a = 0
|
||||||
|
defer: echo "hi" # Delete this line to make it work
|
||||||
|
a
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
atFuncEnd()
|
||||||
|
echo 1
|
||||||
|
let i = testB()
|
||||||
|
echo 2
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
|
||||||
10
tests/generics/mclosed_sym.nim
Normal file
10
tests/generics/mclosed_sym.nim
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
type R* = object
|
||||||
|
|
||||||
|
type Data*[T] = object
|
||||||
|
d*: T
|
||||||
|
|
||||||
|
proc same(r:R, d:int) = echo "TEST2"
|
||||||
|
|
||||||
|
proc doIt*(d:Data, r:R) =
|
||||||
|
r.same(1) # Expecting this to invoke the local `same()` method
|
||||||
11
tests/generics/tclosed_sym.nim
Normal file
11
tests/generics/tclosed_sym.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
discard """
|
||||||
|
output: "TEST2"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #2664
|
||||||
|
|
||||||
|
import mclosed_sym
|
||||||
|
|
||||||
|
proc same(r:R, d:int) = echo "TEST1"
|
||||||
|
|
||||||
|
doIt(Data[int](d:123), R())
|
||||||
|
|
@ -21,6 +21,11 @@ test "unittest typedescs":
|
||||||
check(none(int) != some(1))
|
check(none(int) != some(1))
|
||||||
|
|
||||||
|
|
||||||
|
test "unittest multiple requires":
|
||||||
|
require(true)
|
||||||
|
require(true)
|
||||||
|
|
||||||
|
|
||||||
import math
|
import math
|
||||||
from strutils import parseInt
|
from strutils import parseInt
|
||||||
proc defectiveRobot() =
|
proc defectiveRobot() =
|
||||||
|
|
|
||||||
13
tests/template/twhen_gensym.nim
Normal file
13
tests/template/twhen_gensym.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
output: "hi"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #2670
|
||||||
|
template testTemplate(b: bool): stmt =
|
||||||
|
when b:
|
||||||
|
var a = "hi"
|
||||||
|
else:
|
||||||
|
var a = 5
|
||||||
|
echo a
|
||||||
|
|
||||||
|
testTemplate(true)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue