Merge ../Nim into devel

This commit is contained in:
Charles Blake 2015-08-09 06:58:36 -04:00
commit 9c3c48a6d0
22 changed files with 455 additions and 102 deletions

View file

@ -90,3 +90,4 @@ proc initDefines*() =
defineSymbol("nimnode") defineSymbol("nimnode")
defineSymbol("nimnomagic64") defineSymbol("nimnomagic64")
defineSymbol("nimvarargstyped") defineSymbol("nimvarargstyped")
defineSymbol("nimtypedescfixed")

View file

@ -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

View file

@ -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.

View file

@ -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}))

View file

@ -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 =

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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)

View file

@ -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 =

View file

@ -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

View file

@ -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.

View file

@ -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

View 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()

View file

@ -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()

View 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

View 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())

View file

@ -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() =

View 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)