mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-03 19:52:36 +00:00
Merge ../Nim into devel
This commit is contained in:
@@ -90,3 +90,4 @@ proc initDefines*() =
|
||||
defineSymbol("nimnode")
|
||||
defineSymbol("nimnomagic64")
|
||||
defineSymbol("nimvarargstyped")
|
||||
defineSymbol("nimtypedescfixed")
|
||||
|
||||
@@ -184,7 +184,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
|
||||
var params = routine.ast.sons[paramsPos]
|
||||
# -1 is correct here as param.position is 0 based but we have at position 0
|
||||
# some nkEffect node:
|
||||
param.position = params.len-1
|
||||
param.position = routine.typ.n.len-1
|
||||
addSon(params, newSymNode(param))
|
||||
incl(routine.typ.flags, tfCapturesEnv)
|
||||
assert sfFromGeneric in param.flags
|
||||
|
||||
@@ -177,6 +177,15 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||
else:
|
||||
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,
|
||||
varSection: PNode): tuple[outer, inner: PNode] =
|
||||
# Accepts a var or let section.
|
||||
|
||||
@@ -2259,7 +2259,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkStaticStmt:
|
||||
result = semStaticStmt(c, n)
|
||||
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:
|
||||
localError(n.info, errInvalidExpressionX,
|
||||
renderTree(n, {renderNoComments}))
|
||||
|
||||
@@ -39,9 +39,9 @@ type
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags, ctx: var GenericCtx): PNode
|
||||
|
||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags,
|
||||
ctx: var GenericCtx): PNode =
|
||||
ctx: var GenericCtx): PNode =
|
||||
openScope(c)
|
||||
result = semGenericStmt(c, n, flags, ctx)
|
||||
closeScope(c)
|
||||
@@ -73,7 +73,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skGenericParam:
|
||||
of skGenericParam:
|
||||
if s.typ != nil and s.typ.kind == tyStatic:
|
||||
if s.typ.n != nil:
|
||||
result = s.typ.n
|
||||
@@ -85,18 +85,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
of skParam:
|
||||
result = n
|
||||
styleCheckUse(n.info, s)
|
||||
of skType:
|
||||
of skType:
|
||||
if (s.typ != nil) and
|
||||
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
else:
|
||||
else:
|
||||
result = n
|
||||
styleCheckUse(n.info, s)
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var GenericCtx): PNode =
|
||||
result = n
|
||||
let ident = considerQuotedIdent(n)
|
||||
@@ -118,13 +118,13 @@ proc newDot(n, b: PNode): PNode =
|
||||
result.add(n.sons[0])
|
||||
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 =
|
||||
assert n.kind == nkDotExpr
|
||||
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
||||
|
||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||
|
||||
|
||||
var s = qualifiedLookUp(c, n, luf)
|
||||
if s != nil:
|
||||
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:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
else:
|
||||
let sym = semGenericStmtSymbol(c, n, s, ctx)
|
||||
if sym.kind == nkSym:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
let syms = semGenericStmtSymbol(c, n, s, ctx)
|
||||
if syms.kind == nkSym:
|
||||
let choice = symChoice(c, n, s, scForceOpen)
|
||||
choice.kind = nkClosedSymChoice
|
||||
result = newDot(result, choice)
|
||||
else:
|
||||
result = newDot(result, sym)
|
||||
result = newDot(result, syms)
|
||||
|
||||
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||
let s = newSymS(skUnknown, getIdentNode(n), c)
|
||||
addPrelimDecl(c, s)
|
||||
styleCheckDef(n.info, s, kind)
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
|
||||
result = 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)
|
||||
of nkMixinStmt:
|
||||
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:
|
||||
checkMinSonsLen(n, 1)
|
||||
let fn = n.sons[0]
|
||||
var s = qualifiedLookUp(c, fn, {})
|
||||
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:
|
||||
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
||||
|
||||
|
||||
var first = 0
|
||||
var mixinContext = false
|
||||
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
|
||||
# the famous "undeclared identifier: it" bug:
|
||||
mixinContext = true
|
||||
of skUnknown, skParam:
|
||||
of skUnknown, skParam:
|
||||
# Leave it as an identifier.
|
||||
discard
|
||||
of skProc, skMethod, skIterators, skConverter:
|
||||
@@ -230,9 +232,9 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
first = 1
|
||||
of skType:
|
||||
of skType:
|
||||
# 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)
|
||||
styleCheckUse(fn.info, s)
|
||||
first = 1
|
||||
@@ -244,34 +246,34 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||
first = 1
|
||||
# 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.
|
||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||
for i in countup(first, sonsLen(result) - 1):
|
||||
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
||||
of nkIfStmt:
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
of nkIfStmt:
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
|
||||
of nkWhenStmt:
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx)
|
||||
of nkWhileStmt:
|
||||
of nkWhileStmt:
|
||||
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)
|
||||
closeScope(c)
|
||||
of nkCaseStmt:
|
||||
of nkCaseStmt:
|
||||
openScope(c)
|
||||
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]
|
||||
checkMinSonsLen(a, 1)
|
||||
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[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkForStmt, nkParForStmt:
|
||||
of nkForStmt, nkParForStmt:
|
||||
var L = sonsLen(n)
|
||||
openScope(c)
|
||||
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)
|
||||
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
addTempDecl(c, n.sons[0], skLabel)
|
||||
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkTryStmt:
|
||||
of nkTryStmt:
|
||||
checkMinSonsLen(n, 2)
|
||||
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]
|
||||
checkMinSonsLen(a, 1)
|
||||
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[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||
of nkVarSection, nkLetSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkVarSection, nkLetSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
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)
|
||||
checkMinSonsLen(a, 3)
|
||||
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)
|
||||
for j in countup(0, L-3):
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
|
||||
of nkGenericParams:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkGenericParams:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in countup(0, L-3):
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in countup(0, L-3):
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skType)
|
||||
of nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkConstDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
|
||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
||||
of nkTypeSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
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]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
if a.sons[1].kind != nkEmpty:
|
||||
if a.sons[1].kind != nkEmpty:
|
||||
openScope(c)
|
||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
||||
closeScope(c)
|
||||
else:
|
||||
else:
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
||||
of nkEnumTy:
|
||||
of nkEnumTy:
|
||||
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)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a: PNode
|
||||
case n.sons[i].kind
|
||||
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
||||
@@ -360,26 +362,26 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
discard
|
||||
of nkFormalParams:
|
||||
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)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
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)
|
||||
for j in countup(0, L-3):
|
||||
for j in countup(0, L-3):
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef, nkLambdaKinds:
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef, nkLambdaKinds:
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
if n.sons[namePos].kind != nkEmpty:
|
||||
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
|
||||
openScope(c)
|
||||
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
||||
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
||||
flags, ctx)
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
||||
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
|
||||
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
||||
@@ -394,7 +396,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
checkMinSonsLen(n, 2)
|
||||
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
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)
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode): PNode =
|
||||
|
||||
@@ -369,6 +369,15 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
|
||||
else:
|
||||
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 =
|
||||
if v.name.s == "_":
|
||||
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]
|
||||
v.typ = tup.sons[j]
|
||||
b.sons[j] = newSymNode(v)
|
||||
addDefer(c, result, v)
|
||||
checkNilable(v)
|
||||
if sfCompileTime in v.flags: hasCompileTime = true
|
||||
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):
|
||||
let k = n.sons[i].kind
|
||||
case k
|
||||
of nkFinally, nkExceptBranch, nkDefer:
|
||||
of nkFinally, nkExceptBranch:
|
||||
# stand-alone finally and except blocks are
|
||||
# transformed into regular try blocks:
|
||||
#
|
||||
@@ -1424,21 +1434,13 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
n.typ = n.sons[i].typ
|
||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||
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:
|
||||
for j in countup(i + 1, length - 1):
|
||||
case n.sons[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||
else: discard
|
||||
if result.len == 1:
|
||||
if result.len == 1 and result.sons[0].kind != nkDefer:
|
||||
result = result.sons[0]
|
||||
when defined(nimfix):
|
||||
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:
|
||||
let ident = getIdentNode(c, n)
|
||||
if not isTemplParam(c, ident):
|
||||
let local = newGenSym(k, ident, c)
|
||||
addPrelimDecl(c.c, local)
|
||||
styleCheckDef(n.info, local)
|
||||
replaceIdentBySym(n, newSymNode(local, n.info))
|
||||
# fix #2670, consider:
|
||||
#
|
||||
# when b:
|
||||
# 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:
|
||||
replaceIdentBySym(n, ident)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# * converts "continue" to "break"; disambiguates "break"
|
||||
# * introduces method dispatchers
|
||||
# * performs lambda lifting for closure support
|
||||
# * transforms 'defer' into a 'try finally' statement
|
||||
|
||||
import
|
||||
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)
|
||||
nestedProcs: int # > 0 if we are in a nested proc
|
||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
deferDetected: bool
|
||||
PTransf = ref TTransfContext
|
||||
|
||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||
@@ -680,6 +682,14 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||
result = n
|
||||
|
||||
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
|
||||
of nkSym:
|
||||
result = transformSym(c, n)
|
||||
@@ -712,13 +722,36 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
result = transformFor(c, n)
|
||||
of nkParForStmt:
|
||||
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:
|
||||
result = PTransNode(newNodeI(nkBreakStmt, n.info))
|
||||
var labl = c.contSyms[c.contSyms.high]
|
||||
add(result, PTransNode(newSymNode(labl)))
|
||||
of nkBreakStmt: result = transformBreak(c, n)
|
||||
of nkWhileStmt: result = transformWhile(c, n)
|
||||
of nkCallKinds:
|
||||
result = transformCall(c, n)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
@@ -754,8 +787,6 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
result = transformYield(c, n)
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of nkBlockStmt, nkBlockExpr:
|
||||
result = transformBlock(c, n)
|
||||
of nkIdentDefs, nkConstDef:
|
||||
result = transformSons(c, n)
|
||||
# XXX comment handling really sucks:
|
||||
@@ -764,6 +795,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
of nkClosure: return PTransNode(n)
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
when false:
|
||||
if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
|
||||
var cnst = getConstExpr(c.module, PNode(result))
|
||||
# we inline constants if they are not complex constants:
|
||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
@@ -785,12 +818,52 @@ proc openTransf(module: PSym, filename: string): PTransf =
|
||||
result.breakSyms = @[]
|
||||
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 =
|
||||
if nfTransf in n.flags or prc.kind in {skTemplate}:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
result = processTransf(c, n, prc)
|
||||
liftDefer(c, result)
|
||||
result = liftLambdas(prc, result)
|
||||
#if prc.kind == skClosureIterator:
|
||||
# result = lambdalifting.liftIterator(prc, result)
|
||||
@@ -805,6 +878,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
result = liftLambdasForTopLevel(module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
when useEffectSystem: trackTopLevelStmt(module, result)
|
||||
@@ -815,4 +889,5 @@ proc transformExpr*(module: PSym, n: PNode): PNode =
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
@@ -432,7 +432,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
assert regs[rb].kind == rkNode
|
||||
let nb = regs[rb].node
|
||||
case nb.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
ensureKind(rkInt)
|
||||
regs[ra].intVal = nb.intVal
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
|
||||
@@ -66,12 +66,14 @@ Running tests
|
||||
You can run the tests with
|
||||
|
||||
::
|
||||
|
||||
./koch tests
|
||||
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
./koch tests --failing all
|
||||
|
||||
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.
|
||||
|
||||
::
|
||||
|
||||
./koch tests c lib
|
||||
|
||||
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.
|
||||
|
||||
::
|
||||
|
||||
git checkout devel
|
||||
DEVEL_COMMIT=$(git rev-parse HEAD)
|
||||
./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.
|
||||
|
||||
::
|
||||
|
||||
git checkout your-changes
|
||||
./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.
|
||||
|
||||
::
|
||||
|
||||
./koch --print html $DEVEL_COMMIT
|
||||
|
||||
|
||||
|
||||
@@ -226,6 +226,10 @@ proc `$`*[A, B](t: Table[A, B]): string =
|
||||
## The `$` operator for hash tables.
|
||||
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() =
|
||||
if s.counter == t.counter:
|
||||
# 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`.
|
||||
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 =
|
||||
## alias of `hasKey` for use with the `in` operator.
|
||||
return hasKey[A, B](t, key)
|
||||
|
||||
@@ -608,29 +608,29 @@ proc newJArray*(): JsonNode =
|
||||
proc getStr*(n: JsonNode, default: string = ""): string =
|
||||
## Retrieves the string value of a `JString JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JString``.
|
||||
if n.kind != JString: return default
|
||||
## Returns ``default`` if ``n`` is not a ``JString``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JString: return default
|
||||
else: return n.str
|
||||
|
||||
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
|
||||
## Retrieves the int value of a `JInt JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JInt``.
|
||||
if n.kind != JInt: return default
|
||||
## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JInt: return default
|
||||
else: return n.num
|
||||
|
||||
proc getFNum*(n: JsonNode, default: float = 0.0): float =
|
||||
## Retrieves the float value of a `JFloat JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JFloat``.
|
||||
if n.kind != JFloat: return default
|
||||
## Returns ``default`` if ``n`` is not a ``JFloat``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JFloat: return default
|
||||
else: return n.fnum
|
||||
|
||||
proc getBVal*(n: JsonNode, default: bool = false): bool =
|
||||
## Retrieves the bool value of a `JBool JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JBool``.
|
||||
if n.kind != JBool: return default
|
||||
## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JBool: return default
|
||||
else: return n.bval
|
||||
|
||||
proc getFields*(n: JsonNode,
|
||||
@@ -638,15 +638,15 @@ proc getFields*(n: JsonNode,
|
||||
seq[tuple[key: string, val: JsonNode]] =
|
||||
## Retrieves the key, value pairs of a `JObject JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JObject``.
|
||||
if n.kind != JObject: return default
|
||||
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JObject: return default
|
||||
else: return n.fields
|
||||
|
||||
proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
|
||||
## Retrieves the int value of a `JArray JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JArray``.
|
||||
if n.kind != JArray: return default
|
||||
## Returns ``default`` if ``n`` is not a ``JArray``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JArray: return default
|
||||
else: return n.elems
|
||||
|
||||
proc `%`*(s: string): JsonNode =
|
||||
|
||||
@@ -1052,6 +1052,117 @@ proc parse*(value, layout: string): TimeInfo =
|
||||
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
|
||||
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:
|
||||
# $ date --date='@2147483647'
|
||||
@@ -1137,3 +1248,18 @@ when isMainModule:
|
||||
assert "15:04:00" in $s.parse(f)
|
||||
when not defined(testing):
|
||||
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))
|
||||
|
||||
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
|
||||
## immediately. Any teardown statements are not executed and the failed
|
||||
## test output is not generated.
|
||||
|
||||
@@ -188,7 +188,7 @@ proc new*(T: typedesc): auto =
|
||||
## reference to it as result value.
|
||||
##
|
||||
## 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):
|
||||
var r: T
|
||||
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,
|
||||
## ``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.}
|
||||
## 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``.
|
||||
## The allocated memory belongs to its allocating thread!
|
||||
## 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: [],
|
||||
benign.}
|
||||
## 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 """
|
||||
output: '''hi
|
||||
hi'''
|
||||
hi
|
||||
1
|
||||
hi
|
||||
2
|
||||
B
|
||||
A'''
|
||||
"""
|
||||
|
||||
# bug #1742
|
||||
@@ -16,3 +21,23 @@ import strutils
|
||||
let x = try: parseInt("133a")
|
||||
except: -1
|
||||
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))
|
||||
|
||||
|
||||
test "unittest multiple requires":
|
||||
require(true)
|
||||
require(true)
|
||||
|
||||
|
||||
import math
|
||||
from strutils import parseInt
|
||||
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)
|
||||
Reference in New Issue
Block a user