mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dde13f38c9 | ||
|
|
fabbb7ea3e | ||
|
|
76971596ad | ||
|
|
d777a8f86c | ||
|
|
00cd7b8ca4 | ||
|
|
714fd81199 | ||
|
|
59b5bdc2c6 | ||
|
|
4642a3485c | ||
|
|
58d711ec57 | ||
|
|
8f3f264160 | ||
|
|
2ce9352285 | ||
|
|
825f358c8b | ||
|
|
17bed3c966 | ||
|
|
eb51fa5ead | ||
|
|
dc1c251a2c | ||
|
|
d6c8a91b72 | ||
|
|
991902e286 | ||
|
|
5534c56d05 | ||
|
|
777c28cf45 | ||
|
|
3f0432bf8d | ||
|
|
bc42ec515e | ||
|
|
60783ccc11 | ||
|
|
9599d95caa | ||
|
|
e3c85f5885 | ||
|
|
da03b5ca8b | ||
|
|
736e1dd0a0 | ||
|
|
c6d51805be | ||
|
|
c53c6458b0 | ||
|
|
eefb13d638 | ||
|
|
7ef706fef9 | ||
|
|
4827bf5e88 | ||
|
|
2624de0588 | ||
|
|
183f876bd1 | ||
|
|
6eb656a75b | ||
|
|
0e457ae92c | ||
|
|
5254e0693e | ||
|
|
abe72ba1b3 | ||
|
|
e980256794 | ||
|
|
7bba0deb1d | ||
|
|
0845e88110 | ||
|
|
040ac6cd2b | ||
|
|
1c8ed1de0e | ||
|
|
b5c90a3431 | ||
|
|
53f3bd9376 | ||
|
|
ae688aa7f5 | ||
|
|
4e428c5a18 | ||
|
|
dc3f74f1c2 | ||
|
|
98e73512d1 | ||
|
|
a41ece8d86 | ||
|
|
67d729aa2e | ||
|
|
0ddf7153b8 | ||
|
|
0aec43e850 | ||
|
|
f94a3fa671 |
@@ -51,9 +51,10 @@ jobs:
|
||||
condition: eq(variables['Agent.OS'], 'Windows_NT')
|
||||
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
displayName: 'Checkout csources'
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources
|
||||
displayName: 'Checkout Nim csources'
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
@@ -71,19 +72,12 @@ jobs:
|
||||
- bash: |
|
||||
sudo dpkg --add-architecture i386
|
||||
|
||||
# Downgrade llvm, libgcc and libstdc++:
|
||||
# Downgrade llvm:
|
||||
# - llvm has to be downgraded to have 32bit version installed for sfml.
|
||||
# - libgcc and libstdc++ have to be downgraded as an optimization to
|
||||
# prevent the use of the toolchain ppa, which has a terrible download
|
||||
# speed.
|
||||
cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel
|
||||
Package: libllvm6.0 libgcc1 libstdc++6
|
||||
Package: libllvm6.0
|
||||
Pin: origin "azure.archive.ubuntu.com"
|
||||
Pin-Priority: 1001
|
||||
|
||||
Package: *
|
||||
Pin: release o=LP-PPA-ubuntu-toolchain-r-test
|
||||
Pin-Priority: 100
|
||||
EOF
|
||||
|
||||
sudo apt-fast update -qq
|
||||
@@ -139,8 +133,18 @@ jobs:
|
||||
make -v
|
||||
displayName: 'System information'
|
||||
|
||||
- bash: echo '##vso[task.setvariable variable=csources_version]'"$(git -C csources rev-parse HEAD)"
|
||||
displayName: 'Get csources version'
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: 'csources | "$(Agent.OS)" | $(CPU) | $(csources_version)'
|
||||
path: csources/bin
|
||||
displayName: 'Restore built csources'
|
||||
|
||||
- bash: |
|
||||
ncpu=
|
||||
ext=
|
||||
case '$(Agent.OS)' in
|
||||
'Linux')
|
||||
ncpu=$(nproc)
|
||||
@@ -150,19 +154,25 @@ jobs:
|
||||
;;
|
||||
'Windows_NT')
|
||||
ncpu=$NUMBER_OF_PROCESSORS
|
||||
ext=.exe
|
||||
;;
|
||||
esac
|
||||
[[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1
|
||||
|
||||
make -C csources -j $ncpu CC=gcc ucpu=$(CPU)
|
||||
displayName: 'Build csources'
|
||||
if [[ -x csources/bin/nim$ext ]]; then
|
||||
echo "Found cached compiler, skipping build"
|
||||
else
|
||||
make -C csources -j $ncpu CC=gcc ucpu=$(CPU) koch=no
|
||||
fi
|
||||
|
||||
cp csources/bin/nim$ext bin
|
||||
displayName: 'Build 1-stage compiler from csources'
|
||||
|
||||
- bash: nim c koch
|
||||
displayName: 'Build koch'
|
||||
|
||||
# set result to omit the "bash exited with error code '1'" message
|
||||
- bash: |
|
||||
./koch runCI || echo '##vso[task.complete result=Failed]'
|
||||
- bash: ./koch runCI || echo '##vso[task.complete result=Failed]'
|
||||
displayName: 'Run CI'
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
|
||||
13
changelog.md
13
changelog.md
@@ -129,6 +129,19 @@
|
||||
|
||||
## Language changes
|
||||
- In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this:
|
||||
|
||||
- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts
|
||||
`wasMoved` calls where needed.
|
||||
- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there
|
||||
is no need to update your code. This change was backported to 1.2 too so you can use the
|
||||
more readability `=copy` without loss of compatibility.
|
||||
|
||||
- In the newruntime it is now allowed to assign to the discriminator field
|
||||
without restrictions as long as case object doesn't have custom destructor.
|
||||
The discriminator value doesn't have to be a constant either. If you have a
|
||||
custom destructor for a case object and you do want to freely assign discriminator
|
||||
fields, it is recommended to refactor object into 2 objects like this:
|
||||
|
||||
```nim
|
||||
type
|
||||
MyObj = object
|
||||
|
||||
@@ -1327,7 +1327,7 @@ const
|
||||
MaxLockLevel* = 1000'i16
|
||||
UnknownLockLevel* = TLockLevel(1001'i16)
|
||||
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
|
||||
"=destroy", "=", "=sink", "=trace", "=dispose", "=deepcopy"]
|
||||
"=destroy", "=copy", "=sink", "=trace", "=dispose", "=deepcopy"]
|
||||
|
||||
proc `$`*(x: TLockLevel): string =
|
||||
if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
|
||||
|
||||
@@ -1781,9 +1781,9 @@ template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
|
||||
|
||||
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
|
||||
case int(getSize(p.config, skipTypes(e[1].typ, abstractVar)))
|
||||
of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)")
|
||||
of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)")
|
||||
of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)")
|
||||
of 1: binaryExprIn(p, e, a, b, d, "(($1 &((NU8)1<<((NU)($2)&7U)))!=0)")
|
||||
of 2: binaryExprIn(p, e, a, b, d, "(($1 &((NU16)1<<((NU)($2)&15U)))!=0)")
|
||||
of 4: binaryExprIn(p, e, a, b, d, "(($1 &((NU32)1<<((NU)($2)&31U)))!=0)")
|
||||
of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)")
|
||||
else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)")
|
||||
|
||||
@@ -1981,25 +1981,30 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
|
||||
checkUnsignedConversions notin p.config.legacyFeatures):
|
||||
discard "no need to generate a check because it was disabled"
|
||||
else:
|
||||
let raiser =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
|
||||
of tyFloat..tyFloat128: "raiseRangeErrorF"
|
||||
else: "raiseRangeErrorI"
|
||||
discard cgsym(p.module, raiser)
|
||||
# This seems to be bug-compatible with Nim version 1 but what we
|
||||
# should really do here is to check if uint64Value < high(int)
|
||||
let n0t = n[0].typ
|
||||
let boundaryCast =
|
||||
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
|
||||
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
|
||||
"(NI64)"
|
||||
else:
|
||||
""
|
||||
|
||||
# emit range check:
|
||||
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), boundaryCast])
|
||||
if n0t.kind in {tyUInt, tyUInt64}:
|
||||
linefmt(p, cpsStmts, "if ($1 > ($6)($3)){ #raiseRangeErrorNoArgs(); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), getTypeDesc(p.module, n0t)])
|
||||
else:
|
||||
let raiser =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
|
||||
of tyFloat..tyFloat128: "raiseRangeErrorF"
|
||||
else: "raiseRangeErrorI"
|
||||
discard cgsym(p.module, raiser)
|
||||
|
||||
let boundaryCast =
|
||||
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
|
||||
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
|
||||
"(NI64)"
|
||||
else:
|
||||
""
|
||||
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), boundaryCast])
|
||||
putIntoDest(p, d, n, "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
|
||||
|
||||
@@ -2665,9 +2670,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
expr(p, n[1][0], d)
|
||||
of nkObjDownConv: downConv(p, n, d)
|
||||
of nkObjUpConv: upConv(p, n, d)
|
||||
of nkChckRangeF: genRangeChck(p, n, d)
|
||||
of nkChckRange64: genRangeChck(p, n, d)
|
||||
of nkChckRange: genRangeChck(p, n, d)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d)
|
||||
of nkStringToCString: convStrToCStr(p, n, d)
|
||||
of nkCStringToString: convCStrToStr(p, n, d)
|
||||
of nkLambdaKinds:
|
||||
@@ -2941,7 +2944,23 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
|
||||
proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope =
|
||||
case n.kind
|
||||
of nkHiddenStdConv, nkHiddenSubConv:
|
||||
result = genBracedInit(p, n[1], isConst)
|
||||
when false:
|
||||
# XXX The frontend doesn't keep conversions to openArray for us. :-(
|
||||
# We need to change 'transformConv' first, but that is hard.
|
||||
if n.typ.kind == tyOpenArray:
|
||||
assert n[1].kind == nkBracket
|
||||
let data = genBracedInit(p, n[1], isConst)
|
||||
|
||||
let payload = getTempName(p.module)
|
||||
let ctype = getTypeDesc(p.module, n.typ.skipTypes(abstractInst)[0])
|
||||
let arrLen = n[1].len
|
||||
appcg(p.module, cfsData,
|
||||
"static $5 $1 $3[$2] = $4;$n", [
|
||||
ctype, arrLen, payload, data,
|
||||
if isConst: "const" else: ""])
|
||||
result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen]
|
||||
else:
|
||||
result = genBracedInit(p, n[1], isConst)
|
||||
else:
|
||||
var ty = tyNone
|
||||
if n.typ == nil:
|
||||
|
||||
@@ -130,7 +130,8 @@
|
||||
|
||||
import
|
||||
ast, msgs, idents,
|
||||
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
|
||||
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos,
|
||||
tables, options
|
||||
|
||||
type
|
||||
Ctx = object
|
||||
@@ -1102,7 +1103,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
|
||||
|
||||
result = ctx.states[stateIdx][0].intVal.int
|
||||
|
||||
proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode =
|
||||
proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
|
||||
result = n
|
||||
case n.kind
|
||||
of nkSkip:
|
||||
@@ -1282,6 +1283,101 @@ proc deleteEmptyStates(ctx: var Ctx) =
|
||||
else:
|
||||
inc i
|
||||
|
||||
type
|
||||
PreprocessContext = object
|
||||
finallys: seq[PNode]
|
||||
config: ConfigRef
|
||||
blocks: seq[(PNode, int)]
|
||||
FreshVarsContext = object
|
||||
tab: Table[int, PSym]
|
||||
config: ConfigRef
|
||||
info: TLineInfo
|
||||
|
||||
proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
let x = c.tab.getOrDefault(n.sym.id)
|
||||
if x == nil:
|
||||
result = n
|
||||
else:
|
||||
result = newSymNode(x, n.info)
|
||||
of nkSkip - {nkSym}:
|
||||
result = n
|
||||
of nkLetSection, nkVarSection:
|
||||
result = copyNode(n)
|
||||
for it in n:
|
||||
if it.kind in {nkIdentDefs, nkVarTuple}:
|
||||
let idefs = copyNode(it)
|
||||
for v in 0..it.len-3:
|
||||
if it[v].kind == nkSym:
|
||||
let x = copySym(it[v].sym)
|
||||
c.tab[it[v].sym.id] = x
|
||||
idefs.add newSymNode(x)
|
||||
else:
|
||||
idefs.add it[v]
|
||||
|
||||
for rest in it.len-2 ..< it.len: idefs.add it[rest]
|
||||
result.add idefs
|
||||
else:
|
||||
result.add it
|
||||
of nkRaiseStmt:
|
||||
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
|
||||
else:
|
||||
result = n
|
||||
for i in 0..<n.safeLen:
|
||||
result[i] = freshVars(n[i], c)
|
||||
|
||||
proc preprocess(c: var PreprocessContext; n: PNode): PNode =
|
||||
# in order to fix bug #15243 without risking regressions, we preprocess
|
||||
# the AST so that 'break' statements inside a 'try finally' also have the
|
||||
# finally section. We need to duplicate local variables here and also
|
||||
# detect: 'finally: raises X' which is currently not supported. We produce
|
||||
# an error for this case for now. All this will be done properly with Yuriy's
|
||||
# patch.
|
||||
result = n
|
||||
case n.kind
|
||||
of nkTryStmt:
|
||||
let f = n.lastSon
|
||||
if f.kind == nkFinally:
|
||||
c.finallys.add f.lastSon
|
||||
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = preprocess(c, n[i])
|
||||
|
||||
if f.kind == nkFinally:
|
||||
discard c.finallys.pop()
|
||||
|
||||
of nkWhileStmt, nkBlockStmt:
|
||||
c.blocks.add((n, c.finallys.len))
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = preprocess(c, n[i])
|
||||
discard c.blocks.pop()
|
||||
|
||||
of nkBreakStmt:
|
||||
if c.blocks.len == 0:
|
||||
discard
|
||||
else:
|
||||
var fin = -1
|
||||
if n[0].kind == nkEmpty:
|
||||
fin = c.blocks[^1][1]
|
||||
elif n[0].kind == nkSym:
|
||||
for i in countdown(c.blocks.high, 0):
|
||||
if c.blocks[i][0].kind == nkBlockStmt and c.blocks[i][0][0].kind == nkSym and
|
||||
c.blocks[i][0][0].sym == n[0].sym:
|
||||
fin = c.blocks[i][1]
|
||||
break
|
||||
|
||||
if fin >= 0:
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
for i in countdown(c.finallys.high, fin):
|
||||
var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info)
|
||||
result.add freshVars(preprocess(c, c.finallys[i]), vars)
|
||||
result.add n
|
||||
of nkSkip: discard
|
||||
else:
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = preprocess(c, n[i])
|
||||
|
||||
proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
|
||||
var ctx: Ctx
|
||||
ctx.g = g
|
||||
@@ -1294,7 +1390,10 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
|
||||
ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
|
||||
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
|
||||
var n = n.toStmtList
|
||||
var pc = PreprocessContext(finallys: @[], config: g.config)
|
||||
var n = preprocess(pc, n.toStmtList)
|
||||
#echo "transformed into ", n
|
||||
#var n = n.toStmtList
|
||||
|
||||
discard ctx.newState(n, nil)
|
||||
let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
|
||||
|
||||
@@ -116,3 +116,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimNewIntegerOps")
|
||||
defineSymbol("nimHasInvariant")
|
||||
defineSymbol("nimHasStacktraceMsgs")
|
||||
defineSymbol("nimHasStacktracesModule")
|
||||
|
||||
@@ -212,7 +212,7 @@ template isUnpackedTuple(n: PNode): bool =
|
||||
|
||||
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
|
||||
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
|
||||
if opname == "=" and ri != nil:
|
||||
if (opname == "=" or opname == "=copy") and ri != nil:
|
||||
m.add "; requires a copy because it's not the last read of '"
|
||||
m.add renderTree(ri)
|
||||
m.add '\''
|
||||
@@ -301,7 +301,7 @@ proc genCopy(c: var Con; dest, ri: PNode): PNode =
|
||||
if tfHasOwned in t.flags and ri.kind != nkNilLit:
|
||||
# try to improve the error message here:
|
||||
if c.otherRead == nil: discard isLastRead(ri, c)
|
||||
checkForErrorPragma(c, t, ri, "=")
|
||||
checkForErrorPragma(c, t, ri, "=copy")
|
||||
result = genCopyNoCheck(c, dest, ri)
|
||||
|
||||
proc addTopVar(c: var Con; v: PNode) =
|
||||
|
||||
@@ -77,6 +77,7 @@ Files: "lib"
|
||||
[Other]
|
||||
Files: "examples"
|
||||
Files: "dist/nimble"
|
||||
Files: "dist/fusion"
|
||||
|
||||
Files: "tests"
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ type
|
||||
tkComma, tkSemiColon,
|
||||
tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon,
|
||||
tkOpr, tkComment, tkAccent,
|
||||
# these are fake tokens used by renderer.nim
|
||||
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
|
||||
|
||||
TTokTypes* = set[TTokType]
|
||||
|
||||
@@ -19,5 +19,6 @@ define:useStdoutAsStdmsg
|
||||
styleCheck:error
|
||||
@end
|
||||
|
||||
|
||||
#define:useNodeIds
|
||||
#gc:markAndSweep
|
||||
|
||||
@@ -31,6 +31,7 @@ type
|
||||
TSrcGen* = object
|
||||
indent*: int
|
||||
lineLen*: int
|
||||
col: int
|
||||
pos*: int # current position for iteration over the buffer
|
||||
idx*: int # current token index for iteration over the buffer
|
||||
tokens*: TRenderTokSeq
|
||||
@@ -109,11 +110,10 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
|
||||
g.config = config
|
||||
|
||||
proc addTok(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
|
||||
setLen(g.tokens, g.tokens.len + 1)
|
||||
g.tokens[^1].kind = kind
|
||||
g.tokens[^1].length = int16(s.len)
|
||||
g.tokens[^1].sym = sym
|
||||
g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym)
|
||||
g.buf.add(s)
|
||||
if kind != tkSpaces:
|
||||
inc g.col, s.len
|
||||
|
||||
proc addPendingNL(g: var TSrcGen) =
|
||||
if g.pendingNL >= 0:
|
||||
@@ -123,6 +123,7 @@ proc addPendingNL(g: var TSrcGen) =
|
||||
const newlines = "\n"
|
||||
addTok(g, tkSpaces, newlines & spaces(g.pendingNL))
|
||||
g.lineLen = g.pendingNL
|
||||
g.col = g.pendingNL
|
||||
g.pendingNL = - 1
|
||||
g.pendingWhitespace = -1
|
||||
elif g.pendingWhitespace >= 0:
|
||||
@@ -131,7 +132,10 @@ proc addPendingNL(g: var TSrcGen) =
|
||||
|
||||
proc putNL(g: var TSrcGen, indent: int) =
|
||||
if g.pendingNL >= 0: addPendingNL(g)
|
||||
else: addTok(g, tkSpaces, "\n")
|
||||
else:
|
||||
addTok(g, tkSpaces, "\n")
|
||||
g.col = 0
|
||||
|
||||
g.pendingNL = indent
|
||||
g.lineLen = indent
|
||||
g.pendingWhitespace = -1
|
||||
@@ -173,16 +177,17 @@ proc put(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
|
||||
addPendingNL(g)
|
||||
if s.len > 0:
|
||||
addTok(g, kind, s, sym)
|
||||
inc(g.lineLen, s.len)
|
||||
else:
|
||||
g.pendingWhitespace = s.len
|
||||
inc g.col, s.len
|
||||
inc(g.lineLen, s.len)
|
||||
|
||||
proc putComment(g: var TSrcGen, s: string) =
|
||||
if s.len == 0: return
|
||||
var i = 0
|
||||
let hi = s.len - 1
|
||||
var isCode = (s.len >= 2) and (s[1] != ' ')
|
||||
var ind = g.lineLen
|
||||
let isCode = (s.len >= 2) and (s[1] != ' ')
|
||||
let ind = g.col
|
||||
var com = "## "
|
||||
while i <= hi:
|
||||
case s[i]
|
||||
@@ -208,7 +213,7 @@ proc putComment(g: var TSrcGen, s: string) =
|
||||
# compute length of the following word:
|
||||
var j = i
|
||||
while j <= hi and s[j] > ' ': inc(j)
|
||||
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
||||
if not isCode and (g.col + (j - i) > MaxLineLen):
|
||||
put(g, tkComment, com)
|
||||
optNL(g, ind)
|
||||
com = "## "
|
||||
@@ -290,15 +295,18 @@ proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
|
||||
proc gcom(g: var TSrcGen, n: PNode) =
|
||||
assert(n != nil)
|
||||
if shouldRenderComment(g, n):
|
||||
var oneSpaceAdded = 0
|
||||
if (g.pendingNL < 0) and (g.buf.len > 0) and (g.buf[^1] != ' '):
|
||||
put(g, tkSpaces, Space)
|
||||
oneSpaceAdded = 1
|
||||
# Before long comments we cannot make sure that a newline is generated,
|
||||
# because this might be wrong. But it is no problem in practice.
|
||||
if (g.pendingNL < 0) and (g.buf.len > 0) and
|
||||
(g.lineLen < LineCommentColumn):
|
||||
(g.col < LineCommentColumn):
|
||||
var ml = maxLineLength(n.comment)
|
||||
if ml + LineCommentColumn <= MaxLineLen:
|
||||
put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
|
||||
put(g, tkSpaces, spaces(LineCommentColumn - g.col))
|
||||
dec g.col, oneSpaceAdded
|
||||
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
|
||||
|
||||
proc gcoms(g: var TSrcGen) =
|
||||
|
||||
@@ -23,7 +23,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
result = newNode(nkEmpty)
|
||||
return
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
|
||||
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = copyNode(n)
|
||||
of nkIdent, nkSym:
|
||||
result = n
|
||||
let ident = considerQuotedIdent(c.c, n)
|
||||
@@ -52,8 +52,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
if n.kind == nkContinueStmt:
|
||||
localError(c.c.config, n.info,
|
||||
"'continue' not supported in a 'fields' loop")
|
||||
result = copyNode(n)
|
||||
newSons(result, n.len)
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = instFieldLoopBody(c, n[i], forLoop)
|
||||
|
||||
|
||||
@@ -785,7 +785,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
|
||||
tracked.owner.flags.incl sfInjectDestructors
|
||||
# bug #15038: ensure consistency
|
||||
if not hasDestructor(n.typ): n.typ = n.sym.typ
|
||||
if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
|
||||
of nkRaiseStmt:
|
||||
if n[0].kind != nkEmpty:
|
||||
n[0].info = n.info
|
||||
|
||||
@@ -161,7 +161,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
if it.len == 2:
|
||||
openScope(c)
|
||||
it[0] = forceBool(c, semExprWithType(c, it[0]))
|
||||
it[1] = semExprBranch(c, it[1])
|
||||
it[1] = semExprBranch(c, it[1], flags)
|
||||
typ = commonType(typ, it[1])
|
||||
closeScope(c)
|
||||
elif it.len == 1:
|
||||
@@ -722,7 +722,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
result = n
|
||||
let iterBase = n[^2].typ
|
||||
var iter = skipTypes(iterBase, {tyGenericInst, tyAlias, tySink, tyOwned})
|
||||
var iterAfterVarLent = iter.skipTypes({tyLent, tyVar})
|
||||
var iterAfterVarLent = iter.skipTypes({tyGenericInst, tyAlias, tyLent, tyVar})
|
||||
# n.len == 3 means that there is one for loop variable
|
||||
# and thus no tuple unpacking:
|
||||
if iterAfterVarLent.kind != tyTuple or n.len == 3:
|
||||
@@ -1748,7 +1748,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
|
||||
incl(s.flags, sfUsed)
|
||||
incl(s.flags, sfOverriden)
|
||||
of "=", "=sink":
|
||||
of "=", "=copy", "=sink":
|
||||
if s.magic == mAsgn: return
|
||||
incl(s.flags, sfUsed)
|
||||
incl(s.flags, sfOverriden)
|
||||
@@ -1770,7 +1770,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
# attach these ops to the canonical tySequence
|
||||
obj = canonType(c, obj)
|
||||
#echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj)
|
||||
let k = if name == "=": attachedAsgn else: attachedSink
|
||||
let k = if name == "=" or name == "=copy": attachedAsgn else: attachedSink
|
||||
if obj.attachedOps[k] == s:
|
||||
discard "forward declared op"
|
||||
elif obj.attachedOps[k].isNil and tfCheckedForDestructor notin obj.flags:
|
||||
|
||||
@@ -1086,7 +1086,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||
if x == isNone: return isNone
|
||||
if x < result: result = x
|
||||
return
|
||||
return result
|
||||
|
||||
of tyAnd:
|
||||
# XXX: deal with the current dual meaning of tyGenericParam
|
||||
@@ -1421,7 +1421,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
let ff = rootf[i]
|
||||
let aa = roota[i]
|
||||
let res = typeRel(c, ff, aa, nextFlags)
|
||||
if res != isEqual: result = isGeneric
|
||||
if res != isNone and res != isEqual: result = isGeneric
|
||||
if res notin {isEqual, isGeneric}:
|
||||
if trNoCovariance notin flags and ff.kind == aa.kind:
|
||||
let paramFlags = rootf.base[i-1].flags
|
||||
|
||||
@@ -138,12 +138,13 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a
|
||||
accum.offset = szUnknownSize
|
||||
accum.maxAlign = szUnknownSize
|
||||
else:
|
||||
# the union neds to be aligned first, before the offsets can be assigned
|
||||
# the union needs to be aligned first, before the offsets can be assigned
|
||||
accum.align(maxChildAlign)
|
||||
let accumRoot = accum # copy, because each branch should start af the same offset
|
||||
for i in 1..<n.len:
|
||||
var branchAccum = accumRoot
|
||||
var branchAccum = OffsetAccum(offset: accumRoot.offset, maxAlign: 1)
|
||||
computeObjectOffsetsFoldFunction(conf, n[i].lastSon, packed, branchAccum)
|
||||
discard finish(branchAccum)
|
||||
accum.mergeBranch(branchAccum)
|
||||
of nkRecList:
|
||||
for i, child in n.sons:
|
||||
@@ -173,9 +174,10 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var
|
||||
localError(conf, n.info, "Illegal use of ``case`` in union type.")
|
||||
of nkRecList:
|
||||
let accumRoot = accum # copy, because each branch should start af the same offset
|
||||
for i, child in n.sons:
|
||||
var branchAccum = accumRoot
|
||||
for child in n.sons:
|
||||
var branchAccum = OffsetAccum(offset: accumRoot.offset, maxAlign: 1)
|
||||
computeUnionObjectOffsetsFoldFunction(conf, child, branchAccum)
|
||||
discard finish(branchAccum)
|
||||
accum.mergeBranch(branchAccum)
|
||||
of nkSym:
|
||||
var size = szUnknownSize
|
||||
|
||||
@@ -830,13 +830,6 @@ proc transformExceptBranch(c: PTransf, n: PNode): PNode =
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
|
||||
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
||||
# symbols that expand to a complex constant (array, etc.) should not be
|
||||
# inlined, unless it's the empty array:
|
||||
result = orig.kind == nkSym and
|
||||
cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
|
||||
cnst.len != 0
|
||||
|
||||
proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
|
||||
result = n
|
||||
for i in 0..<n.safeLen:
|
||||
@@ -1090,15 +1083,15 @@ proc liftDeferAux(n: PNode) =
|
||||
if n[i].kind == nkDefer:
|
||||
let deferPart = newNodeI(nkFinally, n[i].info)
|
||||
deferPart.add n[i][0]
|
||||
var tryStmt = newNodeI(nkTryStmt, n[i].info)
|
||||
var body = newNodeI(n.kind, n[i].info)
|
||||
var tryStmt = newNodeIT(nkTryStmt, n[i].info, n.typ)
|
||||
var body = newNodeIT(n.kind, n[i].info, n.typ)
|
||||
if i < last:
|
||||
body.sons = n.sons[(i+1)..last]
|
||||
tryStmt.add body
|
||||
tryStmt.add deferPart
|
||||
n[i] = tryStmt
|
||||
n.sons.setLen(i+1)
|
||||
n.typ = n[i].typ
|
||||
n.typ = tryStmt.typ
|
||||
goOn = true
|
||||
break
|
||||
for i in 0..n.safeLen-1:
|
||||
|
||||
@@ -169,3 +169,10 @@ proc flattenStmts*(n: PNode): PNode =
|
||||
proc extractRange*(k: TNodeKind, n: PNode, a, b: int): PNode =
|
||||
result = newNodeI(k, n.info, b-a+1)
|
||||
for i in 0..b-a: result[i] = n[i+a]
|
||||
|
||||
proc dontInlineConstant*(orig, cnst: PNode): bool {.inline.} =
|
||||
# symbols that expand to a complex constant (array, etc.) should not be
|
||||
# inlined, unless it's the empty array:
|
||||
result = orig.kind == nkSym and
|
||||
cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and
|
||||
cnst.len > ord(cnst.kind == nkObjConstr)
|
||||
|
||||
@@ -2086,6 +2086,7 @@ proc execute(c: PCtx, start: int): PNode =
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
|
||||
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
||||
c.loopIterations = c.config.maxLoopIterationsVM
|
||||
if sym.kind in routineKinds:
|
||||
if sym.typ.len-1 != args.len:
|
||||
localError(c.config, sym.info,
|
||||
|
||||
@@ -247,6 +247,8 @@ proc freeTemp(c: PCtx; r: TRegister) =
|
||||
proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
|
||||
# if register pressure is high, we re-use more aggressively:
|
||||
let c = cc.prc
|
||||
# we could also customize via the following (with proper caching in ConfigRef):
|
||||
# let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt
|
||||
if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
|
||||
for i in 0..c.maxSlots-n:
|
||||
if not c.slots[i].inUse:
|
||||
@@ -1521,14 +1523,14 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(idx)
|
||||
# c.freeTemp(idx) # BUGFIX, see nkDotExpr
|
||||
c.freeTemp(objR)
|
||||
of nkDotExpr:
|
||||
let dest = c.genx(le[0], {gfNode})
|
||||
let idx = genField(c, le[1])
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
|
||||
c.freeTemp(idx)
|
||||
# c.freeTemp(idx) # BUGFIX: idx is an immediate (field position), not a register
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(dest)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
|
||||
@@ -41,7 +41,7 @@ written as:
|
||||
dealloc(x.data)
|
||||
x.data = nil
|
||||
|
||||
proc `=`*[T](a: var myseq[T]; b: myseq[T]) =
|
||||
proc `=copy`*[T](a: var myseq[T]; b: myseq[T]) =
|
||||
# do nothing for self-assignments:
|
||||
if a.data == b.data: return
|
||||
`=destroy`(a)
|
||||
@@ -134,7 +134,7 @@ not free the resources afterwards by setting the object to its default value
|
||||
default value is written as ``wasMoved(x)``. When not provided the compiler
|
||||
is using a combination of `=destroy` and `copyMem` instead. This is efficient
|
||||
hence users rarely need to implement their own `=sink` operator, it is enough to
|
||||
provide `=destroy` and `=`, compiler will take care about the rest.
|
||||
provide `=destroy` and `=copy`, compiler will take care about the rest.
|
||||
|
||||
The prototype of this hook for a type ``T`` needs to be:
|
||||
|
||||
@@ -156,10 +156,10 @@ The general pattern in ``=sink`` looks like:
|
||||
How self-assignments are handled is explained later in this document.
|
||||
|
||||
|
||||
`=` (copy) hook
|
||||
`=copy` hook
|
||||
---------------
|
||||
|
||||
The ordinary assignment in Nim conceptually copies the values. The ``=`` hook
|
||||
The ordinary assignment in Nim conceptually copies the values. The ``=copy`` hook
|
||||
is called for assignments that couldn't be transformed into ``=sink``
|
||||
operations.
|
||||
|
||||
@@ -167,21 +167,21 @@ The prototype of this hook for a type ``T`` needs to be:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
proc `=`(dest: var T; source: T)
|
||||
proc `=copy`(dest: var T; source: T)
|
||||
|
||||
|
||||
The general pattern in ``=`` looks like:
|
||||
The general pattern in ``=copy`` looks like:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
proc `=`(dest: var T; source: T) =
|
||||
proc `=copy`(dest: var T; source: T) =
|
||||
# protect against self-assignments:
|
||||
if dest.field != source.field:
|
||||
`=destroy`(dest)
|
||||
dest.field = duplicateResource(source.field)
|
||||
|
||||
|
||||
The ``=`` proc can be marked with the ``{.error.}`` pragma. Then any assignment
|
||||
The ``=copy`` proc can be marked with the ``{.error.}`` pragma. Then any assignment
|
||||
that otherwise would lead to a copy is prevented at compile-time.
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ Swap
|
||||
====
|
||||
|
||||
The need to check for self-assignments and also the need to destroy previous
|
||||
objects inside ``=`` and ``=sink`` is a strong indicator to treat
|
||||
objects inside ``=copy`` and ``=sink`` is a strong indicator to treat
|
||||
``system.swap`` as a builtin primitive of its own that simply swaps every
|
||||
field in the involved objects via ``copyMem`` or a comparable mechanism.
|
||||
In other words, ``swap(a, b)`` is **not** implemented
|
||||
@@ -320,7 +320,7 @@ not destroyed at the scope exit, but at the proc exit.
|
||||
|
||||
x = y
|
||||
------------------ (copy)
|
||||
`=`(x, y)
|
||||
`=copy`(x, y)
|
||||
|
||||
|
||||
f_sink(g())
|
||||
@@ -330,7 +330,7 @@ not destroyed at the scope exit, but at the proc exit.
|
||||
|
||||
f_sink(notLastReadOf y)
|
||||
-------------------------- (copy-to-sink)
|
||||
(let tmp; `=`(tmp, y);
|
||||
(let tmp; `=copy`(tmp, y);
|
||||
f_sink(tmp))
|
||||
|
||||
|
||||
|
||||
36
koch.nim
36
koch.nim
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
const
|
||||
NimbleStableCommit = "63695f490728e3935692c29f3d71944d83bb1e83" # master
|
||||
NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master
|
||||
|
||||
when not defined(windows):
|
||||
const
|
||||
@@ -136,35 +136,11 @@ proc bundleC2nim(args: string) =
|
||||
|
||||
proc bundleNimbleExe(latest: bool, args: string) =
|
||||
let commit = if latest: "HEAD" else: NimbleStableCommit
|
||||
cloneDependency(distDir, "https://github.com/nim-lang/nimble.git", commit = commit)
|
||||
cloneDependency(distDir, "https://github.com/nim-lang/nimble.git",
|
||||
commit = commit, allowBundled = true)
|
||||
# installer.ini expects it under $nim/bin
|
||||
nimCompile("dist/nimble/src/nimble.nim",
|
||||
options = "-d:release --nilseqs:on " & args)
|
||||
|
||||
proc buildNimble(latest: bool, args: string) =
|
||||
# if koch is used for a tar.xz, build the dist/nimble we shipped
|
||||
# with the tarball:
|
||||
var installDir = "dist/nimble"
|
||||
if not latest and dirExists(installDir) and not dirExists("dist/nimble/.git"):
|
||||
discard "don't do the git dance"
|
||||
else:
|
||||
if not dirExists("dist/nimble/.git"):
|
||||
if dirExists(installDir):
|
||||
var id = 0
|
||||
while dirExists("dist/nimble" & $id):
|
||||
inc id
|
||||
installDir = "dist/nimble" & $id
|
||||
# consider using/adapting cloneDependency
|
||||
exec("git clone -q https://github.com/nim-lang/nimble.git " & installDir)
|
||||
withDir(installDir):
|
||||
if latest:
|
||||
exec("git checkout -f master")
|
||||
exec("git pull")
|
||||
else:
|
||||
exec("git fetch")
|
||||
exec("git checkout " & NimbleStableCommit)
|
||||
nimCompile(installDir / "src/nimble.nim",
|
||||
options = "--noNimblePath --nilseqs:on -d:release " & args)
|
||||
options = "-d:release --noNimblePath " & args)
|
||||
|
||||
proc bundleNimsuggest(args: string) =
|
||||
nimCompileFold("Compile nimsuggest", "nimsuggest/nimsuggest.nim",
|
||||
@@ -664,13 +640,13 @@ when isMainModule:
|
||||
of "temp": temp(op.cmdLineRest)
|
||||
of "xtemp": xtemp(op.cmdLineRest)
|
||||
of "wintools": bundleWinTools(op.cmdLineRest)
|
||||
of "nimble": buildNimble(latest, op.cmdLineRest)
|
||||
of "nimble": bundleNimbleExe(latest, op.cmdLineRest)
|
||||
of "nimsuggest": bundleNimsuggest(op.cmdLineRest)
|
||||
of "toolsnonimble":
|
||||
buildTools(op.cmdLineRest)
|
||||
of "tools":
|
||||
buildTools(op.cmdLineRest)
|
||||
buildNimble(latest, op.cmdLineRest)
|
||||
bundleNimbleExe(latest, op.cmdLineRest)
|
||||
of "pushcsource", "pushcsources": pushCsources()
|
||||
of "valgrind": valgrind(op.cmdLineRest)
|
||||
of "c2nim": bundleC2nim(op.cmdLineRest)
|
||||
|
||||
@@ -271,7 +271,7 @@ proc setPointer*(x: Any, y: pointer) =
|
||||
## ``akPointer``, ``akSequence``.
|
||||
assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer,
|
||||
tySequence, tyProc}
|
||||
cast[ppointer](x.value)[] = y
|
||||
genericAssign(x.value, y, x.rawType)
|
||||
|
||||
proc fieldsAux(p: pointer, n: ptr TNimNode,
|
||||
ret: var seq[tuple[name: cstring, any: Any]]) =
|
||||
|
||||
@@ -531,7 +531,7 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt
|
||||
raise RegexInternalError(msg : "Unknown internal error: " & $execRet)
|
||||
|
||||
proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] =
|
||||
## Like ` ``find(...)`` <#proc-find>`_, but anchored to the start of the
|
||||
## Like `find(...)<#find,string,Regex,int>`_, but anchored to the start of the
|
||||
## string.
|
||||
##
|
||||
runnableExamples:
|
||||
@@ -541,11 +541,11 @@ proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[R
|
||||
return str.matchImpl(pattern, start, endpos, pcre.ANCHORED)
|
||||
|
||||
iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): RegexMatch =
|
||||
## Works the same as ` ``find(...)`` <#proc-find>`_, but finds every
|
||||
## Works the same as `find(...)<#find,string,Regex,int>`_, but finds every
|
||||
## non-overlapping match. ``"2222".find(re"22")`` is ``"22", "22"``, not
|
||||
## ``"22", "22", "22"``.
|
||||
##
|
||||
## Arguments are the same as ` ``find(...)`` <#proc-find>`_
|
||||
## Arguments are the same as `find(...)<#find,string,Regex,int>`_
|
||||
##
|
||||
## Variants:
|
||||
##
|
||||
@@ -624,7 +624,7 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string]
|
||||
## Splits the string with the given regex. This works according to the
|
||||
## rules that Perl and Javascript use.
|
||||
##
|
||||
## ``start`` behaves the same as in ` ``find(...)`` <#proc-find>`_.
|
||||
## ``start`` behaves the same as in `find(...)<#find,string,Regex,int>`_.
|
||||
##
|
||||
runnableExamples:
|
||||
# - If the match is zero-width, then the string is still split:
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
import os, tables, strutils, times, heapqueue, options, deques, cstrutils
|
||||
|
||||
import "system/stacktraces"
|
||||
|
||||
# TODO: This shouldn't need to be included, but should ideally be exported.
|
||||
type
|
||||
CallbackFunc = proc () {.closure, gcsafe.}
|
||||
@@ -311,7 +313,12 @@ proc getHint(entry: StackTraceEntry): string =
|
||||
if cmpIgnoreStyle(entry.filename, "asyncmacro.nim") == 0:
|
||||
return "Resumes an async procedure"
|
||||
|
||||
proc `$`*(entries: seq[StackTraceEntry]): string =
|
||||
proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string =
|
||||
when defined(nimStackTraceOverride):
|
||||
let entries = addDebuggingInfo(stackTraceEntries)
|
||||
else:
|
||||
let entries = stackTraceEntries
|
||||
|
||||
result = ""
|
||||
# Find longest filename & line number combo for alignment purposes.
|
||||
var longestLeft = 0
|
||||
@@ -326,10 +333,10 @@ proc `$`*(entries: seq[StackTraceEntry]): string =
|
||||
# Format the entries.
|
||||
for entry in entries:
|
||||
if entry.procname.isNil:
|
||||
if entry.line == -10:
|
||||
if entry.line == reraisedFromBegin:
|
||||
result.add(spaces(indent) & "#[\n")
|
||||
indent.inc(2)
|
||||
else:
|
||||
elif entry.line == reraisedFromEnd:
|
||||
indent.dec(2)
|
||||
result.add(spaces(indent) & "]#\n")
|
||||
continue
|
||||
|
||||
@@ -691,8 +691,12 @@ elif defined(nimdoc):
|
||||
|
||||
proc close*(socket: AsyncSocket) =
|
||||
## Closes the socket.
|
||||
if socket.closed: return
|
||||
|
||||
defer:
|
||||
socket.fd.AsyncFD.closeSocket()
|
||||
socket.closed = true # TODO: Add extra debugging checks for this.
|
||||
|
||||
when defineSsl:
|
||||
if socket.isSsl:
|
||||
let res = SSL_shutdown(socket.sslHandle)
|
||||
@@ -701,7 +705,6 @@ proc close*(socket: AsyncSocket) =
|
||||
discard
|
||||
elif res != 1:
|
||||
raiseSSLError()
|
||||
socket.closed = true # TODO: Add extra debugging checks for this.
|
||||
|
||||
when defineSsl:
|
||||
proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) =
|
||||
|
||||
@@ -230,11 +230,11 @@ proc decode*(s: string): string =
|
||||
|
||||
template inputChar(x: untyped) =
|
||||
let x = int decodeTable[ord(s[inputIndex])]
|
||||
inc inputIndex
|
||||
if x == invalidChar:
|
||||
raise newException(ValueError,
|
||||
"Invalid base64 format character `" & s[inputIndex] &
|
||||
"` (ord " & $s[inputIndex].ord & ") at location " & $inputIndex & ".")
|
||||
inc inputIndex
|
||||
|
||||
template outputChar(x: untyped) =
|
||||
result[outputIndex] = char(x and 255)
|
||||
|
||||
@@ -1808,7 +1808,7 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): <//>OrderedTableRef[A, B]
|
||||
assert b == {'a': 5, 'b': 9}.newOrderedTable
|
||||
|
||||
result = newOrderedTable[A, B](rightSize(pairs.len))
|
||||
for key, val in items(pairs): result.add(key, val)
|
||||
for key, val in items(pairs): result[key] = val
|
||||
|
||||
|
||||
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
||||
@@ -2634,7 +2634,7 @@ proc `[]`*[A](t: CountTableRef[A], key: A): int =
|
||||
## See also:
|
||||
## * `getOrDefault<#getOrDefault,CountTableRef[A],A,int>`_ to return
|
||||
## a custom value if the key doesn't exist
|
||||
## * `mget proc<#mget,CountTableRef[A],A>`_
|
||||
## * `inc proc<#inc,CountTableRef[A],A>`_ to inc even if missing
|
||||
## * `[]= proc<#[]%3D,CountTableRef[A],A,int>`_ for inserting a new
|
||||
## (key, value) pair in the table
|
||||
## * `hasKey proc<#hasKey,CountTableRef[A],A>`_ for checking if a key
|
||||
@@ -3002,37 +3002,37 @@ when isMainModule:
|
||||
block: #5482
|
||||
var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
|
||||
var b = newOrderedTable[string, string](initialSize = 2)
|
||||
b.add("wrong?", "foo")
|
||||
b.add("wrong?", "foo2")
|
||||
b["wrong?"] = "foo"
|
||||
b["wrong?"] = "foo2"
|
||||
assert a == b
|
||||
|
||||
block: #5482
|
||||
var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
|
||||
var b = newOrderedTable[string, string](initialSize = 2)
|
||||
b.add("wrong?", "foo")
|
||||
b.add("wrong?", "foo2")
|
||||
b["wrong?"] = "foo"
|
||||
b["wrong?"] = "foo2"
|
||||
assert a == b
|
||||
|
||||
block: #5487
|
||||
var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
|
||||
var b = newOrderedTable[string, string]() # notice, default size!
|
||||
b.add("wrong?", "foo")
|
||||
b.add("wrong?", "foo2")
|
||||
b["wrong?"] = "foo"
|
||||
b["wrong?"] = "foo2"
|
||||
assert a == b
|
||||
|
||||
block: #5487
|
||||
var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
|
||||
var b = newOrderedTable[string, string]() # notice, default size!
|
||||
b.add("wrong?", "foo")
|
||||
b.add("wrong?", "foo2")
|
||||
b["wrong?"] = "foo"
|
||||
b["wrong?"] = "foo2"
|
||||
assert a == b
|
||||
|
||||
block:
|
||||
var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
|
||||
var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
|
||||
var c = newOrderedTable[string, string]() # notice, default size!
|
||||
c.add("wrong?", "foo")
|
||||
c.add("wrong?", "foo2")
|
||||
c["wrong?"] = "foo"
|
||||
c["wrong?"] = "foo2"
|
||||
assert a == b
|
||||
assert a == c
|
||||
|
||||
|
||||
@@ -68,11 +68,11 @@ type
|
||||
Protocol* = enum ## third argument to `socket` proc
|
||||
IPPROTO_TCP = 6, ## Transmission control protocol.
|
||||
IPPROTO_UDP = 17, ## User datagram protocol.
|
||||
IPPROTO_IP, ## Internet protocol. Unsupported on Windows.
|
||||
IPPROTO_IPV6, ## Internet Protocol Version 6. Unsupported on Windows.
|
||||
IPPROTO_IP, ## Internet protocol.
|
||||
IPPROTO_IPV6, ## Internet Protocol Version 6.
|
||||
IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows.
|
||||
IPPROTO_ICMP ## Control message protocol. Unsupported on Windows.
|
||||
IPPROTO_ICMPV6 ## Control message protocol for IPv6. Unsupported on Windows.
|
||||
IPPROTO_ICMP ## Internet Control message protocol.
|
||||
IPPROTO_ICMPV6 ## Internet Control message protocol for IPv6.
|
||||
|
||||
Servent* = object ## information about a service
|
||||
name*: string
|
||||
@@ -113,7 +113,7 @@ proc `==`*(a, b: Port): bool {.borrow.}
|
||||
## ``==`` for ports.
|
||||
|
||||
proc `$`*(p: Port): string {.borrow.}
|
||||
## returns the port number as a string
|
||||
## Returns the port number as a string
|
||||
|
||||
proc toInt*(domain: Domain): cint
|
||||
## Converts the Domain enum to a platform-dependent ``cint``.
|
||||
@@ -174,7 +174,21 @@ else:
|
||||
result = cint(ord(typ))
|
||||
|
||||
proc toInt(p: Protocol): cint =
|
||||
result = cint(ord(p))
|
||||
case p
|
||||
of IPPROTO_IP:
|
||||
result = 0.cint
|
||||
of IPPROTO_ICMP:
|
||||
result = 1.cint
|
||||
of IPPROTO_TCP:
|
||||
result = 6.cint
|
||||
of IPPROTO_UDP:
|
||||
result = 17.cint
|
||||
of IPPROTO_IPV6:
|
||||
result = 41.cint
|
||||
of IPPROTO_ICMPV6:
|
||||
result = 58.cint
|
||||
else:
|
||||
result = cint(ord(p))
|
||||
|
||||
proc toSockType*(protocol: Protocol): SockType =
|
||||
result = case protocol
|
||||
@@ -414,7 +428,7 @@ proc getHostname*(): string {.tags: [ReadIOEffect].} =
|
||||
result.setLen(x)
|
||||
|
||||
proc getSockDomain*(socket: SocketHandle): Domain =
|
||||
## returns the socket's domain (AF_INET or AF_INET6).
|
||||
## Returns the socket's domain (AF_INET or AF_INET6).
|
||||
var name: Sockaddr_in6
|
||||
var namelen = sizeof(name).SockLen
|
||||
if getsockname(socket, cast[ptr SockAddr](addr(name)),
|
||||
@@ -426,7 +440,7 @@ proc getSockDomain*(socket: SocketHandle): Domain =
|
||||
raise newException(IOError, "Unknown socket family in getSockDomain")
|
||||
|
||||
proc getAddrString*(sockAddr: ptr SockAddr): string =
|
||||
## return the string representation of address within sockAddr
|
||||
## Returns the string representation of address within sockAddr
|
||||
if sockAddr.sa_family.cint == nativeAfInet:
|
||||
result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr)
|
||||
elif sockAddr.sa_family.cint == nativeAfInet6:
|
||||
@@ -459,7 +473,7 @@ when defined(posix) and not defined(nimdoc):
|
||||
copyMem(addr result.sun_path, path.cstring, path.len + 1)
|
||||
|
||||
proc getSockName*(socket: SocketHandle): Port =
|
||||
## returns the socket's associated port number.
|
||||
## Returns the socket's associated port number.
|
||||
var name: Sockaddr_in
|
||||
when useWinVersion:
|
||||
name.sin_family = uint16(ord(AF_INET))
|
||||
@@ -474,7 +488,7 @@ proc getSockName*(socket: SocketHandle): Port =
|
||||
result = Port(nativesockets.ntohs(name.sin_port))
|
||||
|
||||
proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
|
||||
## returns the socket's local address and port number.
|
||||
## Returns the socket's local address and port number.
|
||||
##
|
||||
## Similar to POSIX's `getsockname`:idx:.
|
||||
case domain
|
||||
@@ -511,7 +525,7 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
|
||||
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
|
||||
|
||||
proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
|
||||
## returns the socket's peer address and port number.
|
||||
## Returns the socket's peer address and port number.
|
||||
##
|
||||
## Similar to POSIX's `getpeername`:idx:
|
||||
case domain
|
||||
|
||||
@@ -1816,4 +1816,5 @@ proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress =
|
||||
else:
|
||||
newSocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
|
||||
socket.connect($dest, 80.Port)
|
||||
socket.getLocalAddr()[0].parseIpAddress()
|
||||
result = socket.getLocalAddr()[0].parseIpAddress()
|
||||
socket.close()
|
||||
|
||||
@@ -630,8 +630,11 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
success = winlean.createProcessW(nil, tmp, nil, nil, 1, flags,
|
||||
ee, wwd, si, procInfo)
|
||||
else:
|
||||
var ee =
|
||||
if e.str.isNil: cstring(nil)
|
||||
else: cstring(e.str)
|
||||
success = winlean.createProcessA(nil,
|
||||
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, si, procInfo)
|
||||
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, ee, wd, si, procInfo)
|
||||
let lastError = osLastError()
|
||||
|
||||
if poParentStreams notin options:
|
||||
|
||||
@@ -672,6 +672,9 @@ proc parseAttribute(my: var XmlParser) =
|
||||
parseEntity(my, my.b)
|
||||
my.kind = xmlAttribute # parseEntity overwrites my.kind!
|
||||
pos = my.bufpos
|
||||
elif c == '/':
|
||||
pos = lexbase.handleRefillChar(my, pos)
|
||||
add(my.b, '/')
|
||||
else:
|
||||
add(my.b, c)
|
||||
inc(pos)
|
||||
|
||||
@@ -396,7 +396,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||
var resLen = genSym(nskLet, "resLen")
|
||||
conds.add newLetStmt(resLen, newCall(bindSym"parseUntil", inp,
|
||||
results[i], newLit(token), idx))
|
||||
conds.add newCall(bindSym"!=", resLen, newLit min)
|
||||
conds.add newCall(bindSym">=", resLen, newLit min)
|
||||
conds.add resLen
|
||||
else:
|
||||
matchError
|
||||
|
||||
@@ -917,6 +917,31 @@ proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
||||
inc shift, 3
|
||||
mask = mask shl BiggestUInt(3)
|
||||
|
||||
proc toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string {.noSideEffect.} =
|
||||
const
|
||||
HexChars = "0123456789ABCDEF"
|
||||
var n = x
|
||||
result = newString(len)
|
||||
for j in countdown(len-1, 0):
|
||||
result[j] = HexChars[int(n and 0xF)]
|
||||
n = n shr 4
|
||||
# handle negative overflow
|
||||
if n == 0 and handleNegative: n = not(BiggestUInt 0)
|
||||
|
||||
proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} =
|
||||
## Converts `x` to its hexadecimal representation.
|
||||
##
|
||||
## The resulting string will be exactly `len` characters long. No prefix like
|
||||
## ``0x`` is generated.
|
||||
runnableExamples:
|
||||
let
|
||||
a = 62'u64
|
||||
b = 4097'u64
|
||||
doAssert a.toHex(3) == "03E"
|
||||
doAssert b.toHex(3) == "001"
|
||||
doAssert b.toHex(4) == "1001"
|
||||
toHexImpl(x, len, false)
|
||||
|
||||
proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
||||
rtl, extern: "nsuToHex".} =
|
||||
## Converts `x` to its hexadecimal representation.
|
||||
@@ -927,25 +952,19 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
||||
let
|
||||
a = 62
|
||||
b = 4097
|
||||
c = -8
|
||||
doAssert a.toHex(3) == "03E"
|
||||
doAssert b.toHex(3) == "001"
|
||||
doAssert b.toHex(4) == "1001"
|
||||
const
|
||||
HexChars = "0123456789ABCDEF"
|
||||
var
|
||||
n = x
|
||||
result = newString(len)
|
||||
for j in countdown(len-1, 0):
|
||||
result[j] = HexChars[int(n and 0xF)]
|
||||
n = n shr 4
|
||||
# handle negative overflow
|
||||
if n == 0 and x < 0: n = -1
|
||||
doAssert c.toHex(6) == "FFFFF8"
|
||||
toHexImpl(cast[BiggestUInt](x), len, x < 0)
|
||||
|
||||
proc toHex*[T: SomeInteger](x: T): string =
|
||||
proc toHex*[T: SomeInteger](x: T): string {.noSideEffect.} =
|
||||
## Shortcut for ``toHex(x, T.sizeof * 2)``
|
||||
runnableExamples:
|
||||
doAssert toHex(1984'i64) == "00000000000007C0"
|
||||
toHex(BiggestInt(x), T.sizeof * 2)
|
||||
doAssert toHex(1984'i16) == "07C0"
|
||||
toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0)
|
||||
|
||||
proc toHex*(s: string): string {.noSideEffect, rtl.} =
|
||||
## Converts a bytes string to its hexadecimal representation.
|
||||
@@ -1806,7 +1825,7 @@ proc initSkipTable*(a: var SkipTable, sub: string)
|
||||
|
||||
proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int
|
||||
{.noSideEffect, rtl, extern: "nsuFindStrA".} =
|
||||
## Searches for `sub` in `s` inside range `start`..`last` using preprocessed
|
||||
## Searches for `sub` in `s` inside range `start..last` using preprocessed
|
||||
## table `a`. If `last` is unspecified, it defaults to `s.high` (the last
|
||||
## element).
|
||||
##
|
||||
|
||||
@@ -369,3 +369,13 @@ when isMainModule:
|
||||
of "bird": "word"
|
||||
else: d
|
||||
assert z == @["word", "word"]
|
||||
|
||||
|
||||
proc tforum =
|
||||
let ans = collect(newSeq):
|
||||
for y in 0..10:
|
||||
if y mod 5 == 2:
|
||||
for x in 0..y:
|
||||
x
|
||||
|
||||
tforum()
|
||||
|
||||
@@ -689,10 +689,9 @@ template styledEchoProcessArg(f: File, color: Color) =
|
||||
template styledEchoProcessArg(f: File, cmd: TerminalCmd) =
|
||||
when cmd == resetStyle:
|
||||
resetAttributes(f)
|
||||
when cmd == fgColor:
|
||||
fgSetColor = true
|
||||
when cmd == bgColor:
|
||||
fgSetColor = false
|
||||
elif cmd in {fgColor, bgColor}:
|
||||
let term = getTerminal()
|
||||
term.fgSetColor = cmd == fgColor
|
||||
|
||||
macro styledWrite*(f: File, m: varargs[typed]): untyped =
|
||||
## Similar to ``write``, but treating terminal style arguments specially.
|
||||
@@ -776,25 +775,20 @@ when defined(windows):
|
||||
## ``true`` otherwise.
|
||||
password.string.setLen(0)
|
||||
stdout.write(prompt)
|
||||
while true:
|
||||
let c = getch()
|
||||
case c.char
|
||||
of '\r', chr(0xA):
|
||||
break
|
||||
of '\b':
|
||||
# ensure we delete the whole UTF-8 character:
|
||||
var i = 0
|
||||
var x = 1
|
||||
while i < password.len:
|
||||
x = runeLenAt(password.string, i)
|
||||
inc i, x
|
||||
password.string.setLen(max(password.len - x, 0))
|
||||
of chr(0x0):
|
||||
# modifier key - ignore - for details see
|
||||
# https://github.com/nim-lang/Nim/issues/7764
|
||||
continue
|
||||
else:
|
||||
password.string.add(toUTF8(c.Rune))
|
||||
let hi = createFileA("CONIN$",
|
||||
GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0)
|
||||
var mode = DWORD 0
|
||||
discard getConsoleMode(hi, addr mode)
|
||||
let origMode = mode
|
||||
const
|
||||
ENABLE_PROCESSED_INPUT = 1
|
||||
ENABLE_ECHO_INPUT = 4
|
||||
mode = (mode or ENABLE_PROCESSED_INPUT) and not ENABLE_ECHO_INPUT
|
||||
|
||||
discard setConsoleMode(hi, mode)
|
||||
result = readLine(stdin, password)
|
||||
discard setConsoleMode(hi, origMode)
|
||||
discard closeHandle(hi)
|
||||
stdout.write "\n"
|
||||
|
||||
else:
|
||||
|
||||
@@ -1357,6 +1357,12 @@ type # these work for most platforms:
|
||||
culonglong* {.importc: "unsigned long long", nodecl.} = uint64
|
||||
## This is the same as the type ``unsigned long long`` in *C*.
|
||||
|
||||
# There is a disparity on macOS where Nim's `uint` is `unsigned long long` and
|
||||
# `uintptr_t` is `unsigned long`. Even though both data types are the same
|
||||
# size (64 bits), clang++ refuses to do automatic conversion between them.
|
||||
cuintptr_t* {.importc: "uintptr_t", nodecl.} = uint
|
||||
## This is the same as the type ``uintptr_t`` in *C*.
|
||||
|
||||
cstringArray* {.importc: "char**", nodecl.} = ptr UncheckedArray[cstring]
|
||||
## This is binary compatible to the type ``char**`` in *C*. The array's
|
||||
## high value is large enough to disable bounds checking in practice.
|
||||
@@ -2052,7 +2058,7 @@ const
|
||||
NimMinor* {.intdefine.}: int = 2
|
||||
## is the minor number of Nim's version.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 6
|
||||
NimPatch* {.intdefine.}: int = 8
|
||||
## is the patch number of Nim's version.
|
||||
|
||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
|
||||
@@ -38,6 +38,9 @@ proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} =
|
||||
# todo: better error reporting
|
||||
sysFatal(RangeError, "value out of range")
|
||||
|
||||
proc raiseRangeErrorNoArgs() {.compilerproc, noinline.} =
|
||||
sysFatal(RangeError, "value out of range")
|
||||
|
||||
proc raiseObjectConversionError() {.compilerproc, noinline.} =
|
||||
sysFatal(ObjectConversionError, "invalid object conversion")
|
||||
|
||||
|
||||
@@ -25,6 +25,11 @@ type
|
||||
## rendered at a later time, we should ensure the stacktrace
|
||||
## data isn't invalidated; any pointer into PFrame is
|
||||
## subject to being invalidated so shouldn't be stored.
|
||||
when defined(nimStackTraceOverride):
|
||||
programCounter*: uint ## Program counter - will be used to get the rest of the info,
|
||||
## when `$` is called on this type. We can't use
|
||||
## "cuintptr_t" in here.
|
||||
procnameStr*, filenameStr*: string ## GC-ed objects holding the cstrings in "procname" and "filename"
|
||||
|
||||
Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \
|
||||
## Base exception class.
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
# Exception handling code. Carefully coded so that tiny programs which do not
|
||||
# use the heap (and nor exceptions) do not include the GC or memory allocator.
|
||||
|
||||
import stacktraces
|
||||
|
||||
var
|
||||
errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign,
|
||||
nimcall.})
|
||||
@@ -133,20 +135,6 @@ const
|
||||
hasSomeStackTrace = NimStackTrace or defined(nimStackTraceOverride) or
|
||||
(defined(nativeStackTrace) and nativeStackTraceSupported)
|
||||
|
||||
when defined(nimStackTraceOverride):
|
||||
type StackTraceOverrideProc* = proc (): string {.nimcall, noinline, benign, raises: [], tags: [].}
|
||||
## Procedure type for overriding the default stack trace.
|
||||
|
||||
var stackTraceOverrideGetTraceback: StackTraceOverrideProc = proc(): string {.noinline.} =
|
||||
result = "Stack trace override procedure not registered.\n"
|
||||
|
||||
proc registerStackTraceOverride*(overrideProc: StackTraceOverrideProc) =
|
||||
## Override the default stack trace inside rawWriteStackTrace() with your
|
||||
## own procedure.
|
||||
stackTraceOverrideGetTraceback = overrideProc
|
||||
|
||||
proc auxWriteStackTraceWithOverride(s: var string) =
|
||||
add(s, stackTraceOverrideGetTraceback())
|
||||
|
||||
when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||
type
|
||||
@@ -164,13 +152,13 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||
|
||||
when not hasThreadSupport:
|
||||
var
|
||||
tempAddresses: array[0..127, pointer] # should not be alloc'd on stack
|
||||
tempAddresses: array[maxStackTraceLines, pointer] # should not be alloc'd on stack
|
||||
tempDlInfo: TDl_info
|
||||
|
||||
proc auxWriteStackTraceWithBacktrace(s: var string) =
|
||||
when hasThreadSupport:
|
||||
var
|
||||
tempAddresses: array[0..127, pointer] # but better than a threadvar
|
||||
tempAddresses: array[maxStackTraceLines, pointer] # but better than a threadvar
|
||||
tempDlInfo: TDl_info
|
||||
# This is allowed to be expensive since it only happens during crashes
|
||||
# (but this way you don't need manual stack tracing)
|
||||
@@ -198,11 +186,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||
|
||||
when hasSomeStackTrace and not hasThreadSupport:
|
||||
var
|
||||
tempFrames: array[0..127, PFrame] # should not be alloc'd on stack
|
||||
|
||||
const
|
||||
reraisedFromBegin = -10
|
||||
reraisedFromEnd = -100
|
||||
tempFrames: array[maxStackTraceLines, PFrame] # should not be alloc'd on stack
|
||||
|
||||
template reraisedFrom(z): untyped =
|
||||
StackTraceEntry(procname: nil, line: z, filename: nil)
|
||||
@@ -253,7 +237,12 @@ template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) =
|
||||
for i in first..<f.frameMsgLen: add(s, frameMsgBuf[i])
|
||||
add(s, "\n")
|
||||
|
||||
proc `$`(s: seq[StackTraceEntry]): string =
|
||||
proc `$`(stackTraceEntries: seq[StackTraceEntry]): string =
|
||||
when defined(nimStackTraceOverride):
|
||||
let s = addDebuggingInfo(stackTraceEntries)
|
||||
else:
|
||||
let s = stackTraceEntries
|
||||
|
||||
result = newStringOfCap(2000)
|
||||
for i in 0 .. s.len-1:
|
||||
if s[i].line == reraisedFromBegin: result.add "[[reraised from:\n"
|
||||
@@ -265,7 +254,7 @@ when hasSomeStackTrace:
|
||||
proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||
when hasThreadSupport:
|
||||
var
|
||||
tempFrames: array[0..127, PFrame] # but better than a threadvar
|
||||
tempFrames: array[maxStackTraceLines, PFrame] # but better than a threadvar
|
||||
const
|
||||
firstCalls = 32
|
||||
var
|
||||
@@ -324,7 +313,9 @@ when hasSomeStackTrace:
|
||||
add(s, "No stack traceback available\n")
|
||||
|
||||
proc rawWriteStackTrace(s: var seq[StackTraceEntry]) =
|
||||
when NimStackTrace:
|
||||
when defined(nimStackTraceOverride):
|
||||
auxWriteStackTraceWithOverride(s)
|
||||
elif NimStackTrace:
|
||||
auxWriteStackTrace(framePtr, s)
|
||||
else:
|
||||
s = @[]
|
||||
@@ -463,7 +454,12 @@ proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring
|
||||
if e.name.isNil: e.name = ename
|
||||
when hasSomeStackTrace:
|
||||
when defined(nimStackTraceOverride):
|
||||
e.trace = @[]
|
||||
if e.trace.len == 0:
|
||||
rawWriteStackTrace(e.trace)
|
||||
else:
|
||||
e.trace.add reraisedFrom(reraisedFromBegin)
|
||||
auxWriteStackTraceWithOverride(e.trace)
|
||||
e.trace.add reraisedFrom(reraisedFromEnd)
|
||||
elif NimStackTrace:
|
||||
if e.trace.len == 0:
|
||||
rawWriteStackTrace(e.trace)
|
||||
|
||||
83
lib/system/stacktraces.nim
Normal file
83
lib/system/stacktraces.nim
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# Additional code for customizable stack traces. Unstable API, for internal
|
||||
# usage only.
|
||||
|
||||
const
|
||||
reraisedFromBegin* = -10
|
||||
reraisedFromEnd* = -100
|
||||
maxStackTraceLines* = 128
|
||||
|
||||
when defined(nimStackTraceOverride):
|
||||
## Procedure types for overriding the default stack trace.
|
||||
type
|
||||
cuintptr_t {.importc: "uintptr_t", nodecl.} = uint
|
||||
## This is the same as the type ``uintptr_t`` in C.
|
||||
|
||||
StackTraceOverrideGetTracebackProc* = proc (): string {.
|
||||
nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.}
|
||||
StackTraceOverrideGetProgramCountersProc* = proc (maxLength: cint): seq[cuintptr_t] {.
|
||||
nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.}
|
||||
StackTraceOverrideGetDebuggingInfoProc* =
|
||||
proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.
|
||||
nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.}
|
||||
|
||||
# Default procedures (not normally used, because people opting in on this
|
||||
# override are supposed to register their own versions).
|
||||
var
|
||||
stackTraceOverrideGetTraceback: StackTraceOverrideGetTracebackProc =
|
||||
proc (): string {.nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} =
|
||||
discard
|
||||
#result = "Stack trace override procedure not registered.\n"
|
||||
stackTraceOverrideGetProgramCounters: StackTraceOverrideGetProgramCountersProc =
|
||||
proc (maxLength: cint): seq[cuintptr_t] {.nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} =
|
||||
discard
|
||||
stackTraceOverrideGetDebuggingInfo: StackTraceOverrideGetDebuggingInfoProc =
|
||||
proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.
|
||||
nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} =
|
||||
discard
|
||||
|
||||
# Custom procedure registration.
|
||||
proc registerStackTraceOverride*(overrideProc: StackTraceOverrideGetTracebackProc) =
|
||||
## Override the default stack trace inside rawWriteStackTrace() with your
|
||||
## own procedure.
|
||||
stackTraceOverrideGetTraceback = overrideProc
|
||||
proc registerStackTraceOverrideGetProgramCounters*(overrideProc: StackTraceOverrideGetProgramCountersProc) =
|
||||
stackTraceOverrideGetProgramCounters = overrideProc
|
||||
proc registerStackTraceOverrideGetDebuggingInfo*(overrideProc: StackTraceOverrideGetDebuggingInfoProc) =
|
||||
stackTraceOverrideGetDebuggingInfo = overrideProc
|
||||
|
||||
# Custom stack trace manipulation.
|
||||
proc auxWriteStackTraceWithOverride*(s: var string) =
|
||||
add(s, stackTraceOverrideGetTraceback())
|
||||
|
||||
proc auxWriteStackTraceWithOverride*(s: var seq[StackTraceEntry]) =
|
||||
let programCounters = stackTraceOverrideGetProgramCounters(maxStackTraceLines)
|
||||
if s.len == 0:
|
||||
s = newSeqOfCap[StackTraceEntry](programCounters.len)
|
||||
for programCounter in programCounters:
|
||||
s.add(StackTraceEntry(programCounter: cast[uint](programCounter)))
|
||||
|
||||
# We may have more stack trace lines in the output, due to inlined procedures.
|
||||
proc addDebuggingInfo*(s: seq[StackTraceEntry]): seq[StackTraceEntry] =
|
||||
var programCounters: seq[cuintptr_t]
|
||||
# We process program counters in groups from complete stack traces, because
|
||||
# we have logic that keeps track of certain functions being inlined or not.
|
||||
for entry in s:
|
||||
if entry.procname.isNil and entry.programCounter != 0:
|
||||
programCounters.add(cast[cuintptr_t](entry.programCounter))
|
||||
elif entry.procname.isNil and (entry.line == reraisedFromBegin or entry.line == reraisedFromEnd):
|
||||
result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))
|
||||
programCounters = @[]
|
||||
result.add(entry)
|
||||
else:
|
||||
result.add(entry)
|
||||
if programCounters.len > 0:
|
||||
result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))
|
||||
@@ -145,13 +145,13 @@ else:
|
||||
SysCond = ptr SysCondObj
|
||||
|
||||
when not declared(c_malloc):
|
||||
proc c_malloc(size: csize): pointer {.
|
||||
proc c_malloc(size: csize_t): pointer {.
|
||||
importc: "malloc", header: "<stdlib.h>".}
|
||||
proc c_free(p: pointer) {.
|
||||
importc: "free", header: "<stdlib.h>".}
|
||||
|
||||
proc initSysLock(L: var SysLock, attr: ptr SysLockAttr = nil) =
|
||||
L = cast[SysLock](c_malloc(sizeof(SysLockObj)))
|
||||
L = cast[SysLock](c_malloc(csize_t(sizeof(SysLockObj))))
|
||||
initSysLockAux(L[], attr)
|
||||
|
||||
proc deinitSys(L: var SysLock) =
|
||||
@@ -201,7 +201,7 @@ else:
|
||||
|
||||
when defined(ios):
|
||||
proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
|
||||
cond = cast[SysCond](c_malloc(sizeof(SysCondObj)))
|
||||
cond = cast[SysCond](c_malloc(csize_t(sizeof(SysCondObj))))
|
||||
initSysCondAux(cond[], cond_attr)
|
||||
|
||||
proc deinitSysCond(cond: var SysCond) =
|
||||
|
||||
@@ -311,7 +311,10 @@ else:
|
||||
when hasSharedHeap: t.core.stackSize = ThreadStackSize
|
||||
var a {.noinit.}: Pthread_attr
|
||||
doAssert pthread_attr_init(a) == 0
|
||||
doAssert pthread_attr_setstacksize(a, ThreadStackSize) == 0
|
||||
let setstacksizeResult = pthread_attr_setstacksize(a, ThreadStackSize)
|
||||
when not defined(ios):
|
||||
# This fails on iOS
|
||||
doAssert(setstacksizeResult == 0)
|
||||
if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0:
|
||||
raise newException(ResourceExhaustedError, "cannot create thread")
|
||||
doAssert pthread_attr_destroy(a) == 0
|
||||
|
||||
@@ -717,22 +717,20 @@ proc setHandleInformation*(hObject: Handle, dwMask: DWORD,
|
||||
proc getCurrentProcess*(): Handle{.stdcall, dynlib: "kernel32",
|
||||
importc: "GetCurrentProcess".}
|
||||
|
||||
when useWinUnicode:
|
||||
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
|
||||
lpSecurityAttributes: pointer,
|
||||
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
|
||||
hTemplateFile: Handle): Handle {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateFileW".}
|
||||
proc deleteFileW*(pathName: WideCString): int32 {.
|
||||
importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
|
||||
else:
|
||||
proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
|
||||
lpSecurityAttributes: pointer,
|
||||
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
|
||||
hTemplateFile: Handle): Handle {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateFileA".}
|
||||
proc deleteFileA*(pathName: cstring): int32 {.
|
||||
importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
|
||||
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
|
||||
lpSecurityAttributes: pointer,
|
||||
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
|
||||
hTemplateFile: Handle): Handle {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateFileW".}
|
||||
proc deleteFileW*(pathName: WideCString): int32 {.
|
||||
importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
|
||||
proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
|
||||
lpSecurityAttributes: pointer,
|
||||
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
|
||||
hTemplateFile: Handle): Handle {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateFileA".}
|
||||
proc deleteFileA*(pathName: cstring): int32 {.
|
||||
importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
|
||||
|
||||
proc setEndOfFile*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "SetEndOfFile".}
|
||||
|
||||
@@ -64,9 +64,9 @@ elif useWinVersion:
|
||||
from winlean import SocketHandle
|
||||
else:
|
||||
when defined(osx):
|
||||
const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.47|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
|
||||
const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.47|.48|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
|
||||
else:
|
||||
const versions = "(.1.1|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.47|.46|.45|.44|.43|.41|.39|.38|.10|)"
|
||||
const versions = "(.1.1|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.48|.47|.46|.45|.44|.43|.41|.39|.38|.10|)"
|
||||
|
||||
when defined(macosx):
|
||||
const
|
||||
|
||||
@@ -9,7 +9,7 @@ pkg "argparse"
|
||||
pkg "arraymancer", true, "nim c tests/tests_cpu.nim"
|
||||
pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim"
|
||||
pkg "asyncmysql", true
|
||||
pkg "bigints"
|
||||
pkg "bigints", url = "https://github.com/Araq/nim-bigints"
|
||||
pkg "binaryheap", false, "nim c -r binaryheap.nim"
|
||||
# pkg "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39
|
||||
pkg "bncurve", true
|
||||
@@ -91,6 +91,6 @@ pkg "unicodeplus", true
|
||||
pkg "unpack"
|
||||
# pkg "winim", true
|
||||
pkg "with"
|
||||
pkg "ws"
|
||||
# pkg "ws"
|
||||
pkg "yaml"
|
||||
pkg "zero_functional", false, "nim c -r test.nim"
|
||||
|
||||
25
tests/async/tbreak_must_exec_finally.nim
Normal file
25
tests/async/tbreak_must_exec_finally.nim
Normal file
@@ -0,0 +1,25 @@
|
||||
discard """
|
||||
output: '''
|
||||
finally handler 8
|
||||
do not duplicate this one
|
||||
'''
|
||||
"""
|
||||
|
||||
# bug #15243
|
||||
|
||||
import asyncdispatch
|
||||
|
||||
proc f() {.async.} =
|
||||
try:
|
||||
while true:
|
||||
try:
|
||||
await sleepAsync(400)
|
||||
break
|
||||
finally:
|
||||
var localHere = 8
|
||||
echo "finally handler ", localHere
|
||||
finally:
|
||||
echo "do not duplicate this one"
|
||||
|
||||
when isMainModule:
|
||||
waitFor f()
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
cmd: "nim c --newruntime $file"
|
||||
errormsg: "'=' is not available for type <owned Foo>; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice"
|
||||
errormsg: "'=copy' is not available for type <owned Foo>; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice"
|
||||
line: 11
|
||||
"""
|
||||
type
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
line: 29
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
file: "tprevent_assign2.nim"
|
||||
line: 48
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
|
||||
file: "tprevent_assign3.nim"
|
||||
line: 46
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
cmd: '''nim c --newruntime $file'''
|
||||
errormsg: "'=' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)"
|
||||
errormsg: "'=copy' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)"
|
||||
line: 48
|
||||
"""
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ proc rsplit(s: string; sep: string; maxsplit: int = -1): seq[string]
|
||||
first type mismatch at position: 2
|
||||
required type for sep: string
|
||||
but expression '{':'}' is of type: set[char]
|
||||
proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[string]
|
||||
proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[
|
||||
string]
|
||||
first type mismatch at position: 3
|
||||
unknown named parameter: maxsplits
|
||||
|
||||
@@ -22,6 +23,5 @@ expression: rsplit("abc:def", {':'}, maxsplits = 1)
|
||||
# bug #8043
|
||||
|
||||
|
||||
|
||||
import strutils
|
||||
"abc:def".rsplit({':'}, maxsplits = 1)
|
||||
|
||||
@@ -55,3 +55,10 @@ const
|
||||
for i in 0..len(stringArray)-1:
|
||||
echo(stringArray[i])
|
||||
|
||||
# bug #15360
|
||||
|
||||
type Rule[T] = (int, T)
|
||||
|
||||
var t: seq[Rule[int]]
|
||||
for (c, t) in t:
|
||||
discard
|
||||
|
||||
@@ -346,6 +346,21 @@ testinstance:
|
||||
c: char
|
||||
d: int32 # unaligned
|
||||
|
||||
Kind = enum
|
||||
K1, K2
|
||||
|
||||
AnotherEnum = enum
|
||||
X1, X2, X3
|
||||
|
||||
MyObject = object
|
||||
s: string
|
||||
case k: Kind
|
||||
of K1: nil
|
||||
of K2:
|
||||
x: float
|
||||
y: int32
|
||||
z: AnotherEnum
|
||||
|
||||
const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time
|
||||
|
||||
proc main(): void =
|
||||
@@ -361,6 +376,7 @@ testinstance:
|
||||
var go : GenericObject[int64]
|
||||
var po : PaddingOfSetEnum33
|
||||
var capo: MyCustomAlignPackedObject
|
||||
var issue15516: MyObject
|
||||
|
||||
var
|
||||
e1: Enum1
|
||||
@@ -379,7 +395,7 @@ testinstance:
|
||||
else:
|
||||
doAssert sizeof(SimpleAlignment) > 10
|
||||
|
||||
testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo)
|
||||
testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo, issue15516)
|
||||
|
||||
type
|
||||
WithBitsize {.objectconfig.} = object
|
||||
|
||||
@@ -75,3 +75,14 @@ let rangeVar = 0'u64 ..< limit
|
||||
doAssert repr(rangeVar) == """[a = 0,
|
||||
b = 0]
|
||||
"""
|
||||
|
||||
# bug #15210
|
||||
|
||||
let a3 = not 0'u64
|
||||
var success = false
|
||||
try:
|
||||
discard a3.int64
|
||||
except RangeError:
|
||||
success = true
|
||||
|
||||
doAssert success, "conversion should fail at runtime"
|
||||
|
||||
29
tests/stdlib/tnativesockets.nim
Normal file
29
tests/stdlib/tnativesockets.nim
Normal file
@@ -0,0 +1,29 @@
|
||||
discard """
|
||||
cmd: "nim c -r --styleCheck:hint --panics:on $options $file"
|
||||
targets: "c"
|
||||
nimout: ""
|
||||
action: "run"
|
||||
exitcode: 0
|
||||
timeout: 60.0
|
||||
"""
|
||||
|
||||
import nativesockets
|
||||
|
||||
|
||||
when defined(windows):
|
||||
doAssert toInt(IPPROTO_IP) == 0.cint
|
||||
doAssert toInt(IPPROTO_ICMP) == 1.cint
|
||||
doAssert toInt(IPPROTO_TCP) == 6.cint
|
||||
doAssert toInt(IPPROTO_UDP) == 17.cint
|
||||
doAssert toInt(IPPROTO_IPV6) == 41.cint
|
||||
doAssert toInt(IPPROTO_ICMPV6) == 58.cint
|
||||
doAssert toInt(IPPROTO_RAW) == 20.cint
|
||||
|
||||
# no changes to enum value
|
||||
doAssert ord(IPPROTO_TCP) == 6
|
||||
doAssert ord(IPPROTO_UDP) == 17
|
||||
doAssert ord(IPPROTO_IP) == 18
|
||||
doAssert ord(IPPROTO_IPV6) == 19
|
||||
doAssert ord(IPPROTO_RAW) == 20
|
||||
doAssert ord(IPPROTO_ICMP) == 21
|
||||
doAssert ord(IPPROTO_ICMPV6) == 22
|
||||
@@ -79,8 +79,22 @@ block EmptyTuple:
|
||||
block Arrow:
|
||||
let text = "foo;bar;baz;"
|
||||
var idx = 0
|
||||
var res = ""
|
||||
doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
|
||||
doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
|
||||
doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
|
||||
doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') == false
|
||||
|
||||
|
||||
block issue15064:
|
||||
var nick1, msg1: string
|
||||
doAssert scanf("<abcd> a", "<$+> $+", nick1, msg1)
|
||||
doAssert nick1 == "abcd"
|
||||
doAssert msg1 == "a"
|
||||
|
||||
var nick2, msg2: string
|
||||
doAssert(not scanf("<abcd> ", "<$+> $+", nick2, msg2))
|
||||
|
||||
var nick3, msg3: string
|
||||
doAssert scanf("<abcd> ", "<$+> $*", nick3, msg3)
|
||||
doAssert nick3 == "abcd"
|
||||
doAssert msg3 == ""
|
||||
|
||||
@@ -6,8 +6,6 @@ discard """
|
||||
import
|
||||
strutils
|
||||
|
||||
import macros
|
||||
|
||||
template rejectParse(e) =
|
||||
try:
|
||||
discard e
|
||||
@@ -298,6 +296,10 @@ assert "/1/2/3".rfind('0') == -1
|
||||
assert(toHex(100i16, 32) == "00000000000000000000000000000064")
|
||||
assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
|
||||
|
||||
assert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF")
|
||||
assert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF")
|
||||
assert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF")
|
||||
|
||||
assert "".parseHexStr == ""
|
||||
assert "00Ff80".parseHexStr == "\0\xFF\x80"
|
||||
try:
|
||||
|
||||
8
tests/stdlib/tterminal.nim
Normal file
8
tests/stdlib/tterminal.nim
Normal file
@@ -0,0 +1,8 @@
|
||||
discard """
|
||||
action: compile
|
||||
"""
|
||||
|
||||
import terminal, colors
|
||||
|
||||
styledEcho fgColor, colRed, "Test"
|
||||
styledEcho bgColor, colBlue, "Test"
|
||||
18
tests/system/tnim_stacktrace_override.nim
Normal file
18
tests/system/tnim_stacktrace_override.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
cmd: "nim c -d:nimStacktraceOverride $file"
|
||||
output: '''begin
|
||||
Traceback (most recent call last, using override)
|
||||
Error: unhandled exception: stack trace produced [ValueError]
|
||||
'''
|
||||
exitcode: 1
|
||||
"""
|
||||
|
||||
import asyncfutures
|
||||
|
||||
proc main =
|
||||
echo "begin"
|
||||
if true:
|
||||
raise newException(ValueError, "stack trace produced")
|
||||
echo "unreachable"
|
||||
|
||||
main()
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
timeout: "4"
|
||||
timeout: "7"
|
||||
action: "compile"
|
||||
nimout: '''create
|
||||
search
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
import os, uri, strformat
|
||||
import os, uri, strformat, osproc, strutils
|
||||
|
||||
proc exec(cmd: string) =
|
||||
echo "deps.cmd: " & cmd
|
||||
let status = execShellCmd(cmd)
|
||||
doAssert status == 0, cmd
|
||||
|
||||
proc execEx(cmd: string): tuple[output: TaintedString, exitCode: int] =
|
||||
echo "deps.cmd: " & cmd
|
||||
execCmdEx(cmd, {poStdErrToStdOut, poUsePath, poEvalCommand})
|
||||
|
||||
proc isGitRepo(dir: string): bool =
|
||||
# This command is used to get the relative path to the root of the repository.
|
||||
# Using this, we can verify whether a folder is a git repository by checking
|
||||
# whether the command success and if the output is empty.
|
||||
let (output, status) = execEx fmt"git -C {quoteShell(dir)} rev-parse --show-cdup"
|
||||
# On Windows there will be a trailing newline on success, remove it.
|
||||
# The value of a successful call typically won't have a whitespace (it's
|
||||
# usually a series of ../), so we know that it's safe to unconditionally
|
||||
# remove trailing whitespaces from the result.
|
||||
result = status == 0 and output.strip() == ""
|
||||
|
||||
const commitHead* = "HEAD"
|
||||
|
||||
proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, appendRepoName = true) =
|
||||
proc cloneDependency*(destDirBase: string, url: string, commit = commitHead,
|
||||
appendRepoName = true, allowBundled = false) =
|
||||
let destDirBase = destDirBase.absolutePath
|
||||
let p = url.parseUri.path
|
||||
let name = p.splitFile.name
|
||||
@@ -18,5 +34,10 @@ proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, app
|
||||
# note: old code used `destDir / .git` but that wouldn't prevent git clone
|
||||
# from failing
|
||||
exec fmt"git clone -q {url} {destDir2}"
|
||||
exec fmt"git -C {destDir2} fetch -q"
|
||||
exec fmt"git -C {destDir2} checkout -q {commit}"
|
||||
if isGitRepo(destDir):
|
||||
exec fmt"git -C {destDir2} fetch -q"
|
||||
exec fmt"git -C {destDir2} checkout -q {commit}"
|
||||
elif allowBundled:
|
||||
discard "this dependency was bundled with Nim, don't do anything"
|
||||
else:
|
||||
quit "FAILURE: " & destdir & " already exists but is not a git repo"
|
||||
|
||||
Reference in New Issue
Block a user