mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-03 04:13:40 +00:00
fixex merge conflicts
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
1306
compiler/closureiters.nim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -118,7 +118,8 @@ type
|
||||
callOperator,
|
||||
parallel,
|
||||
destructor,
|
||||
notnil
|
||||
notnil,
|
||||
oldIterTransf
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||
|
||||
@@ -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.}")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
##
|
||||
|
||||
@@ -130,7 +130,7 @@ proc nimNumber(g: var GeneralTokenizer, position: int): int =
|
||||
|
||||
const
|
||||
OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
|
||||
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
|
||||
'|', '=', '%', '&', '$', '@', '~', ':'}
|
||||
|
||||
proc nimNextToken(g: var GeneralTokenizer) =
|
||||
const
|
||||
|
||||
@@ -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>".}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
19
tests/async/t7985.nim
Normal 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())
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.} =
|
||||
|
||||
@@ -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
407
tests/iter/tyieldintry.nim
Normal 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"
|
||||
@@ -1,12 +0,0 @@
|
||||
discard """
|
||||
file: "thexlit.nim"
|
||||
output: "equal"
|
||||
"""
|
||||
|
||||
var t=0x950412DE
|
||||
|
||||
if t==0x950412DE:
|
||||
echo "equal"
|
||||
else:
|
||||
echo "not equal"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
type
|
||||
TArray = array[0x0012..0x0013, int]
|
||||
|
||||
var a: TArray
|
||||
|
||||
echo a[0x0012] #OUT 0
|
||||
|
||||
27
tests/lexer/tlexermisc.nim
Normal file
27
tests/lexer/tlexermisc.nim
Normal 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
|
||||
@@ -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")
|
||||
@@ -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"
|
||||
|
||||
@@ -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
245
tests/typerel/t4799.nim
Normal 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
20
tests/typerel/t4799_1.nim
Normal 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
20
tests/typerel/t4799_2.nim
Normal 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
20
tests/typerel/t4799_3.nim
Normal 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])
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user