fixex merge conflicts

This commit is contained in:
Araq
2018-06-08 19:50:36 +02:00
53 changed files with 2648 additions and 355 deletions

View File

@@ -65,6 +65,7 @@
- Added cotangent, secant and cosecant procs ``math.cot``, ``math.sec`` and ``math.csc``; and their hyperbolic, inverse and inverse hyperbolic functions, ``math.coth``, ``math.sech``, ``math.csch``, ``math.arccot``, ``math.arcsec``, ``math.arccsc``, ``math.arccoth``, ``math.arcsech`` and ``math.arccsch`` procs.
- Added the procs ``math.floorMod`` and ``math.floorDiv`` for floor based integer division.
- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals.
- Added the proc ``math.prod`` for product of elements in openArray.
### Library changes
@@ -90,6 +91,7 @@
API". Using the Nim compiler and its VM as a scripting engine has never been
easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to
use the Nim VM in a native Nim application.
- The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated.
### Language additions

View File

@@ -83,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
result = isInCurrentFrame(p, n.sons[0])
else: discard
proc genIndexCheck(p: BProc; arr, idx: TLoc)
proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
proc openArrayLoc(p: BProc, n: PNode): Rope =
var a: TLoc
@@ -97,8 +97,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
initLocExpr(p, q[3], c)
# but first produce the required index checks:
if optBoundsCheck in p.options:
genIndexCheck(p, a, b)
genIndexCheck(p, a, c)
genBoundsCheck(p, a, b, c)
let ty = skipTypes(a.t, abstractVar+{tyPtr})
case ty.kind
of tyArray:

View File

@@ -351,7 +351,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else:
useStringh(p.module)
linefmt(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n",
# bug #4799, keep the memcpy for a while
#"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n",
"$1 = $2;$n",
rdLoc(dest), rdLoc(src))
of tySet:
if mapType(p.config, ty) == ctArray:
@@ -873,21 +875,26 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
putIntoDest(p, d, n,
ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
proc genIndexCheck(p: BProc; arr, idx: TLoc) =
proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
let ty = skipTypes(arr.t, abstractVarRange)
case ty.kind
of tyOpenArray, tyVarargs:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n",
rdLoc(idx), rdLoc(arr))
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n",
rdLoc(a), rdLoc(b), rdLoc(arr))
of tyArray:
let first = intLiteral(firstOrd(p.config, ty))
if tfUncheckedArray notin ty.flags:
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
rdCharLoc(idx), first, intLiteral(lastOrd(p.config, ty)))
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
of tySequence, tyString:
linefmt(p, cpsStmts,
"if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
rdLoc(idx), rdLoc(arr), lenField(p))
"if ($2-$1 != -1 && " &
"(!$3 || (NU)($1) >= (NU)($3->$4) || (NU)($2) >= (NU)($3->$4))) #raiseIndexError();$n",
rdLoc(a), rdLoc(b), rdLoc(arr), lenField(p))
else: discard
proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
@@ -2326,7 +2333,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkParForStmt: genParForStmt(p, n)
of nkState: genState(p, n)
of nkGotoState: genGotoState(p, n)
of nkBreakState: genBreakState(p, n)
of nkBreakState: genBreakState(p, n, d)
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode): Rope =

View File

@@ -157,6 +157,39 @@ proc genState(p: BProc, n: PNode) =
elif n0.kind == nkStrLit:
linefmt(p, cpsStmts, "$1: ;$n", n0.strVal.rope)
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts,
var stack = newSeq[tuple[n: PNode, inExcept: bool]](0)
for i in countup(1, howManyTrys):
let tryStmt = p.nestedTryStmts.pop
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
# Pop safe points generated by try
if not tryStmt.inExcept:
linefmt(p, cpsStmts, "#popSafePoint();$n")
# Pop this try-stmt of the list of nested trys
# so we don't infinite recurse on it in the next step.
stack.add(tryStmt)
# Find finally-stmt for this try-stmt
# and generate a copy of its sons
var finallyStmt = lastSon(tryStmt.n)
if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0])
# push old elements again:
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
# Pop exceptions that was handled by the
# except-blocks we are in
for i in countdown(howManyExcepts-1, 0):
linefmt(p, cpsStmts, "#popCurrentException();$n")
proc genGotoState(p: BProc, n: PNode) =
# we resist the temptation to translate it into duff's device as it later
# will be translated into computed gotos anyway for GCC at least:
@@ -167,7 +200,11 @@ proc genGotoState(p: BProc, n: PNode) =
initLocExpr(p, n.sons[0], a)
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.beforeRetNeeded = true
lineF(p, cpsStmts, "case -1: goto BeforeRet_;$n", [])
lineF(p, cpsStmts, "case -1:$n", [])
blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen)
lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
var statesCounter = lastOrd(p.config, n.sons[0].typ)
if n.len >= 2 and n[1].kind == nkIntLit:
statesCounter = n[1].intVal
@@ -177,17 +214,17 @@ proc genGotoState(p: BProc, n: PNode) =
lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
lineF(p, cpsStmts, "}$n", [])
proc genBreakState(p: BProc, n: PNode) =
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLoc(d, locExpr, n, OnUnknown)
if n.sons[0].kind == nkClosure:
# XXX this produces quite inefficient code!
initLocExpr(p, n.sons[0].sons[1], a)
lineF(p, cpsStmts, "if (((NI*) $1)[1] < 0) break;$n", [rdLoc(a)])
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
else:
initLocExpr(p, n.sons[0], a)
# the environment is guaranteed to contain the 'state' field at offset 1:
lineF(p, cpsStmts, "if ((((NI*) $1.ClE_0)[1]) < 0) break;$n", [rdLoc(a)])
# lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
proc genGotoVar(p: BProc; value: PNode) =
if value.kind notin {nkCharLit..nkUInt64Lit}:
@@ -328,40 +365,6 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
else: internalError(p.config, n.info, "genIf()")
if sonsLen(n) > 1: fixLabel(p, lend)
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts,
var stack = newSeq[tuple[n: PNode, inExcept: bool]](0)
for i in countup(1, howManyTrys):
let tryStmt = p.nestedTryStmts.pop
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
# Pop safe points generated by try
if not tryStmt.inExcept:
linefmt(p, cpsStmts, "#popSafePoint();$n")
# Pop this try-stmt of the list of nested trys
# so we don't infinite recurse on it in the next step.
stack.add(tryStmt)
# Find finally-stmt for this try-stmt
# and generate a copy of its sons
var finallyStmt = lastSon(tryStmt.n)
if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0])
# push old elements again:
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
# Pop exceptions that was handled by the
# except-blocks we are in
for i in countdown(howManyExcepts-1, 0):
linefmt(p, cpsStmts, "#popCurrentException();$n")
proc genReturnStmt(p: BProc, t: PNode) =
if nfPreventCg in t.flags: return
p.beforeRetNeeded = true
@@ -772,6 +775,13 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
else:
genOrdinalCase(p, t, d)
proc genRestoreFrameAfterException(p: BProc) =
if optStackTrace in p.module.config.options:
if not p.hasCurFramePointer:
p.hasCurFramePointer = true
p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", []))
p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", []))
linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n")
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
# code to generate:
@@ -791,8 +801,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
# finallyPart();
template genExceptBranchBody(body: PNode) {.dirty.} =
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
genRestoreFrameAfterException(p)
expr(p, body, d)
if not isEmptyType(t.typ) and d.k == locNone:
@@ -895,8 +904,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
endBlock(p)
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
genRestoreFrameAfterException(p)
p.nestedTryStmts[^1].inExcept = true
var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch):

View File

@@ -68,6 +68,8 @@ type
prc*: PSym # the Nim proc that this C proc belongs to
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar
hasCurFramePointer*: bool # true if _nimCurFrame var needed to recover after
# exception is generated
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
currLineInfo*: TLineInfo # AST codegen will make this superfluous
nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]

1306
compiler/closureiters.nim Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,12 +7,11 @@
# distribution, for details about the copyright.
#
# This include file implements lambda lifting for the transformator.
# This file implements lambda lifting for the transformator.
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, magicsys, lowerings, tables,
modulegraphs, lineinfos
intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos
discard """
The basic approach is that captured vars need to be put on the heap and
@@ -126,7 +125,7 @@ proc newCall(a: PSym, b: PNode): PNode =
result.add newSymNode(a)
result.add b
proc createStateType(g: ModuleGraph; iter: PSym): PType =
proc createClosureIterStateType*(g: ModuleGraph; iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
@@ -137,8 +136,8 @@ proc createStateType(g: ModuleGraph; iter: PSym): PType =
rawAddSon(result, intType)
proc createStateField(g: ModuleGraph; iter: PSym): PSym =
result = newSym(skField, getIdent(g.cache, ":state"), iter, iter.info, {})
result.typ = createStateType(g, iter)
result = newSym(skField, getIdent(g.cache, ":state"), iter, iter.info)
result.typ = createClosureIterStateType(g, iter)
proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
# YYY meh, just add the state field for every closure for now, it's too
@@ -146,12 +145,12 @@ proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
result = createObj(g, owner, info, final=false)
rawAddField(result, createStateField(g, owner))
proc getIterResult(iter: PSym; cache: IdentCache): PSym =
proc getClosureIterResult*(g: ModuleGraph; iter: PSym): PSym =
if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent(cache, ":result"), iter, iter.info, {})
result = newSym(skResult, getIdent(g.cache, ":result"), iter, iter.info, {})
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
@@ -400,7 +399,11 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
if not c.capturedVars.containsOrIncl(s.id):
let obj = getHiddenParam(c.graph, owner).typ.lastSon
#let obj = c.getEnvTypeForOwner(s.owner).lastSon
addField(obj, s, c.graph.cache)
if s.name.id == getIdent(c.graph.cache, ":state").id:
obj.n[0].sym.id = -s.id
else:
addField(obj, s, c.graph.cache)
# but always return because the rest of the proc is only relevant when
# ow != owner:
return
@@ -598,7 +601,7 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
localError(d.graph.config, n.info, "internal error: not part of closure object type")
result = n
proc getStateField(g: ModuleGraph; owner: PSym): PSym =
proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
getHiddenParam(g, owner).typ.sons[0].n.sons[0].sym
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
@@ -625,7 +628,7 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = liftCapturedVars(n.sons[0], owner, d, c)
addSon(a, newSymNode(getIterResult(owner, d.graph.cache)))
addSon(a, newSymNode(getClosureIterResult(d.graph, owner)))
addSon(a, retVal)
retStmt.add(a)
else:
@@ -718,7 +721,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
# echo renderTree(s.getBody, {renderIds})
let oldInContainer = c.inContainer
c.inContainer = 0
let body = wrapIterBody(d.graph, liftCapturedVars(s.getBody, s, d, c), s)
var body = liftCapturedVars(s.getBody, s, d, c)
if oldIterTransf in d.graph.config.features:
body = wrapIterBody(d.graph, body, s)
if c.envvars.getOrDefault(s.id).isNil:
s.ast.sons[bodyPos] = body
else:
@@ -761,9 +766,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
if n[1].kind == nkClosure: result = n[1]
else:
if owner.isIterator:
if n.kind == nkYieldStmt:
if oldIterTransf in d.graph.config.features and n.kind == nkYieldStmt:
return transformYield(n, owner, d, c)
elif n.kind == nkReturnStmt:
elif oldIterTransf in d.graph.config.features and n.kind == nkReturnStmt:
return transformReturn(n, owner, d, c)
elif nfLL in n.flags:
# special case 'when nimVm' due to bug #3636:
@@ -811,7 +816,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo
fn.typ.callConv = oldCC
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
# XXX conf.cmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
# However we can do lifting for the stuff which is *only* compiletime.
@@ -820,6 +825,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PN
if body.kind == nkEmpty or (
g.config.cmd == cmdCompileToJS and not isCompileTime) or
fn.skipGenericOwner.kind != skModule:
# ignore forward declaration:
result = body
tooEarly = true
@@ -831,10 +837,12 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PN
d.somethingToDo = true
if d.somethingToDo:
var c = initLiftingPass(fn)
var newBody = liftCapturedVars(body, fn, d, c)
result = liftCapturedVars(body, fn, d, c)
if c.envvars.getOrDefault(fn.id) != nil:
newBody = newTree(nkStmtList, rawClosureCreation(fn, d, c), newBody)
result = wrapIterBody(g, newBody, fn)
result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result)
if oldIterTransf in g.config.features:
result = wrapIterBody(g, result, fn)
else:
result = body
#if fn.name.s == "get2":
@@ -872,7 +880,8 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
cl = createClosure()
while true:
let i = foo(cl)
nkBreakState(cl.state)
if (nkBreakState(cl.state)):
break
...
"""
if liftingHarmful(g.config, owner): return body
@@ -932,5 +941,16 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
loopBody.sons[0] = v2
var bs = newNodeI(nkBreakState, body.info)
bs.addSon(call.sons[0])
loopBody.sons[1] = bs
let ibs = newNodeI(nkIfStmt, body.info)
let elifBranch = newNodeI(nkElifBranch, body.info)
elifBranch.add(bs)
let br = newNodeI(nkBreakStmt, body.info)
br.add(g.emptyNode)
elifBranch.add(br)
ibs.add(elifBranch)
loopBody.sons[1] = ibs
loopBody.sons[2] = body[L-1]

View File

@@ -25,7 +25,7 @@ const
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
'|', '=', '%', '&', '$', '@', '~', ':'}
# don't forget to update the 'highlite' module if these charsets should change

View File

@@ -201,7 +201,8 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
else:
processSwitch(s, val, passPP, info, config)
proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
proc readConfigFile(
filename: string; cache: IdentCache; config: ConfigRef): bool =
var
L: TLexer
tok: TToken
@@ -216,7 +217,7 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
if len(condStack) > 0: lexMessage(L, errGenerated, "expected @end")
closeLexer(L)
rawMessage(config, hintConf, filename)
return true
proc getUserConfigPath(filename: string): string =
result = joinPath(getConfigDir(), filename)
@@ -233,23 +234,33 @@ proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
setDefaultLibpath(conf)
var configFiles = newSeq[string]()
template readConfigFile(path: string) =
let configPath = path
if readConfigFile(configPath, cache, conf):
add(configFiles, configPath)
if optSkipConfigFile notin conf.globalOptions:
readConfigFile(getSystemConfigPath(conf, cfg), cache, conf)
readConfigFile(getSystemConfigPath(conf, cfg))
if optSkipUserConfigFile notin conf.globalOptions:
readConfigFile(getUserConfigPath(cfg), cache, conf)
readConfigFile(getUserConfigPath(cfg))
let pd = if conf.projectPath.len > 0: conf.projectPath else: getCurrentDir()
if optSkipParentConfigFiles notin conf.globalOptions:
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
readConfigFile(dir / cfg, cache, conf)
readConfigFile(dir / cfg)
if optSkipProjConfigFile notin conf.globalOptions:
readConfigFile(pd / cfg, cache, conf)
readConfigFile(pd / cfg)
if conf.projectName.len != 0:
# new project wide config file:
var projectConfig = changeFileExt(conf.projectFull, "nimcfg")
if not fileExists(projectConfig):
projectConfig = changeFileExt(conf.projectFull, "nim.cfg")
readConfigFile(projectConfig, cache, conf)
readConfigFile(projectConfig)
for filename in configFiles:
rawMessage(conf, hintConf, filename)

View File

@@ -118,7 +118,8 @@ type
callOperator,
parallel,
destructor,
notnil
notnil,
oldIterTransf
SymbolFilesOption* = enum
disabledSf, writeOnlySf, readOnlySf, v2Sf

View File

@@ -381,6 +381,10 @@ proc processPush(c: PContext, n: PNode, start: int) =
x.otherPragmas.add n.sons[i]
#localError(c.config, n.info, errOptionExpected)
# If stacktrace is disabled globally we should not enable it
if optStackTrace notin c.optionStack[0].options:
c.config.options.excl(optStackTrace)
proc processPop(c: PContext, n: PNode) =
if c.optionStack.len <= 1:
localError(c.config, n.info, "{.pop.} without a corresponding {.push.}")

View File

@@ -1414,11 +1414,21 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParLe, "(ComesFrom|")
gsub(g, n, 0)
put(g, tkParRi, ")")
of nkGotoState, nkState:
of nkGotoState:
var c: TContext
initContext c
putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
putWithSpace g, tkSymbol, "goto"
gsons(g, n, c)
of nkState:
var c: TContext
initContext c
putWithSpace g, tkSymbol, "state"
gsub(g, n[0], c)
putWithSpace(g, tkColon, ":")
indentNL(g)
gsons(g, n, c, 1)
dedent(g)
of nkBreakState:
put(g, tkTuple, "breakstate")
of nkTypeClassTy:

View File

@@ -158,11 +158,13 @@ proc commonType*(x, y: PType): PType =
a = a.lastSon.skipTypes({tyGenericInst})
b = b.lastSon.skipTypes({tyGenericInst})
if a.kind == tyObject and b.kind == tyObject:
result = commonSuperclass(a, b, k)
result = commonSuperclass(a, b)
# this will trigger an error later:
if result.isNil or result == a: return x
if result == b: return y
if k != tyNone:
# bug #7906, tyRef/tyPtr + tyGenericInst of ref/ptr object ->
# ill-formed AST, no need for additional tyRef/tyPtr
if k != tyNone and x.kind != tyGenericInst:
let r = result
result = newType(k, r.owner)
result.addSonSkipIntLit(r)

View File

@@ -1556,7 +1556,7 @@ proc semYield(c: PContext, n: PNode): PNode =
checkSonsLen(n, 1, c.config)
if c.p.owner == nil or c.p.owner.kind != skIterator:
localError(c.config, n.info, errYieldNotAllowedHere)
elif c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline:
elif oldIterTransf in c.features and c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline:
localError(c.config, n.info, errYieldNotAllowedInTryStmt)
elif n.sons[0].kind != nkEmpty:
n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:

View File

@@ -2020,6 +2020,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
if r == isGeneric:
result.typ = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true
# bug #4799, varargs accepting subtype relation object
elif r == isSubtype:
inc(m.subtypeMatches)
if f.kind == tyTypeDesc:
result = arg
else:
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
m.baseTypeMatch = true
else:
result = userConvMatch(c, m, base(f), a, arg)
if result != nil: m.baseTypeMatch = true

View File

@@ -19,9 +19,9 @@
# * transforms 'defer' into a 'try finally' statement
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
idents, renderer, types, passes, semfold, magicsys, cgmeth,
lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals,
lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters,
modulegraphs, lineinfos
type
@@ -984,6 +984,10 @@ proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
result = liftLocalsIfRequested(prc, result, g.cache, g.config)
if c.needsDestroyPass: #and newDestructors:
result = injectDestructorCalls(g, prc, result)
if prc.isIterator and oldIterTransf notin g.config.features:
result = g.transformClosureIterator(prc, result)
incl(result.flags, nfTransf)
#if prc.name.s == "testbody":
# echo renderTree(result)

View File

@@ -1044,7 +1044,7 @@ proc inheritanceDiff*(a, b: PType): int =
inc(result)
result = high(int)
proc commonSuperclass*(a, b: PType, k: TTypeKind): PType =
proc commonSuperclass*(a, b: PType): PType =
# quick check: are they the same?
if sameObjectTypes(a, b): return a
@@ -1064,7 +1064,7 @@ proc commonSuperclass*(a, b: PType, k: TTypeKind): PType =
y = skipTypes(y, skipPtrs)
if ancestors.contains(y.id):
# bug #7818, defer the previous skipTypes
if k in {tyRef, tyPtr}: t = y
if t.kind != tyGenericInst: t = y
return t
y = y.sons[0]

View File

@@ -855,7 +855,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNewStringOfCap:
# we ignore the 'cap' argument and translate it as 'newString(0)'.
# eval n.sons[1] for possible side effects:
var tmp = c.genx(n.sons[1])
c.freeTemp(c.genx(n.sons[1]))
var tmp = c.getTemp(n.sons[1].typ)
c.gABx(n, opcLdImmInt, tmp, 0)
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opcNewStr, dest, tmp)

View File

@@ -10,11 +10,11 @@
## Regular expression support for Nim.
##
## This module is implemented by providing a wrapper around the
## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
## C library. This means that your application will depend on the PRCE
## `PCRE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
## C library. This means that your application will depend on the PCRE
## library's licence when using this module, which should not be a problem
## though.
## PRCE's licence follows:
## PCRE's licence follows:
##
## .. include:: ../../doc/regexprs.txt
##

View File

@@ -130,7 +130,7 @@ proc nimNumber(g: var GeneralTokenizer, position: int): int =
const
OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
'|', '=', '%', '&', '$', '@', '~', ':'}
proc nimNextToken(g: var GeneralTokenizer) =
const

View File

@@ -82,6 +82,14 @@ const
# Special types
type Sighandler = proc (a: cint) {.noconv.}
const StatHasNanoseconds* = defined(linux) or defined(freebsd) or
defined(openbsd) or defined(dragonfly) ## \
## Boolean flag that indicates if the system supports nanosecond time
## resolution in the fields of ``Stat``. Note that the nanosecond based fields
## (``Stat.st_atim``, ``Stat.st_mtim`` and ``Stat.st_ctim``) can be accessed
## without checking this flag, because this module defines fallback procs
## when they are not available.
# Platform specific stuff
when defined(linux) and defined(amd64):
@@ -92,9 +100,9 @@ else:
# There used to be this name in posix.nim a long time ago, not sure why!
{.deprecated: [cSIG_HOLD: SIG_HOLD].}
when not defined(macosx) and not defined(android):
when StatHasNanoseconds:
proc st_atime*(s: Stat): Time {.inline.} =
## Second-granularity time of last access
## Second-granularity time of last access.
result = s.st_atim.tv_sec
proc st_mtime*(s: Stat): Time {.inline.} =
## Second-granularity time of last data modification.
@@ -102,6 +110,16 @@ when not defined(macosx) and not defined(android):
proc st_ctime*(s: Stat): Time {.inline.} =
## Second-granularity time of last status change.
result = s.st_ctim.tv_sec
else:
proc st_atim*(s: Stat): TimeSpec {.inline.} =
## Nanosecond-granularity time of last access.
result.tv_sec = s.st_atime
proc st_mtim*(s: Stat): TimeSpec {.inline.} =
## Nanosecond-granularity time of last data modification.
result.tv_sec = s.st_mtime
proc st_ctim*(s: Stat): TimeSpec {.inline.} =
## Nanosecond-granularity time of last data modification.
result.tv_sec = s.st_ctime
when hasAioH:
proc aio_cancel*(a1: cint, a2: ptr Taiocb): cint {.importc, header: "<aio.h>".}

View File

@@ -215,14 +215,14 @@ type
## For a typed memory object, the length in bytes.
## For other file types, the use of this field is
## unspecified.
when defined(macosx) or defined(android):
st_atime*: Time ## Time of last access.
st_mtime*: Time ## Time of last data modification.
st_ctime*: Time ## Time of last status change.
else:
when StatHasNanoseconds:
st_atim*: Timespec ## Time of last access.
st_mtim*: Timespec ## Time of last data modification.
st_ctim*: Timespec ## Time of last status change.
else:
st_atime*: Time ## Time of last access.
st_mtime*: Time ## Time of last data modification.
st_ctime*: Time ## Time of last status change.
st_blksize*: Blksize ## A file system-specific preferred I/O block size
## for this object. In some file system types, this
## may vary from file to file.

View File

@@ -62,52 +62,6 @@ template createCb(retFutureSym, iteratorNameSym,
identName()
#{.pop.}
proc generateExceptionCheck(futSym,
tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
if tryStmt.kind == nnkNilLit:
result = rootReceiver
else:
var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
let errorNode = newDotExpr(futSym, newIdentNode("error"))
for i in 1 ..< tryStmt.len:
let exceptBranch = tryStmt[i]
if exceptBranch[0].kind == nnkStmtList:
exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
else:
var exceptIdentCount = 0
var ifCond: NimNode
for i in 0 ..< exceptBranch.len:
let child = exceptBranch[i]
if child.kind == nnkIdent:
let cond = infix(errorNode, "of", child)
if exceptIdentCount == 0:
ifCond = cond
else:
ifCond = infix(ifCond, "or", cond)
else:
break
exceptIdentCount.inc
expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
# -> -> else: raise futSym.error
exceptionChecks.add((newIdentNode("true"),
newNimNode(nnkRaiseStmt).add(errorNode)))
# Read the future if there is no error.
# -> else: futSym.read
let elseNode = newNimNode(nnkElse, fromNode)
elseNode.add newNimNode(nnkStmtList, fromNode)
elseNode[0].add rootReceiver
let ifBody = newStmtList()
ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
ifBody.add newIfStmt(exceptionChecks)
ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
result = newIfStmt(
(newDotExpr(futSym, newIdentNode("failed")), ifBody)
)
result.add elseNode
template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
rootReceiver: untyped, fromNode: NimNode) =
@@ -123,8 +77,7 @@ template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
# -> future<x>.read
valueReceiver = newDotExpr(futureVarNode, newIdentNode("read"))
result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver,
fromNode)
result.add rootReceiver
template createVar(result: var NimNode, futSymName: string,
asyncProc: NimNode,
@@ -154,8 +107,8 @@ proc createFutureVarCompletions(futureVarIdents: seq[NimNode],
)
proc processBody(node, retFutureSym: NimNode,
subTypeIsVoid: bool, futureVarIdents: seq[NimNode],
tryStmt: NimNode): NimNode {.compileTime.} =
subTypeIsVoid: bool,
futureVarIdents: seq[NimNode]): NimNode {.compileTime.} =
#echo(node.treeRepr)
result = node
case node.kind
@@ -173,7 +126,7 @@ proc processBody(node, retFutureSym: NimNode,
result.add newCall(newIdentNode("complete"), retFutureSym)
else:
let x = node[0].processBody(retFutureSym, subTypeIsVoid,
futureVarIdents, tryStmt)
futureVarIdents)
if x.kind == nnkYieldStmt: result.add x
else:
result.add newCall(newIdentNode("complete"), retFutureSym, x)
@@ -224,63 +177,11 @@ proc processBody(node, retFutureSym: NimNode,
var newDiscard = node
result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
newDiscard[0], newDiscard, node)
of nnkTryStmt:
# try: await x; except: ...
result = newNimNode(nnkStmtList, node)
template wrapInTry(n, tryBody: untyped) =
var temp = n
n[0] = tryBody
tryBody = temp
# Transform ``except`` body.
# TODO: Could we perform some ``await`` transformation here to get it
# working in ``except``?
tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid,
futureVarIdents, nil)
proc processForTry(n: NimNode, i: var int,
res: NimNode): bool {.compileTime.} =
## Transforms the body of the tryStmt. Does not transform the
## body in ``except``.
## Returns true if the tryStmt node was transformed into an ifStmt.
result = false
var skipped = n.skipStmtList()
while i < skipped.len:
var processed = processBody(skipped[i], retFutureSym,
subTypeIsVoid, futureVarIdents, n)
# Check if we transformed the node into an exception check.
# This suggests skipped[i] contains ``await``.
if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
processed = processed.skipUntilStmtList()
expectKind(processed, nnkStmtList)
expectKind(processed[2][1], nnkElse)
i.inc
if not processForTry(n, i, processed[2][1][0]):
# We need to wrap the nnkElse nodes back into a tryStmt.
# As they are executed if an exception does not happen
# inside the awaited future.
# The following code will wrap the nodes inside the
# original tryStmt.
wrapInTry(n, processed[2][1][0])
res.add processed
result = true
else:
res.add skipped[i]
i.inc
var i = 0
if not processForTry(node, i, result):
# If the tryStmt hasn't been transformed we can just put the body
# back into it.
wrapInTry(node, result)
return
else: discard
for i in 0 ..< result.len:
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid,
futureVarIdents, nil)
futureVarIdents)
proc getName(node: NimNode): string {.compileTime.} =
case node.kind
@@ -362,7 +263,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
# -> complete(retFuture, result)
var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
futureVarIdents, nil)
futureVarIdents)
# don't do anything with forward bodies (empty)
if procBody.kind != nnkEmpty:
procBody.add(createFutureVarCompletions(futureVarIdents, nil))

View File

@@ -167,7 +167,7 @@ proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) =
## increments `c[key]` by `val`.
let oldCount = c.count
var n = rawInsert(c, key)
if c.count == oldCount or oldCount == 0:
if c.count >= oldCount or oldCount == 0:
# not a new key:
inc n.val, val
@@ -322,10 +322,14 @@ proc `$`*[T](c: CritBitTree[T]): string =
const avgItemLen = 16
result = newStringOfCap(c.count * avgItemLen)
result.add("{")
for key, val in pairs(c):
if result.len > 1: result.add(", ")
result.add($key)
when T isnot void:
when T is void:
for key in keys(c):
if result.len > 1: result.add(", ")
result.addQuoted(key)
else:
for key, val in pairs(c):
if result.len > 1: result.add(", ")
result.addQuoted(key)
result.add(": ")
result.addQuoted(val)
result.add("}")
@@ -362,3 +366,12 @@ when isMainModule:
c.inc("a", -5)
assert c["a"] == 0
c.inc("b", 2)
assert c["b"] == 2
c.inc("c", 3)
assert c["c"] == 3
c.inc("a", 1)
assert c["a"] == 1

View File

@@ -328,14 +328,14 @@ proc toJson(x: NimNode): NimNode {.compiletime.} =
result = newNimNode(nnkBracket)
for i in 0 ..< x.len:
result.add(toJson(x[i]))
result = newCall(bindSym"%", result)
result = newCall(bindSym("%", brOpen), result)
of nnkTableConstr: # object
if x.len == 0: return newCall(bindSym"newJObject")
result = newNimNode(nnkTableConstr)
for i in 0 ..< x.len:
x[i].expectKind nnkExprColonExpr
result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1]))
result = newCall(bindSym"%", result)
result = newCall(bindSym("%", brOpen), result)
of nnkCurly: # empty object
x.expectLen(0)
result = newCall(bindSym"newJObject")
@@ -343,9 +343,9 @@ proc toJson(x: NimNode): NimNode {.compiletime.} =
result = newCall(bindSym"newJNull")
of nnkPar:
if x.len == 1: result = toJson(x[0])
else: result = newCall(bindSym"%", x)
else: result = newCall(bindSym("%", brOpen), x)
else:
result = newCall(bindSym"%", x)
result = newCall(bindSym("%", brOpen), x)
macro `%*`*(x: untyped): untyped =
## Convert an expression to a JsonNode directly, without having to specify

View File

@@ -129,6 +129,12 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
## If `x` is empty, 0 is returned.
for i in items(x): result = result + i
proc prod*[T](x: openArray[T]): T {.noSideEffect.} =
## Computes the product of the elements in ``x``.
## If ``x`` is empty, 1 is returned.
result = 1.T
for i in items(x): result = result * i
{.push noSideEffect.}
when not defined(JS): # C
proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".}
@@ -274,12 +280,18 @@ when not defined(JS): # C
proc erfc*(x: float64): float64 {.importc: "erfc", header: "<math.h>".}
## The complementary error function
proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "<math.h>".}
proc gamma*(x: float64): float64 {.importc: "tgamma", header: "<math.h>".}
## The gamma function
proc tgamma*(x: float32): float32
{.deprecated: "use gamma instead", importc: "tgammaf", header: "<math.h>".}
proc tgamma*(x: float64): float64
{.deprecated: "use gamma instead", importc: "tgamma", header: "<math.h>".}
## The gamma function
## **Deprecated since version 0.19.0**: Use ``gamma`` instead.
proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "<math.h>".}
proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "<math.h>".}
## Natural log of the gamma function
proc tgamma*(x: float32): float32 {.importc: "tgammaf", header: "<math.h>".}
proc tgamma*(x: float64): float64 {.importc: "tgamma", header: "<math.h>".}
## The gamma function
proc floor*(x: float32): float32 {.importc: "floorf", header: "<math.h>".}
proc floor*(x: float64): float64 {.importc: "floor", header: "<math.h>".}
@@ -372,7 +384,7 @@ when not defined(JS): # C
proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "<math.h>".}
proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "<math.h>".}
## Computes the modulo operation for float operators.
## Computes the modulo operation for float operators.
else: # JS
proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y)
proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.}
@@ -551,6 +563,7 @@ when isMainModule and not defined(JS):
return sqrt(num)
# check gamma function
assert(gamma(5.0) == 24.0) # 4!
assert($tgamma(5.0) == $24.0) # 4!
assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
assert(erf(6.0) > erf(5.0))
@@ -560,6 +573,12 @@ when isMainModule:
# Function for approximate comparison of floats
proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9)
block: # prod
doAssert prod([1, 2, 3, 4]) == 24
doAssert prod([1.5, 3.4]) == 5.1
let x: seq[float] = @[]
doAssert prod(x) == 1.0
block: # round() tests
# Round to 0 decimal places
doAssert round(54.652) ==~ 55.0

View File

@@ -405,33 +405,40 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} =
return false
return true
proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl: var Socklen) =
proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage,
sl: var Socklen) =
## Converts `IpAddress` and `Port` to `SockAddr` and `Socklen`
let port = htons(uint16(port))
case address.family
of IpAddressFamily.IPv4:
sl = sizeof(Sockaddr_in).Socklen
let s = cast[ptr Sockaddr_in](addr sa)
s.sin_family = type(s.sin_family)(AF_INET)
s.sin_family = type(s.sin_family)(toInt(AF_INET))
s.sin_port = port
copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr))
copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0],
sizeof(s.sin_addr))
of IpAddressFamily.IPv6:
sl = sizeof(Sockaddr_in6).Socklen
let s = cast[ptr Sockaddr_in6](addr sa)
s.sin6_family = type(s.sin6_family)(AF_INET6)
s.sin6_family = type(s.sin6_family)(toInt(AF_INET6))
s.sin6_port = port
copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr))
copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0],
sizeof(s.sin6_addr))
proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen, address: var IpAddress, port: var Port) =
if sa.ss_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen:
proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen,
address: var IpAddress, port: var Port) =
if sa.ss_family.int == toInt(AF_INET) and sl == sizeof(Sockaddr_in).Socklen:
address = IpAddress(family: IpAddressFamily.IPv4)
let s = cast[ptr Sockaddr_in](sa)
copyMem(addr address.address_v4[0], addr s.sin_addr, sizeof(address.address_v4))
copyMem(addr address.address_v4[0], addr s.sin_addr,
sizeof(address.address_v4))
port = ntohs(s.sin_port).Port
elif sa.ss_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen:
elif sa.ss_family.int == toInt(AF_INET6) and
sl == sizeof(Sockaddr_in6).Socklen:
address = IpAddress(family: IpAddressFamily.IPv6)
let s = cast[ptr Sockaddr_in6](sa)
copyMem(addr address.address_v6[0], addr s.sin6_addr, sizeof(address.address_v6))
copyMem(addr address.address_v6[0], addr s.sin6_addr,
sizeof(address.address_v6))
port = ntohs(s.sin6_port).Port
else:
raise newException(ValueError, "Neither IPv4 nor IPv6")
@@ -1149,7 +1156,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
return 1
let sslPending = SSLPending(socket.sslHandle)
if sslPending != 0:
return sslPending
return min(sslPending, size)
var startTime = epochTime()
let selRet = select(socket, timeout - int(waited * 1000.0))

View File

@@ -23,6 +23,10 @@ when defined(windows):
import winlean
elif defined(posix):
import posix
proc toTime(ts: Timespec): times.Time {.inline.} =
result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
else:
{.error: "OS module not ported to your operating system!".}
@@ -186,7 +190,7 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1".}
when defined(posix):
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return fromUnix(res.st_mtime.int64)
result = res.st_mtim.toTime
else:
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
@@ -199,7 +203,7 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
when defined(posix):
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return fromUnix(res.st_atime.int64)
result = res.st_atim.toTime
else:
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
@@ -216,7 +220,7 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
when defined(posix):
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return fromUnix(res.st_ctime.int64)
result = res.st_ctim.toTime
else:
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
@@ -228,10 +232,13 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
## Returns true if the file `a` is newer than file `b`, i.e. if `a`'s
## modification time is later than `b`'s.
when defined(posix):
result = getLastModificationTime(a) - getLastModificationTime(b) >= DurationZero
# Posix's resolution sucks so, we use '>=' for posix.
# If we don't have access to nanosecond resolution, use '>='
when not StatHasNanoseconds:
result = getLastModificationTime(a) >= getLastModificationTime(b)
else:
result = getLastModificationTime(a) > getLastModificationTime(b)
else:
result = getLastModificationTime(a) - getLastModificationTime(b) > DurationZero
result = getLastModificationTime(a) > getLastModificationTime(b)
proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
## Returns the `current working directory`:idx:.
@@ -1494,7 +1501,7 @@ type
template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
## Transforms the native file info structure into the one nim uses.
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows,
## or a 'Stat' structure on posix
when defined(Windows):
template merge(a, b): untyped = a or (b shl 32)
@@ -1520,7 +1527,6 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
formalInfo.kind = succ(result.kind)
else:
template checkAndIncludeMode(rawMode, formalMode: untyped) =
if (rawInfo.st_mode and rawMode) != 0'i32:
@@ -1528,9 +1534,9 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
formalInfo.id = (rawInfo.st_dev, rawInfo.st_ino)
formalInfo.size = rawInfo.st_size
formalInfo.linkCount = rawInfo.st_Nlink.BiggestInt
formalInfo.lastAccessTime = fromUnix(rawInfo.st_atime.int64)
formalInfo.lastWriteTime = fromUnix(rawInfo.st_mtime.int64)
formalInfo.creationTime = fromUnix(rawInfo.st_ctime.int64)
formalInfo.lastAccessTime = rawInfo.st_atim.toTime
formalInfo.lastWriteTime = rawInfo.st_mtim.toTime
formalInfo.creationTime = rawInfo.st_ctim.toTime
result.permissions = {}
checkAndIncludeMode(S_IRUSR, fpUserRead)
@@ -1644,7 +1650,9 @@ proc setLastModificationTime*(file: string, t: times.Time) =
## an error.
when defined(posix):
let unixt = posix.Time(t.toUnix)
var timevals = [Timeval(tv_sec: unixt), Timeval(tv_sec: unixt)] # [last access, last modification]
let micro = convert(Nanoseconds, Microseconds, t.nanosecond)
var timevals = [Timeval(tv_sec: unixt, tv_usec: micro),
Timeval(tv_sec: unixt, tv_usec: micro)] # [last access, last modification]
if utimes(file, timevals.addr) != 0: raiseOSError(osLastError())
else:
let h = openHandle(path = file, writeAccess = true)

View File

@@ -527,8 +527,13 @@ proc format*(value: SomeFloat; specifier: string; res: var string) =
var sign = false
if value >= 0.0:
if spec.sign != '-':
f = spec.sign & f
sign = true
if value == 0.0:
if 1.0 / value == Inf:
# only insert the sign if value != negZero
f.insert($spec.sign, 0)
else:
f.insert($spec.sign, 0)
else:
sign = true
@@ -558,12 +563,16 @@ proc format*(value: string; specifier: string; res: var string) =
## sense to call this directly, but it is required to exist
## by the ``&`` macro.
let spec = parseStandardFormatSpecifier(specifier)
var value = value
case spec.typ
of 's', '\0': discard
else:
raise newException(ValueError,
"invalid type in format string for string, expected 's', but got " &
spec.typ)
if spec.precision != -1:
if spec.precision < runelen(value):
setLen(value, runeOffset(value, spec.precision))
res.add alignString(value, spec.minimumWidth, spec.align, spec.fill)
when isMainModule:

View File

@@ -185,8 +185,7 @@ type
DurationParts* = array[FixedTimeUnit, int64] # Array of Duration parts starts
TimeIntervalParts* = array[TimeUnit, int] # Array of Duration parts starts
TimesMutableTypes = DateTime | Time | Duration | TimeInterval
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
TTimeInterval: TimeInterval, TTimeInfo: DateTime, TimeInfo: DateTime].}
@@ -607,30 +606,12 @@ proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} =
doAssert (fromUnix(0) + initDuration(seconds = 1)) == fromUnix(1)
addImpl[Time](a, b)
proc `+=`*(a: var Time, b: Duration) {.operator.} =
## Modify ``a`` in place by subtracting ``b``.
runnableExamples:
var tm = fromUnix(0)
tm += initDuration(seconds = 1)
doAssert tm == fromUnix(1)
a = addImpl[Time](a, b)
proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} =
## Subtracts a duration of time from a ``Time``.
runnableExamples:
doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1)
subImpl[Time](a, b)
proc `-=`*(a: var Time, b: Duration) {.operator.} =
## Modify ``a`` in place by adding ``b``.
runnableExamples:
var tm = fromUnix(0)
tm -= initDuration(seconds = 1)
doAssert tm == fromUnix(-1)
a = subImpl[Time](a, b)
proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} =
## Returns true iff ``a < b``, that is iff a happened before b.
ltImpl(a, b)
@@ -1377,17 +1358,6 @@ proc `+`*(time: Time, interval: TimeInterval): Time =
else:
toTime(time.local + interval)
proc `+=`*(time: var Time, interval: TimeInterval) =
## Modifies `time` by adding `interval`.
## If `interval` contains any years, months, weeks or days the operation
## is performed in the local timezone.
runnableExamples:
var tm = fromUnix(0)
tm += 5.seconds
doAssert tm == fromUnix(5)
time = time + interval
proc `-`*(time: Time, interval: TimeInterval): Time =
## Subtracts `interval` from Time `time`.
## If `interval` contains any years, months, weeks or days the operation
@@ -1401,15 +1371,30 @@ proc `-`*(time: Time, interval: TimeInterval): Time =
else:
toTime(time.local - interval)
proc `-=`*(time: var Time, interval: TimeInterval) =
## Modifies `time` by subtracting `interval`.
## If `interval` contains any years, months, weeks or days the operation
## is performed in the local timezone.
proc `+=`*[T, U: TimesMutableTypes](a: var T, b: U) =
## Modify ``a`` in place by adding ``b``.
runnableExamples:
var tm = fromUnix(0)
tm += initDuration(seconds = 1)
doAssert tm == fromUnix(1)
a = a + b
proc `-=`*[T, U: TimesMutableTypes](a: var T, b: U) =
## Modify ``a`` in place by subtracting ``b``.
runnableExamples:
var tm = fromUnix(5)
tm -= 5.seconds
tm -= initDuration(seconds = 5)
doAssert tm == fromUnix(0)
time = time - interval
a = a - b
proc `*=`*[T: TimesMutableTypes, U](a: var T, b: U) =
# Mutable type is often multiplied by number
runnableExamples:
var dur = initDuration(seconds = 1)
dur *= 5
doAssert dur == initDuration(seconds = 5)
a = a * b
proc formatToken(dt: DateTime, token: string, buf: var string) =
## Helper of the format proc to parse individual tokens.

View File

@@ -2681,7 +2681,7 @@ when not defined(nimscript) and hasAlloc:
{.warning: "GC_unref is a no-op in JavaScript".}
template GC_getStatistics*(): string =
{.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
{.warning: "GC_getStatistics is a no-op in JavaScript".}
""
template accumulateResult*(iter: untyped) =

View File

@@ -116,7 +116,7 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
if mode == mStore:
x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize)
else:
unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
var dstseq = cast[PGenericSeq](dst)
dstseq.len = seq.len

View File

@@ -41,3 +41,6 @@ proc reraiseException() {.compilerRtl.} =
proc writeStackTrace() = discard
proc setControlCHook(hook: proc () {.noconv.}) = discard
proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} =
sysFatal(ReraiseError, "exception handling is not available")

View File

@@ -131,6 +131,10 @@ proc popCurrentExceptionEx(id: uint) {.compilerRtl.} =
quitOrDebug()
prev.up = cur.up
proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} =
if not e.isNil:
currException = e
# some platforms have native support for stack traces:
const
nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and

View File

@@ -1,24 +1,5 @@
discard """
msg: '''BracketExpr
Sym "array"
Infix
Ident ".."
IntLit 0
IntLit 2
BracketExpr
Sym "Vehicle"
Sym "int"
---------
BracketExpr
Sym "array"
Infix
Ident ".."
IntLit 0
IntLit 2
BracketExpr
Sym "Vehicle"
Sym "int"
---------'''
output: "OK"
"""
# bug #7818
@@ -34,12 +15,118 @@ type
Bike[T] = object of Vehicle[T]
macro peek(n: typed): untyped =
echo getTypeImpl(n).treeRepr
echo "---------"
let val = getTypeImpl(n).treeRepr
newLit(val)
block test_t7818:
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)
let y = peek([c, b, v])
let z = peek([v, c, b])
doAssert(y == z)
block test_t7906_1:
proc init(x: typedesc, y: int): ref x =
result = new(ref x)
result.tire = y
var v = init(Vehicle[int], 3)
var c = init(Car[int], 4)
var b = init(Bike[int], 2)
let y = peek([c, b, v])
let z = peek([v, c, b])
doAssert(y == z)
block test_t7906_2:
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)
let y = peek([c.addr, b.addr, v.addr])
let z = peek([v.addr, c.addr, b.addr])
doAssert(y == z)
block test_t7906_3:
type
Animal[T] = object of RootObj
hair: T
Mammal[T] = object of Animal[T]
Monkey[T] = object of Mammal[T]
var v = Animal[int](hair: 3)
var c = Mammal[int](hair: 4)
var b = Monkey[int](hair: 2)
let z = peek([c.addr, b.addr, v.addr])
let y = peek([v.addr, c.addr, b.addr])
doAssert(y == z)
type
Fruit[T] = ref object of RootObj
color: T
Apple[T] = ref object of Fruit[T]
Banana[T] = ref object of Fruit[T]
proc testArray[T](x: array[3, Fruit[T]]): string =
result = ""
for c in x:
result.add $c.color
proc testOpenArray[T](x: openArray[Fruit[T]]): string =
result = ""
for c in x:
result.add $c.color
block test_t7906_4:
var v = Fruit[int](color: 3)
var c = Apple[int](color: 4)
var b = Banana[int](color: 2)
let y = peek([c, b, v])
let z = peek([v, c, b])
doAssert(y == z)
block test_t7906_5:
var a = Fruit[int](color: 1)
var b = Apple[int](color: 2)
var c = Banana[int](color: 3)
doAssert(testArray([a, b, c]) == "123")
doAssert(testArray([b, c, a]) == "231")
doAssert(testOpenArray([a, b, c]) == "123")
doAssert(testOpenArray([b, c, a]) == "231")
doAssert(testOpenArray(@[a, b, c]) == "123")
doAssert(testOpenArray(@[b, c, a]) == "231")
proc testArray[T](x: array[3, ptr Vehicle[T]]): string =
result = ""
for c in x:
result.add $c.tire
proc testOpenArray[T](x: openArray[ptr Vehicle[T]]): string =
result = ""
for c in x:
result.add $c.tire
block test_t7906_6:
var u = Vehicle[int](tire: 1)
var v = Bike[int](tire: 2)
var w = Car[int](tire: 3)
doAssert(testArray([u.addr, v.addr, w.addr]) == "123")
doAssert(testArray([w.addr, u.addr, v.addr]) == "312")
doAssert(testOpenArray([u.addr, v.addr, w.addr]) == "123")
doAssert(testOpenArray([w.addr, u.addr, v.addr]) == "312")
doAssert(testOpenArray(@[u.addr, v.addr, w.addr]) == "123")
doAssert(testOpenArray(@[w.addr, u.addr, v.addr]) == "312")
echo "OK"
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)
peek([c, b, v])
peek([v, c, b])

19
tests/async/t7985.nim Normal file
View File

@@ -0,0 +1,19 @@
discard """
file: "t7985.nim"
exitcode: 0
output: "(value: 1)"
"""
import json, asyncdispatch
proc getData(): Future[JsonNode] {.async.} =
result = %*{"value": 1}
type
MyData = object
value: BiggestInt
proc main() {.async.} =
let data = to(await(getData()), MyData)
echo data
waitFor(main())

View File

@@ -1,18 +1,25 @@
discard """
errormsg: "invalid control flow: 'yield' within a constructor"
line: 16
output: '''
@[1, 2, 3, 4]
123
'''
"""
# bug #5314, bug #6626
import asyncdispatch
proc bar(): Future[int] {.async.} =
await sleepAsync(500)
result = 3
proc bar(i: int): Future[int] {.async.} =
await sleepAsync(2)
result = i
proc foo(): Future[seq[int]] {.async.} =
await sleepAsync(500)
result = @[1, 2, await bar(), 4] # <--- The bug is here
await sleepAsync(2)
result = @[1, 2, await bar(3), 4] # <--- The bug is here
proc foo2() {.async.} =
await sleepAsync(2)
echo(await bar(1), await bar(2), await bar(3))
echo waitFor foo()
waitFor foo2()

View File

@@ -3,7 +3,7 @@ discard """
disabled: "windows"
output: "Matched"
"""
import asyncdispatch
import asyncdispatch, strutils
# Tests to ensure our exception trace backs are friendly.
@@ -82,7 +82,7 @@ Async traceback:
asyncmacro\.nim\(\d+?\)\s+?a
asyncmacro\.nim\(\d+?\)\s+?a_continue
## Resumes an async procedure
asyncmacro\.nim\(\d+?\)\s+?aIter
tasync_traceback\.nim\(\d+?\)\s+?aIter
asyncfutures\.nim\(\d+?\)\s+?read
\]#
Exception message: b failure
@@ -110,17 +110,33 @@ Async traceback:
## Executes pending callbacks
asyncmacro\.nim\(\d+?\)\s+?foo_continue
## Resumes an async procedure
asyncmacro\.nim\(\d+?\)\s+?fooIter
tasync_traceback\.nim\(\d+?\)\s+?fooIter
asyncfutures\.nim\(\d+?\)\s+?read
\]#
Exception message: bar failure
Exception type:
"""
if result.match(re(expected)):
echo("Matched")
else:
echo("Not matched!")
let resLines = splitLines(result.strip)
let expLines = splitLines(expected.strip)
if resLines.len != expLines.len:
echo("Not matched! Wrong number of lines!")
echo()
echo(result)
quit(QuitFailure)
var ok = true
for i in 0 ..< resLines.len:
if not resLines[i].match(re(expLines[i])):
echo "Not matched! Line ", i + 1
echo "Expected:"
echo expLines[i]
echo "Actual:"
echo resLines[i]
ok = false
if ok:
echo("Matched")
else:
quit(QuitFailure)

View File

@@ -9,7 +9,7 @@ Multiple except branches
Multiple except branches 2
'''
"""
import asyncdispatch
import asyncdispatch, strutils
# Here we are testing the ability to catch exceptions.
@@ -22,7 +22,7 @@ proc catch() {.async.} =
try:
await foobar()
except:
echo("Generic except: ", getCurrentExceptionMsg())
echo("Generic except: ", getCurrentExceptionMsg().splitLines[0])
try:
await foobar()

View File

@@ -1,10 +1,12 @@
discard """
file: "tasynctry2.nim"
errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
line: 15
line: 14
"""
import asyncdispatch
{.experimental: "oldIterTransf".}
proc foo(): Future[bool] {.async.} = discard
proc test5(): Future[int] {.async.} =

View File

@@ -68,15 +68,15 @@ block:
block:
var t: CritBitTree[int]
t["a"] = 1
doAssert $t == "{a: 1}"
doAssert $t == """{"a": 1}"""
block:
var t: CritBitTree[string]
t["a"] = "1"
doAssert $t == """{a: "1"}"""
doAssert $t == """{"a": "1"}"""
block:
var t: CritBitTree[char]
t["a"] = '1'
doAssert $t == "{a: '1'}"
doAssert $t == """{"a": '1'}"""
# Test escaping behavior

407
tests/iter/tyieldintry.nim Normal file
View File

@@ -0,0 +1,407 @@
discard """
targets: "c cpp"
output: "ok"
"""
var closureIterResult = newSeq[int]()
proc checkpoint(arg: int) =
closureIterResult.add(arg)
type
TestException = object of Exception
AnotherException = object of Exception
proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedResults: varargs[int]) =
closureIterResult.setLen(0)
var exceptionCaught = false
try:
for i in it():
closureIterResult.add(i)
except TestException:
exceptionCaught = true
if closureIterResult != @expectedResults or exceptionCaught != exceptionExpected:
if closureIterResult != @expectedResults:
echo "Expected: ", @expectedResults
echo "Actual: ", closureIterResult
if exceptionCaught != exceptionExpected:
echo "Expected exception: ", exceptionExpected
echo "Got exception: ", exceptionCaught
doAssert(false)
proc test(it: iterator(): int, expectedResults: varargs[int]) =
testClosureIterAux(it, false, expectedResults)
proc testExc(it: iterator(): int, expectedResults: varargs[int]) =
testClosureIterAux(it, true, expectedResults)
proc raiseException() =
raise newException(TestException, "Test exception!")
block:
iterator it(): int {.closure.} =
var i = 5
while i != 0:
yield i
if i == 3:
yield 123
dec i
test(it, 5, 4, 3, 123, 2, 1)
block:
iterator it(): int {.closure.} =
yield 0
try:
checkpoint(1)
raiseException()
except TestException:
checkpoint(2)
yield 3
checkpoint(4)
finally:
checkpoint(5)
checkpoint(6)
test(it, 0, 1, 2, 3, 4, 5, 6)
block:
iterator it(): int {.closure.} =
yield 0
try:
yield 1
checkpoint(2)
finally:
checkpoint(3)
yield 4
checkpoint(5)
yield 6
test(it, 0, 1, 2, 3, 4, 5, 6)
block:
iterator it(): int {.closure.} =
yield 0
try:
yield 1
raiseException()
yield 2
finally:
checkpoint(3)
yield 4
checkpoint(5)
yield 6
testExc(it, 0, 1, 3, 4, 5, 6)
block:
iterator it(): int {.closure.} =
try:
try:
raiseException()
except AnotherException:
yield 123
finally:
checkpoint(3)
finally:
checkpoint(4)
testExc(it, 3, 4)
block:
iterator it(): int {.closure.} =
try:
yield 1
raiseException()
except AnotherException:
checkpoint(123)
finally:
checkpoint(2)
checkpoint(3)
testExc(it, 1, 2)
block:
iterator it(): int {.closure.} =
try:
yield 0
try:
yield 1
try:
yield 2
raiseException()
except AnotherException:
yield 123
finally:
yield 3
except AnotherException:
yield 124
finally:
yield 4
checkpoint(1234)
except:
yield 5
checkpoint(6)
finally:
checkpoint(7)
yield 8
checkpoint(9)
test(it, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
block:
iterator it(): int {.closure.} =
try:
yield 0
return 2
finally:
checkpoint(1)
checkpoint(123)
test(it, 0, 1)
block:
iterator it(): int {.closure.} =
try:
try:
yield 0
raiseException()
finally:
checkpoint(1)
except TestException:
yield 2
return
finally:
yield 3
checkpoint(123)
test(it, 0, 1, 2, 3)
block:
iterator it(): int {.closure.} =
try:
try:
yield 0
raiseException()
finally:
return # Return in finally should stop exception propagation
except AnotherException:
yield 2
return
finally:
yield 3
checkpoint(123)
test(it, 0, 3)
block: # Yield in yield
iterator it(): int {.closure.} =
template foo(): int =
yield 1
2
for i in 0 .. 2:
checkpoint(0)
yield foo()
test(it, 0, 1, 2, 0, 1, 2, 0, 1, 2)
block:
iterator it(): int {.closure.} =
let i = if true:
yield 0
1
else:
2
yield i
test(it, 0, 1)
block:
iterator it(): int {.closure.} =
var foo = 123
let i = try:
yield 0
raiseException()
1
except TestException as e:
assert(e.msg == "Test exception!")
case foo
of 1:
yield 123
2
of 123:
yield 5
6
else:
7
yield i
test(it, 0, 5, 6)
block:
iterator it(): int {.closure.} =
proc voidFoo(i1, i2, i3: int) =
checkpoint(i1)
checkpoint(i2)
checkpoint(i3)
proc foo(i1, i2, i3: int): int =
voidFoo(i1, i2, i3)
i3
proc bar(i1: int): int =
checkpoint(i1)
template tryexcept: int =
try:
yield 1
raiseException()
123
except TestException:
yield 2
checkpoint(3)
4
let e1 = true
template ifelse1: int =
if e1:
yield 10
11
else:
12
template ifelse2: int =
if ifelse1() == 12:
yield 20
21
else:
yield 22
23
let i = foo(bar(0), tryexcept, ifelse2)
discard foo(bar(0), tryexcept, ifelse2)
voidFoo(bar(0), tryexcept, ifelse2)
yield i
test(it,
# let i = foo(bar(0), tryexcept, ifelse2)
0, # bar(0)
1, 2, 3, # tryexcept
10, # ifelse1
22, # ifelse22
0, 4, 23, # foo
# discard foo(bar(0), tryexcept, ifelse2)
0, # bar(0)
1, 2, 3, # tryexcept
10, # ifelse1
22, # ifelse22
0, 4, 23, # foo
# voidFoo(bar(0), tryexcept, ifelse2)
0, # bar(0)
1, 2, 3, # tryexcept
10, # ifelse1
22, # ifelse22
0, 4, 23, # foo
23 # i
)
block:
iterator it(): int {.closure.} =
checkpoint(0)
for i in 0 .. 1:
try:
yield 1
raiseException()
except TestException as e:
doAssert(e.msg == "Test exception!")
yield 2
except AnotherException:
yield 123
except:
yield 1234
finally:
yield 3
checkpoint(4)
yield 5
test(it, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
block:
iterator it(): int {.closure.} =
var i = 5
template foo(): bool =
yield i
true
while foo():
dec i
if i == 0:
break
test(it, 5, 4, 3, 2, 1)
block: # Short cirquits
iterator it(): int {.closure.} =
template trueYield: bool =
yield 1
true
template falseYield: bool =
yield 0
false
if trueYield or falseYield:
discard falseYield and trueYield
if falseYield and trueYield:
checkpoint(123)
test(it, 1, 0, 0)
block: #7969
type
SomeObj = object
id: int
iterator it(): int {.closure.} =
template yieldAndSomeObj: SomeObj =
var s: SomeObj
s.id = 2
yield 1
s
checkpoint(yieldAndSomeObj().id)
var i = 5
case i
of 0:
checkpoint(123)
of 1, 2, 5:
checkpoint(3)
else:
checkpoint(123)
test(it, 1, 2, 3)
block: # yield in blockexpr
iterator it(): int {.closure.} =
yield(block:
checkpoint(1)
yield 2
3
)
test(it, 1, 2, 3)
echo "ok"

View File

@@ -1,12 +0,0 @@
discard """
file: "thexlit.nim"
output: "equal"
"""
var t=0x950412DE
if t==0x950412DE:
echo "equal"
else:
echo "not equal"

View File

@@ -1,8 +0,0 @@
type
TArray = array[0x0012..0x0013, int]
var a: TArray
echo a[0x0012] #OUT 0

View File

@@ -0,0 +1,27 @@
discard """
action: run
output: "equal"
"""
var t=0x950412DE
if t==0x950412DE:
echo "equal"
else:
echo "not equal"
type
TArray = array[0x0012..0x0013, int]
var a: TArray
doAssert a[0x0012] == 0
# #7884
type Obj = object
ö: int
let o = Obj(ö: 1)
doAssert o.ö == 1

View File

@@ -42,6 +42,7 @@ Raises
true
true
true
true
'''
"""
# test os path creation, iteration, and deletion
@@ -129,3 +130,12 @@ echo fileExists("../dest/a/b/file.txt")
echo fileExists("../dest/a/b/c/fileC.txt")
removeDir("../dest")
# Test get/set modification times
# Should support at least microsecond resolution
import times
let tm = fromUnix(0) + 100.microseconds
writeFile("a", "")
setLastModificationTime("a", tm)
echo getLastModificationTime("a") == tm
removeFile("a")

View File

@@ -12,6 +12,32 @@ var o: Obj
doAssert fmt"{o}" == "foobar"
doAssert fmt"{o:10}" == "foobar "
# see issue #7933
var str = "abc"
doAssert fmt">7.1 :: {str:>7.1}" == ">7.1 :: a"
doAssert fmt">7.2 :: {str:>7.2}" == ">7.2 :: ab"
doAssert fmt">7.3 :: {str:>7.3}" == ">7.3 :: abc"
doAssert fmt">7.9 :: {str:>7.9}" == ">7.9 :: abc"
doAssert fmt">7.0 :: {str:>7.0}" == ">7.0 :: "
doAssert fmt" 7.1 :: {str:7.1}" == " 7.1 :: a "
doAssert fmt" 7.2 :: {str:7.2}" == " 7.2 :: ab "
doAssert fmt" 7.3 :: {str:7.3}" == " 7.3 :: abc "
doAssert fmt" 7.9 :: {str:7.9}" == " 7.9 :: abc "
doAssert fmt" 7.0 :: {str:7.0}" == " 7.0 :: "
doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 :: a "
doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: ab "
doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: abc "
doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: abc "
doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: "
str = "äöüe\u0309\u0319o\u0307\u0359"
doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 :: ä "
doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: äö "
doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: äöü "
doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: "
# this is actually wrong, but the unicode module has no support for graphemes
doAssert fmt"^7.4 :: {str:^7.4}" == "^7.4 :: äöüe "
doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: äöüe\u0309\u0319o\u0307\u0359"
# see issue #7932
doAssert fmt"{15:08}" == "00000015" # int, works
doAssert fmt"{1.5:08}" == "000001.5" # float, works
@@ -20,3 +46,11 @@ doAssert fmt"{-1.5:0>8}" == "0000-1.5" # even that does not work for negative fl
doAssert fmt"{-1.5:08}" == "-00001.5" # works
doAssert fmt"{1.5:+08}" == "+00001.5" # works
doAssert fmt"{1.5: 08}" == " 00001.5" # works
# only add explicitly requested sign if value != -0.0 (neg zero)
doAssert fmt"{-0.0:g}" == "-0"
doassert fmt"{-0.0:+g}" == "-0"
doassert fmt"{-0.0: g}" == "-0"
doAssert fmt"{0.0:g}" == "0"
doAssert fmt"{0.0:+g}" == "+0"
doAssert fmt"{0.0: g}" == " 0"

View File

@@ -11,6 +11,10 @@ discard """
2
3
4
2
1
2
3
'''
"""
@@ -47,3 +51,38 @@ foo(toOpenArray(arr, 8, 12))
var seqq = @[1, 2, 3, 4, 5]
foo(toOpenArray(seqq, 1, 3))
# empty openArray issue #7904
foo(toOpenArray(seqq, 0, -1))
foo(toOpenArray(seqq, 1, 0))
doAssertRaises(IndexError):
foo(toOpenArray(seqq, 0, -2))
foo(toOpenArray(arr, 9, 8))
foo(toOpenArray(arr, 0, -1))
foo(toOpenArray(arr, 1, 0))
doAssertRaises(IndexError):
foo(toOpenArray(arr, 10, 8))
# test openArray of openArray
proc oaEmpty(a: openArray[int]) =
foo(toOpenArray(a, 0, -1))
proc oaFirstElm(a: openArray[int]) =
foo(toOpenArray(a, 0, 0))
oaEmpty(toOpenArray(seqq, 0, -1))
oaEmpty(toOpenArray(seqq, 1, 0))
oaEmpty(toOpenArray(seqq, 1, 2))
oaFirstElm(toOpenArray(seqq, 1, seqq.len-1))
var arrNeg: array[-3 .. -1, int] = [1, 2, 3]
foo(toOpenArray(arrNeg, -3, -1))
foo(toOpenArray(arrNeg, 0, -1))
foo(toOpenArray(arrNeg, -3, -4))
doAssertRaises(IndexError):
foo(toOpenArray(arrNeg, -4, -1))
doAssertRaises(IndexError):
foo(toOpenArray(arrNeg, -1, 0))
doAssertRaises(IndexError):
foo(toOpenArray(arrNeg, -1, -3))

245
tests/typerel/t4799.nim Normal file
View File

@@ -0,0 +1,245 @@
discard """
output: "OK"
"""
type
GRBase[T] = ref object of RootObj
val: T
GRC[T] = ref object of GRBase[T]
GRD[T] = ref object of GRBase[T]
proc testGR[T](x: varargs[GRBase[T]]): string =
result = ""
for c in x:
result.add $c.val
block test_t4799_1:
var rgv = GRBase[int](val: 3)
var rgc = GRC[int](val: 4)
var rgb = GRD[int](val: 2)
doAssert(testGR(rgb, rgc, rgv) == "243")
doAssert(testGR(rgc, rgv, rgb) == "432")
doAssert(testGR(rgv, rgb, rgc) == "324")
doAssert(testGR([rgb, rgc, rgv]) == "243")
doAssert(testGR([rgc, rgv, rgb]) == "432")
doAssert(testGR([rgv, rgb, rgc]) == "324")
type
PRBase[T] = object of RootObj
val: T
PRC[T] = object of PRBase[T]
PRD[T] = object of PRBase[T]
proc testPR[T](x: varargs[ptr PRBase[T]]): string =
result = ""
for c in x:
result.add $c.val
block test_t4799_2:
var pgv = PRBase[int](val: 3)
var pgc = PRC[int](val: 4)
var pgb = PRD[int](val: 2)
doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243")
doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432")
doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324")
doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243")
doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432")
doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324")
type
RBase = ref object of RootObj
val: int
RC = ref object of RBase
RD = ref object of RBase
proc testR(x: varargs[RBase]): string =
result = ""
for c in x:
result.add $c.val
block test_t4799_3:
var rv = RBase(val: 3)
var rc = RC(val: 4)
var rb = RD(val: 2)
doAssert(testR(rb, rc, rv) == "243")
doAssert(testR(rc, rv, rb) == "432")
doAssert(testR(rv, rb, rc) == "324")
doAssert(testR([rb, rc, rv]) == "243")
doAssert(testR([rc, rv, rb]) == "432")
doAssert(testR([rv, rb, rc]) == "324")
type
PBase = object of RootObj
val: int
PC = object of PBase
PD = object of PBase
proc testP(x: varargs[ptr PBase]): string =
result = ""
for c in x:
result.add $c.val
block test_t4799_4:
var pv = PBase(val: 3)
var pc = PC(val: 4)
var pb = PD(val: 2)
doAssert(testP(pb.addr, pc.addr, pv.addr) == "243")
doAssert(testP(pc.addr, pv.addr, pb.addr) == "432")
doAssert(testP(pv.addr, pb.addr, pc.addr) == "324")
doAssert(testP([pb.addr, pc.addr, pv.addr]) == "243")
doAssert(testP([pc.addr, pv.addr, pb.addr]) == "432")
doAssert(testP([pv.addr, pb.addr, pc.addr]) == "324")
type
PSBase[T, V] = ref object of RootObj
val: T
color: V
PSRC[T] = ref object of PSBase[T, int]
PSRD[T] = ref object of PSBase[T, int]
proc testPS[T, V](x: varargs[PSBase[T, V]]): string =
result = ""
for c in x:
result.add c.val
result.add $c.color
block test_t4799_5:
var a = PSBase[string, int](val: "base", color: 1)
var b = PSRC[string](val: "rc", color: 2)
var c = PSRD[string](val: "rd", color: 3)
doAssert(testPS(a, b, c) == "base1rc2rd3")
doAssert(testPS(b, a, c) == "rc2base1rd3")
doAssert(testPS(c, b, a) == "rd3rc2base1")
doAssert(testPS([a, b, c]) == "base1rc2rd3")
doAssert(testPS([b, a, c]) == "rc2base1rd3")
doAssert(testPS([c, b, a]) == "rd3rc2base1")
type
SBase[T, V] = ref object of RootObj
val: T
color: V
SRC = ref object of SBase[string, int]
SRD = ref object of SBase[string, int]
proc testS[T, V](x: varargs[SBase[T, V]]): string =
result = ""
for c in x:
result.add c.val
result.add $c.color
block test_t4799_6:
var a = SBase[string, int](val: "base", color: 1)
var b = SRC(val: "rc", color: 2)
var c = SRD(val: "rd", color: 3)
doAssert(testS(a, b, c) == "base1rc2rd3")
doAssert(testS(b, a, c) == "rc2base1rd3")
doAssert(testS(c, b, a) == "rd3rc2base1")
doAssert(testS([a, b, c]) == "base1rc2rd3")
# this is not varargs bug, but array construction bug
# see #7955
#doAssert(testS([b, c, a]) == "rc2rd3base1")
#doAssert(testS([c, b, a]) == "rd3rc2base1")
proc test_inproc() =
block test_inproc_1:
var rgv = GRBase[int](val: 3)
var rgc = GRC[int](val: 4)
var rgb = GRD[int](val: 2)
doAssert(testGR(rgb, rgc, rgv) == "243")
doAssert(testGR(rgc, rgv, rgb) == "432")
doAssert(testGR(rgv, rgb, rgc) == "324")
doAssert(testGR([rgb, rgc, rgv]) == "243")
doAssert(testGR([rgc, rgv, rgb]) == "432")
doAssert(testGR([rgv, rgb, rgc]) == "324")
block test_inproc_2:
var pgv = PRBase[int](val: 3)
var pgc = PRC[int](val: 4)
var pgb = PRD[int](val: 2)
doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243")
doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432")
doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324")
doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243")
doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432")
doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324")
test_inproc()
template reject(x) =
static: assert(not compiles(x))
block test_t4799_7:
type
Vehicle[T] = ref object of RootObj
tire: T
Car[T] = object of Vehicle[T]
Bike[T] = object of Vehicle[T]
proc testVehicle[T](x: varargs[Vehicle[T]]): string {.used.} =
result = ""
for c in x:
result.add $c.tire
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)
reject:
echo testVehicle(b, c, v)
block test_t4799_8:
type
Vehicle = ref object of RootObj
tire: int
Car = object of Vehicle
Bike = object of Vehicle
proc testVehicle(x: varargs[Vehicle]): string {.used.} =
result = ""
for c in x:
result.add $c.tire
var v = Vehicle(tire: 3)
var c = Car(tire: 4)
var b = Bike(tire: 2)
reject:
echo testVehicle(b, c, v)
type
PGVehicle[T] = ptr object of RootObj
tire: T
PGCar[T] = object of PGVehicle[T]
PGBike[T] = object of PGVehicle[T]
proc testVehicle[T](x: varargs[PGVehicle[T]]): string {.used.} =
result = ""
for c in x:
result.add $c.tire
var pgc = PGCar[int](tire: 4)
var pgb = PGBike[int](tire: 2)
reject:
echo testVehicle(pgb, pgc)
type
RVehicle = ptr object of RootObj
tire: int
RCar = object of RVehicle
RBike = object of RVehicle
proc testVehicle(x: varargs[RVehicle]): string {.used.} =
result = ""
for c in x:
result.add $c.tire
var rc = RCar(tire: 4)
var rb = RBike(tire: 2)
reject:
echo testVehicle(rb, rc)
echo "OK"

20
tests/typerel/t4799_1.nim Normal file
View File

@@ -0,0 +1,20 @@
discard """
outputsub: '''ObjectAssignmentError'''
exitcode: "1"
"""
type
Vehicle[T] = object of RootObj
tire: T
Car[T] = object of Vehicle[T]
Bike[T] = object of Vehicle[T]
proc testVehicle[T](x: varargs[Vehicle[T]]): string =
result = ""
for c in x:
result.add $c.tire
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)
echo testVehicle b, c, v

20
tests/typerel/t4799_2.nim Normal file
View File

@@ -0,0 +1,20 @@
discard """
outputsub: '''ObjectAssignmentError'''
exitcode: "1"
"""
type
Vehicle[T] = object of RootObj
tire: T
Car[T] = object of Vehicle[T]
Bike[T] = object of Vehicle[T]
proc testVehicle[T](x: varargs[Vehicle[T]]): string =
result = ""
for c in x:
result.add $c.tire
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)
echo testVehicle([b, c, v])

20
tests/typerel/t4799_3.nim Normal file
View File

@@ -0,0 +1,20 @@
discard """
outputsub: '''ObjectAssignmentError'''
exitcode: "1"
"""
type
Vehicle = object of RootObj
tire: int
Car = object of Vehicle
Bike = object of Vehicle
proc testVehicle(x: varargs[Vehicle]): string =
result = ""
for c in x:
result.add $c.tire
var v = Vehicle(tire: 3)
var c = Car(tire: 4)
var b = Bike(tire: 2)
echo testVehicle([b, c, v])

View File

@@ -82,3 +82,11 @@ block:
assert fileExists("MISSINGFILE") == false
assert dirExists("MISSINGDIR") == false
# #7210
block:
static:
proc f(size: int): int =
var some = newStringOfCap(size)
result = size
doAssert f(4) == 4