commit
5ea967d97a
107 changed files with 1137 additions and 2841 deletions
15
changelog.md
15
changelog.md
|
|
@ -1,4 +1,4 @@
|
||||||
## v0.X.X - XX/XX/2018
|
## v0.19.X - XX/XX/2018
|
||||||
|
|
||||||
### Changes affecting backwards compatibility
|
### Changes affecting backwards compatibility
|
||||||
|
|
||||||
|
|
@ -11,9 +11,12 @@
|
||||||
to deal with!
|
to deal with!
|
||||||
- Indexing into a ``cstring`` for the JS target is now mapped
|
- Indexing into a ``cstring`` for the JS target is now mapped
|
||||||
to ``charCodeAt``.
|
to ``charCodeAt``.
|
||||||
- Assignments that would "slice" an object into its supertype are not prevented
|
- Assignments that would "slice" an object into its supertype are now prevented
|
||||||
at runtime. Use ``ref object`` with inheritance rather than ``object`` with
|
at runtime. Use ``ref object`` with inheritance rather than ``object`` with
|
||||||
inheritance to prevent this issue.
|
inheritance to prevent this issue.
|
||||||
|
- The ``not nil`` type annotation now has to be enabled explicitly
|
||||||
|
via ``{.experimental: "notnil"}`` as we are still not pleased with how this
|
||||||
|
feature works with Nim's containers.
|
||||||
|
|
||||||
|
|
||||||
#### Breaking changes in the standard library
|
#### Breaking changes in the standard library
|
||||||
|
|
@ -81,6 +84,14 @@
|
||||||
Imported exceptions can be raised and caught just like Nim exceptions.
|
Imported exceptions can be raised and caught just like Nim exceptions.
|
||||||
More details in language manual.
|
More details in language manual.
|
||||||
|
|
||||||
|
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
||||||
|
these is ``"" / @[]``.
|
||||||
|
- Accessing the binary zero terminator in Nim's native strings
|
||||||
|
is now invalid. Internally a Nim string still has the trailing zero for
|
||||||
|
zero-copy interoperability with ``cstring``. Compile your code with the
|
||||||
|
next switch ``--laxStrings:on`` if you need a transition period.
|
||||||
|
|
||||||
|
|
||||||
### Tool changes
|
### Tool changes
|
||||||
|
|
||||||
- ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed
|
- ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed
|
||||||
|
|
|
||||||
|
|
@ -125,15 +125,15 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
||||||
not compileToCpp(p.module):
|
not compileToCpp(p.module):
|
||||||
result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
|
result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)]
|
||||||
else:
|
else:
|
||||||
result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)]
|
result = "$1->data, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p)]
|
||||||
of tyArray:
|
of tyArray:
|
||||||
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
|
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
|
||||||
of tyPtr, tyRef:
|
of tyPtr, tyRef:
|
||||||
case lastSon(a.t).kind
|
case lastSon(a.t).kind
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
|
result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)]
|
||||||
of tyArray:
|
of tyArray:
|
||||||
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
|
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
|
||||||
else:
|
else:
|
||||||
|
|
@ -143,7 +143,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
|
||||||
proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
|
proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, n.sons[0], a)
|
initLocExpr(p, n.sons[0], a)
|
||||||
result = "$1->data" % [a.rdLoc]
|
result = "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc]
|
||||||
|
|
||||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
|
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = genNilStringLiteral(p.module, n.info)
|
result = genNilStringLiteral(p.module, n.info)
|
||||||
of tyString:
|
of tyString:
|
||||||
|
# with the new semantics for 'nil' strings, we can map "" to nil and
|
||||||
|
# save tons of allocations:
|
||||||
|
#if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info)
|
||||||
|
#else:
|
||||||
result = genStringLiteral(p.module, n)
|
result = genStringLiteral(p.module, n)
|
||||||
else:
|
else:
|
||||||
if n.strVal.isNil: result = rope("NIM_NIL")
|
if n.strVal.isNil: result = rope("NIM_NIL")
|
||||||
|
|
@ -882,7 +886,7 @@ proc genIndexCheck(p: BProc; arr, idx: TLoc) =
|
||||||
rdCharLoc(idx), first, intLiteral(lastOrd(ty)))
|
rdCharLoc(idx), first, intLiteral(lastOrd(ty)))
|
||||||
of tySequence, tyString:
|
of tySequence, tyString:
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
"if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
||||||
rdLoc(idx), rdLoc(arr), lenField(p))
|
rdLoc(idx), rdLoc(arr), lenField(p))
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
|
|
@ -905,13 +909,13 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||||
if ty.kind in {tyRef, tyPtr}:
|
if ty.kind in {tyRef, tyPtr}:
|
||||||
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
|
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
|
||||||
if optBoundsCheck in p.options:
|
if optBoundsCheck in p.options:
|
||||||
if ty.kind == tyString:
|
if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options):
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
|
"if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
|
||||||
rdLoc(b), rdLoc(a), lenField(p))
|
rdLoc(b), rdLoc(a), lenField(p))
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
"if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
||||||
rdLoc(b), rdLoc(a), lenField(p))
|
rdLoc(b), rdLoc(a), lenField(p))
|
||||||
if d.k == locNone: d.storage = OnHeap
|
if d.k == locNone: d.storage = OnHeap
|
||||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||||
|
|
@ -980,10 +984,10 @@ proc genEcho(p: BProc, n: PNode) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
for it in n.sons:
|
for it in n.sons:
|
||||||
if it.skipConv.kind == nkNilLit:
|
if it.skipConv.kind == nkNilLit:
|
||||||
add(args, ", \"nil\"")
|
add(args, ", \"\"")
|
||||||
else:
|
else:
|
||||||
initLocExpr(p, it, a)
|
initLocExpr(p, it, a)
|
||||||
addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
addf(args, ", $1? ($1)->data:\"\"", [rdLoc(a)])
|
||||||
p.module.includeHeader("<base/log.h>")
|
p.module.includeHeader("<base/log.h>")
|
||||||
linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args)
|
linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1034,7 +1038,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
|
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
inc(L, len(e.sons[i + 1].strVal))
|
inc(L, len(e.sons[i + 1].strVal))
|
||||||
else:
|
else:
|
||||||
addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
|
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
|
||||||
add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
|
add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
|
||||||
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
|
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
|
||||||
add(p.s(cpsStmts), appends)
|
add(p.s(cpsStmts), appends)
|
||||||
|
|
@ -1073,7 +1077,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
|
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
inc(L, len(e.sons[i + 2].strVal))
|
inc(L, len(e.sons[i + 2].strVal))
|
||||||
else:
|
else:
|
||||||
addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
|
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
|
||||||
add(appends, rfmt(p.module, "#appendString($1, $2);$n",
|
add(appends, rfmt(p.module, "#appendString($1, $2);$n",
|
||||||
rdLoc(dest), rdLoc(a)))
|
rdLoc(dest), rdLoc(a)))
|
||||||
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
|
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
|
||||||
|
|
@ -1086,17 +1090,17 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
||||||
# seq->data[seq->len-1] = x;
|
# seq->data[seq->len-1] = x;
|
||||||
let seqAppendPattern = if not p.module.compileToCpp:
|
let seqAppendPattern = if not p.module.compileToCpp:
|
||||||
"$1 = ($2) #incrSeqV2(&($1)->Sup, sizeof($3));$n"
|
"$1 = ($2) #incrSeqV3(&($1)->Sup, $3);$n"
|
||||||
else:
|
else:
|
||||||
"$1 = ($2) #incrSeqV2($1, sizeof($3));$n"
|
"$1 = ($2) #incrSeqV3($1, $3);$n"
|
||||||
var a, b, dest, tmpL: TLoc
|
var a, b, dest, tmpL: TLoc
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
let bt = skipTypes(e.sons[2].typ, {tyVar})
|
let seqType = skipTypes(e.sons[1].typ, {tyVar})
|
||||||
lineCg(p, cpsStmts, seqAppendPattern, [
|
lineCg(p, cpsStmts, seqAppendPattern, [
|
||||||
rdLoc(a),
|
rdLoc(a),
|
||||||
getTypeDesc(p.module, e.sons[1].typ),
|
getTypeDesc(p.module, e.sons[1].typ),
|
||||||
getTypeDesc(p.module, bt)])
|
genTypeInfo(p.module, seqType, e.info)])
|
||||||
#if bt != b.t:
|
#if bt != b.t:
|
||||||
# echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
|
# echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
|
||||||
initLoc(dest, locExpr, e.sons[2], OnHeap)
|
initLoc(dest, locExpr, e.sons[2], OnHeap)
|
||||||
|
|
@ -1417,7 +1421,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
|
putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
putIntoDest(p, b, e,
|
putIntoDest(p, b, e,
|
||||||
"$1->data, $1->$2" % [rdLoc(a), lenField(p)], a.storage)
|
"$1->data, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)], a.storage)
|
||||||
of tyArray:
|
of tyArray:
|
||||||
putIntoDest(p, b, e,
|
putIntoDest(p, b, e,
|
||||||
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage)
|
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage)
|
||||||
|
|
@ -1500,13 +1504,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
let t = skipTypes(e.sons[1].typ, {tyVar})
|
let t = skipTypes(e.sons[1].typ, {tyVar})
|
||||||
let setLenPattern = if not p.module.compileToCpp:
|
let setLenPattern = if not p.module.compileToCpp:
|
||||||
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
|
"$1 = ($3) #setLengthSeqV2(&($1)->Sup, $4, $2);$n"
|
||||||
else:
|
else:
|
||||||
"$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n"
|
"$1 = ($3) #setLengthSeqV2($1, $4, $2);$n"
|
||||||
|
|
||||||
lineCg(p, cpsStmts, setLenPattern, [
|
lineCg(p, cpsStmts, setLenPattern, [
|
||||||
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
||||||
getTypeDesc(p.module, t.skipTypes(abstractInst).sons[0])])
|
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
|
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
|
|
@ -1740,7 +1744,7 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
|
||||||
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
|
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, n.sons[0], a)
|
initLocExpr(p, n.sons[0], a)
|
||||||
putIntoDest(p, d, n, "$1->data" % [rdLoc(a)],
|
putIntoDest(p, d, n, "($1 ? $1->data : (NCSTRING)\"\")" % [rdLoc(a)],
|
||||||
a.storage)
|
a.storage)
|
||||||
|
|
||||||
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
|
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
|
|
@ -1755,16 +1759,14 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var x: TLoc
|
var x: TLoc
|
||||||
var a = e.sons[1]
|
var a = e.sons[1]
|
||||||
var b = e.sons[2]
|
var b = e.sons[2]
|
||||||
if (a.kind == nkNilLit) or (b.kind == nkNilLit):
|
if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
|
||||||
binaryExpr(p, e, d, "($1 == $2)")
|
|
||||||
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
|
|
||||||
initLocExpr(p, e.sons[2], x)
|
initLocExpr(p, e.sons[2], x)
|
||||||
putIntoDest(p, d, e,
|
putIntoDest(p, d, e,
|
||||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||||
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
|
elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
|
||||||
initLocExpr(p, e.sons[1], x)
|
initLocExpr(p, e.sons[1], x)
|
||||||
putIntoDest(p, d, e,
|
putIntoDest(p, d, e,
|
||||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, e, d, "#eqStrings($1, $2)")
|
binaryExpr(p, e, d, "#eqStrings($1, $2)")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
|
|
||||||
const
|
const
|
||||||
HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
|
HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
|
||||||
|
"Compiled at $4 $5\n" &
|
||||||
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
|
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -68,7 +69,8 @@ const
|
||||||
|
|
||||||
proc getCommandLineDesc(): string =
|
proc getCommandLineDesc(): string =
|
||||||
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
|
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name]) & Usage
|
CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
|
||||||
|
Usage
|
||||||
|
|
||||||
proc helpOnError(pass: TCmdLinePass) =
|
proc helpOnError(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
|
|
@ -79,7 +81,8 @@ proc writeAdvancedUsage(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name]) & AdvancedUsage,
|
CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
|
||||||
|
AdvancedUsage,
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
msgQuit(0)
|
msgQuit(0)
|
||||||
|
|
||||||
|
|
@ -87,7 +90,8 @@ proc writeFullhelp(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name]) & Usage & AdvancedUsage,
|
CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
|
||||||
|
Usage & AdvancedUsage,
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
msgQuit(0)
|
msgQuit(0)
|
||||||
|
|
||||||
|
|
@ -95,7 +99,7 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name]),
|
CPU[platform.hostCPU].name, CompileDate, CompileTime]),
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
|
|
||||||
const gitHash = gorge("git log -n 1 --format=%H").strip
|
const gitHash = gorge("git log -n 1 --format=%H").strip
|
||||||
|
|
@ -188,11 +192,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||||
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
|
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
|
||||||
else: invalidCmdLineOption(pass, orig, info)
|
else: invalidCmdLineOption(pass, orig, info)
|
||||||
if state == wHint:
|
if state == wHint:
|
||||||
var x = findStr(msgs.HintsToStr, id)
|
let x = findStr(msgs.HintsToStr, id)
|
||||||
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
||||||
else: localError(info, "unknown hint: " & id)
|
else: localError(info, "unknown hint: " & id)
|
||||||
else:
|
else:
|
||||||
var x = findStr(msgs.WarningsToStr, id)
|
let x = findStr(msgs.WarningsToStr, id)
|
||||||
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
||||||
else: localError(info, "unknown warning: " & id)
|
else: localError(info, "unknown warning: " & id)
|
||||||
case substr(arg, i).normalize
|
case substr(arg, i).normalize
|
||||||
|
|
@ -499,6 +503,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
undefSymbol("nimOldNewlines")
|
undefSymbol("nimOldNewlines")
|
||||||
else:
|
else:
|
||||||
localError(info, errOnOrOffExpectedButXFound, arg)
|
localError(info, errOnOrOffExpectedButXFound, arg)
|
||||||
|
of "laxstrings": processOnOffSwitch({optLaxStrings}, arg, pass, info)
|
||||||
of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
|
of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
|
||||||
of "floatchecks":
|
of "floatchecks":
|
||||||
processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
|
processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ proc countDefinedSymbols*(): int =
|
||||||
|
|
||||||
proc initDefines*() =
|
proc initDefines*() =
|
||||||
gSymbols = newStringTable(modeStyleInsensitive)
|
gSymbols = newStringTable(modeStyleInsensitive)
|
||||||
defineSymbol("nimrod") # 'nimrod' is always defined
|
|
||||||
# for bootstrapping purposes and old code:
|
# for bootstrapping purposes and old code:
|
||||||
defineSymbol("nimhygiene")
|
defineSymbol("nimhygiene")
|
||||||
defineSymbol("niminheritable")
|
defineSymbol("niminheritable")
|
||||||
|
|
@ -115,3 +114,6 @@ proc initDefines*() =
|
||||||
defineSymbol("nimHasNilChecks")
|
defineSymbol("nimHasNilChecks")
|
||||||
defineSymbol("nimSymKind")
|
defineSymbol("nimSymKind")
|
||||||
defineSymbol("nimVmEqIdent")
|
defineSymbol("nimVmEqIdent")
|
||||||
|
defineSymbol("nimNoNil")
|
||||||
|
defineSymbol("nimNoZeroTerminator")
|
||||||
|
defineSymbol("nimNotNil")
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ proc newLine(p: var TTmplParser) =
|
||||||
|
|
||||||
proc scanPar(p: var TTmplParser, d: int) =
|
proc scanPar(p: var TTmplParser, d: int) =
|
||||||
var i = d
|
var i = d
|
||||||
while true:
|
let hi = p.x.len - 1
|
||||||
|
while i <= hi:
|
||||||
case p.x[i]
|
case p.x[i]
|
||||||
of '\0': break
|
of '\0': break
|
||||||
of '(': inc(p.par)
|
of '(': inc(p.par)
|
||||||
|
|
|
||||||
|
|
@ -165,13 +165,12 @@ proc isKeyword*(kind: TTokType): bool =
|
||||||
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
|
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
|
||||||
|
|
||||||
proc isNimIdentifier*(s: string): bool =
|
proc isNimIdentifier*(s: string): bool =
|
||||||
if s[0] in SymStartChars:
|
let sLen = s.len
|
||||||
|
if sLen > 0 and s[0] in SymStartChars:
|
||||||
var i = 1
|
var i = 1
|
||||||
var sLen = s.len
|
|
||||||
while i < sLen:
|
while i < sLen:
|
||||||
if s[i] == '_':
|
if s[i] == '_': inc(i)
|
||||||
inc(i)
|
if i < sLen and s[i] notin SymChars: return
|
||||||
if s[i] notin SymChars: return
|
|
||||||
inc(i)
|
inc(i)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
|
@ -311,12 +310,12 @@ template tokenEndPrevious(tok, pos) =
|
||||||
# We need to parse the largest uint literal without overflow checks
|
# We need to parse the largest uint literal without overflow checks
|
||||||
proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
||||||
var i = start
|
var i = start
|
||||||
if s[i] in {'0'..'9'}:
|
if i < s.len and s[i] in {'0'..'9'}:
|
||||||
b = 0
|
b = 0
|
||||||
while s[i] in {'0'..'9'}:
|
while i < s.len and s[i] in {'0'..'9'}:
|
||||||
b = b * 10 + (ord(s[i]) - ord('0'))
|
b = b * 10 + (ord(s[i]) - ord('0'))
|
||||||
inc(i)
|
inc(i)
|
||||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
result = i - start
|
result = i - start
|
||||||
{.pop.} # overflowChecks
|
{.pop.} # overflowChecks
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ type
|
||||||
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
||||||
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||||
warnFieldXNotSupported, warnCommentXIgnored,
|
warnFieldXNotSupported, warnCommentXIgnored,
|
||||||
warnNilStatement, warnTypelessParam,
|
warnTypelessParam,
|
||||||
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
|
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
|
||||||
warnEachIdentIsTuple, warnShadowIdent,
|
warnEachIdentIsTuple, warnShadowIdent,
|
||||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||||
|
|
@ -400,7 +400,6 @@ const
|
||||||
warnLanguageXNotSupported: "language \'$1\' not supported",
|
warnLanguageXNotSupported: "language \'$1\' not supported",
|
||||||
warnFieldXNotSupported: "field \'$1\' not supported",
|
warnFieldXNotSupported: "field \'$1\' not supported",
|
||||||
warnCommentXIgnored: "comment \'$1\' ignored",
|
warnCommentXIgnored: "comment \'$1\' ignored",
|
||||||
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead",
|
|
||||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
||||||
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
||||||
warnWriteToForeignHeap: "write to foreign heap",
|
warnWriteToForeignHeap: "write to foreign heap",
|
||||||
|
|
@ -451,7 +450,7 @@ const
|
||||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||||
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||||
"LanguageXNotSupported", "FieldXNotSupported",
|
"LanguageXNotSupported", "FieldXNotSupported",
|
||||||
"CommentXIgnored", "NilStmt",
|
"CommentXIgnored",
|
||||||
"TypelessParam", "UseBase", "WriteToForeignHeap",
|
"TypelessParam", "UseBase", "WriteToForeignHeap",
|
||||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||||
|
|
@ -474,6 +473,10 @@ const
|
||||||
hintMin* = hintSuccess
|
hintMin* = hintSuccess
|
||||||
hintMax* = high(TMsgKind)
|
hintMax* = high(TMsgKind)
|
||||||
|
|
||||||
|
static:
|
||||||
|
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
|
||||||
|
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
|
||||||
|
|
||||||
type
|
type
|
||||||
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
||||||
TNoteKinds* = set[TNoteKind]
|
TNoteKinds* = set[TNoteKind]
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ proc mainCommand =
|
||||||
compileProject(newModuleGraph(), newIdentCache())
|
compileProject(newModuleGraph(), newIdentCache())
|
||||||
pretty.overwriteFiles()
|
pretty.overwriteFiles()
|
||||||
|
|
||||||
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
proc processCmdLine*(pass: TCmdLinePass, cmd: string, config: ConfigRef) =
|
||||||
var p = parseopt.initOptParser(cmd)
|
var p = parseopt.initOptParser(cmd)
|
||||||
var argsCount = 0
|
var argsCount = 0
|
||||||
gOnlyMainfile = true
|
gOnlyMainfile = true
|
||||||
|
|
@ -76,16 +76,16 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
of "wholeproject": gOnlyMainfile = false
|
of "wholeproject": gOnlyMainfile = false
|
||||||
of "besteffort": msgs.gErrorMax = high(int) # don't stop after first error
|
of "besteffort": msgs.gErrorMax = high(int) # don't stop after first error
|
||||||
else:
|
else:
|
||||||
processSwitch(pass, p)
|
processSwitch(pass, p, config)
|
||||||
of cmdArgument:
|
of cmdArgument:
|
||||||
options.gProjectName = unixToNativePath(p.key)
|
options.gProjectName = unixToNativePath(p.key)
|
||||||
# if processArgument(pass, p, argsCount): break
|
# if processArgument(pass, p, argsCount): break
|
||||||
|
|
||||||
proc handleCmdLine() =
|
proc handleCmdLine(config: ConfigRef) =
|
||||||
if paramCount() == 0:
|
if paramCount() == 0:
|
||||||
stdout.writeLine(Usage)
|
stdout.writeLine(Usage)
|
||||||
else:
|
else:
|
||||||
processCmdLine(passCmd1, "")
|
processCmdLine(passCmd1, "", config)
|
||||||
if gProjectName != "":
|
if gProjectName != "":
|
||||||
try:
|
try:
|
||||||
gProjectFull = canonicalizePath(gProjectName)
|
gProjectFull = canonicalizePath(gProjectName)
|
||||||
|
|
@ -96,11 +96,11 @@ proc handleCmdLine() =
|
||||||
gProjectName = p.name
|
gProjectName = p.name
|
||||||
else:
|
else:
|
||||||
gProjectPath = getCurrentDir()
|
gProjectPath = getCurrentDir()
|
||||||
loadConfigs(DefaultConfig) # load all config files
|
loadConfigs(DefaultConfig, config) # load all config files
|
||||||
# now process command line arguments again, because some options in the
|
# now process command line arguments again, because some options in the
|
||||||
# command line can overwite the config file's settings
|
# command line can overwite the config file's settings
|
||||||
extccomp.initVars()
|
extccomp.initVars()
|
||||||
processCmdLine(passCmd2, "")
|
processCmdLine(passCmd2, "", config)
|
||||||
mainCommand()
|
mainCommand()
|
||||||
|
|
||||||
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||||
|
|
@ -108,4 +108,4 @@ when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||||
|
|
||||||
condsyms.initDefines()
|
condsyms.initDefines()
|
||||||
defineSymbol "nimfix"
|
defineSymbol "nimfix"
|
||||||
handleCmdline()
|
handleCmdline newConfigRef()
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ type # please make sure we have under 32 options
|
||||||
# evaluation
|
# evaluation
|
||||||
optPatterns, # en/disable pattern matching
|
optPatterns, # en/disable pattern matching
|
||||||
optMemTracker,
|
optMemTracker,
|
||||||
optHotCodeReloading
|
optHotCodeReloading,
|
||||||
|
optLaxStrings
|
||||||
|
|
||||||
TOptions* = set[TOption]
|
TOptions* = set[TOption]
|
||||||
TGlobalOption* = enum # **keep binary compatible**
|
TGlobalOption* = enum # **keep binary compatible**
|
||||||
|
|
@ -108,7 +109,8 @@ type
|
||||||
dotOperators,
|
dotOperators,
|
||||||
callOperator,
|
callOperator,
|
||||||
parallel,
|
parallel,
|
||||||
destructor
|
destructor,
|
||||||
|
notnil
|
||||||
|
|
||||||
ConfigRef* = ref object ## eventually all global configuration should be moved here
|
ConfigRef* = ref object ## eventually all global configuration should be moved here
|
||||||
cppDefines*: HashSet[string]
|
cppDefines*: HashSet[string]
|
||||||
|
|
|
||||||
|
|
@ -175,10 +175,11 @@ proc put(g: var TSrcGen, kind: TTokType, s: string) =
|
||||||
proc putComment(g: var TSrcGen, s: string) =
|
proc putComment(g: var TSrcGen, s: string) =
|
||||||
if s.isNil: return
|
if s.isNil: return
|
||||||
var i = 0
|
var i = 0
|
||||||
|
let hi = len(s) - 1
|
||||||
var isCode = (len(s) >= 2) and (s[1] != ' ')
|
var isCode = (len(s) >= 2) and (s[1] != ' ')
|
||||||
var ind = g.lineLen
|
var ind = g.lineLen
|
||||||
var com = "## "
|
var com = "## "
|
||||||
while true:
|
while i <= hi:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '\0':
|
of '\0':
|
||||||
break
|
break
|
||||||
|
|
@ -201,12 +202,12 @@ proc putComment(g: var TSrcGen, s: string) =
|
||||||
# gets too long:
|
# gets too long:
|
||||||
# compute length of the following word:
|
# compute length of the following word:
|
||||||
var j = i
|
var j = i
|
||||||
while s[j] > ' ': inc(j)
|
while j <= hi and s[j] > ' ': inc(j)
|
||||||
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
||||||
put(g, tkComment, com)
|
put(g, tkComment, com)
|
||||||
optNL(g, ind)
|
optNL(g, ind)
|
||||||
com = "## "
|
com = "## "
|
||||||
while s[i] > ' ':
|
while i <= hi and s[i] > ' ':
|
||||||
add(com, s[i])
|
add(com, s[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
put(g, tkComment, com)
|
put(g, tkComment, com)
|
||||||
|
|
@ -215,8 +216,9 @@ proc putComment(g: var TSrcGen, s: string) =
|
||||||
proc maxLineLength(s: string): int =
|
proc maxLineLength(s: string): int =
|
||||||
if s.isNil: return 0
|
if s.isNil: return 0
|
||||||
var i = 0
|
var i = 0
|
||||||
|
let hi = len(s) - 1
|
||||||
var lineLen = 0
|
var lineLen = 0
|
||||||
while true:
|
while i <= hi:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '\0':
|
of '\0':
|
||||||
break
|
break
|
||||||
|
|
@ -235,7 +237,7 @@ proc maxLineLength(s: string): int =
|
||||||
|
|
||||||
proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
|
proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
|
||||||
var i = 0
|
var i = 0
|
||||||
var hi = len(s) - 1
|
let hi = len(s) - 1
|
||||||
var str = ""
|
var str = ""
|
||||||
while i <= hi:
|
while i <= hi:
|
||||||
case s[i]
|
case s[i]
|
||||||
|
|
@ -1064,6 +1066,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
if n.len > 1:
|
if n.len > 1:
|
||||||
let opr = if n[0].kind == nkIdent: n[0].ident
|
let opr = if n[0].kind == nkIdent: n[0].ident
|
||||||
elif n[0].kind == nkSym: n[0].sym.name
|
elif n[0].kind == nkSym: n[0].sym.name
|
||||||
|
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
|
||||||
else: nil
|
else: nil
|
||||||
if n[1].kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
if n[1].kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
|
|
|
||||||
|
|
@ -188,11 +188,11 @@ iterator leaves*(r: Rope): string =
|
||||||
var stack = @[r]
|
var stack = @[r]
|
||||||
while stack.len > 0:
|
while stack.len > 0:
|
||||||
var it = stack.pop
|
var it = stack.pop
|
||||||
while isNil(it.data):
|
while it.left != nil:
|
||||||
|
assert it.right != nil
|
||||||
stack.add(it.right)
|
stack.add(it.right)
|
||||||
it = it.left
|
it = it.left
|
||||||
assert(it != nil)
|
assert(it != nil)
|
||||||
assert(it.data != nil)
|
|
||||||
yield it.data
|
yield it.data
|
||||||
|
|
||||||
iterator items*(r: Rope): char =
|
iterator items*(r: Rope): char =
|
||||||
|
|
@ -251,7 +251,7 @@ proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||||
while true:
|
while true:
|
||||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||||
inc(i)
|
inc(i)
|
||||||
if frmt[i] notin {'0'..'9'}: break
|
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
|
||||||
num = j
|
num = j
|
||||||
if j > high(args) + 1:
|
if j > high(args) + 1:
|
||||||
errorHandler(rInvalidFormatStr, $(j))
|
errorHandler(rInvalidFormatStr, $(j))
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,9 @@ proc commonType*(x, y: PType): PType =
|
||||||
if a.kind in {tyRef, tyPtr}:
|
if a.kind in {tyRef, tyPtr}:
|
||||||
k = a.kind
|
k = a.kind
|
||||||
if b.kind != a.kind: return x
|
if b.kind != a.kind: return x
|
||||||
a = a.lastSon
|
# bug #7601, array construction of ptr generic
|
||||||
b = b.lastSon
|
a = a.lastSon.skipTypes({tyGenericInst})
|
||||||
|
b = b.lastSon.skipTypes({tyGenericInst})
|
||||||
if a.kind == tyObject and b.kind == tyObject:
|
if a.kind == tyObject and b.kind == tyObject:
|
||||||
result = commonSuperclass(a, b)
|
result = commonSuperclass(a, b)
|
||||||
# this will trigger an error later:
|
# this will trigger an error later:
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
filter: TSymKinds,
|
filter: TSymKinds,
|
||||||
best, alt: var TCandidate,
|
best, alt: var TCandidate,
|
||||||
errors: var CandidateErrors,
|
errors: var CandidateErrors,
|
||||||
diagnosticsFlag = false) =
|
diagnosticsFlag: bool,
|
||||||
|
errorsEnabled: bool) =
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
var sym = initOverloadIter(o, c, headSymbol)
|
var sym = initOverloadIter(o, c, headSymbol)
|
||||||
var scope = o.lastOverloadScope
|
var scope = o.lastOverloadScope
|
||||||
|
|
@ -68,6 +69,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
# This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
|
# This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
|
||||||
let counterInitial = c.currentScope.symbols.counter
|
let counterInitial = c.currentScope.symbols.counter
|
||||||
var syms: seq[tuple[s: PSym, scope: int]]
|
var syms: seq[tuple[s: PSym, scope: int]]
|
||||||
|
var noSyms = true
|
||||||
var nextSymIndex = 0
|
var nextSymIndex = 0
|
||||||
while sym != nil:
|
while sym != nil:
|
||||||
if sym.kind in filter:
|
if sym.kind in filter:
|
||||||
|
|
@ -102,7 +104,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
var cmp = cmpCandidates(best, z)
|
var cmp = cmpCandidates(best, z)
|
||||||
if cmp < 0: best = z # x is better than the best so far
|
if cmp < 0: best = z # x is better than the best so far
|
||||||
elif cmp == 0: alt = z # x is as good as the best so far
|
elif cmp == 0: alt = z # x is as good as the best so far
|
||||||
elif errors != nil or z.diagnostics != nil:
|
elif errorsEnabled or z.diagnosticsEnabled:
|
||||||
errors.safeAdd(CandidateError(
|
errors.safeAdd(CandidateError(
|
||||||
sym: sym,
|
sym: sym,
|
||||||
unmatchedVarParam: int z.mutabilityProblem,
|
unmatchedVarParam: int z.mutabilityProblem,
|
||||||
|
|
@ -113,7 +115,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
# before any further candidate init and compare. SLOW, but rare case.
|
# before any further candidate init and compare. SLOW, but rare case.
|
||||||
syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
|
syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
|
||||||
best, alt, o, diagnosticsFlag)
|
best, alt, o, diagnosticsFlag)
|
||||||
if syms == nil:
|
noSyms = false
|
||||||
|
if noSyms:
|
||||||
sym = nextOverloadIter(o, c, headSymbol)
|
sym = nextOverloadIter(o, c, headSymbol)
|
||||||
scope = o.lastOverloadScope
|
scope = o.lastOverloadScope
|
||||||
elif nextSymIndex < syms.len:
|
elif nextSymIndex < syms.len:
|
||||||
|
|
@ -206,7 +209,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
if errorOutputs == {}:
|
if errorOutputs == {}:
|
||||||
# fail fast:
|
# fail fast:
|
||||||
globalError(n.info, errTypeMismatch, "")
|
globalError(n.info, errTypeMismatch, "")
|
||||||
if errors.isNil or errors.len == 0:
|
if errors.len == 0:
|
||||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -227,7 +230,8 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||||
if symx.kind in routineKinds:
|
if symx.kind in routineKinds:
|
||||||
errors.add(CandidateError(sym: symx,
|
errors.add(CandidateError(sym: symx,
|
||||||
unmatchedVarParam: 0, firstMismatch: 0,
|
unmatchedVarParam: 0, firstMismatch: 0,
|
||||||
diagnostics: nil))
|
diagnostics: nil,
|
||||||
|
enabled: false))
|
||||||
symx = nextOverloadIter(o, c, headSymbol)
|
symx = nextOverloadIter(o, c, headSymbol)
|
||||||
if errors.len == 0:
|
if errors.len == 0:
|
||||||
localError(n.info, "could not resolve: " & $n)
|
localError(n.info, "could not resolve: " & $n)
|
||||||
|
|
@ -236,7 +240,8 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||||
|
|
||||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
filter: TSymKinds, flags: TExprFlags,
|
filter: TSymKinds, flags: TExprFlags,
|
||||||
errors: var CandidateErrors): TCandidate =
|
errors: var CandidateErrors,
|
||||||
|
errorsEnabled: bool): TCandidate =
|
||||||
var initialBinding: PNode
|
var initialBinding: PNode
|
||||||
var alt: TCandidate
|
var alt: TCandidate
|
||||||
var f = n.sons[0]
|
var f = n.sons[0]
|
||||||
|
|
@ -249,7 +254,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
|
|
||||||
template pickBest(headSymbol) =
|
template pickBest(headSymbol) =
|
||||||
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||||
filter, result, alt, errors, efExplain in flags)
|
filter, result, alt, errors, efExplain in flags,
|
||||||
|
errorsEnabled)
|
||||||
pickBest(f)
|
pickBest(f)
|
||||||
|
|
||||||
let overloadsState = result.state
|
let overloadsState = result.state
|
||||||
|
|
@ -423,9 +429,8 @@ proc tryDeref(n: PNode): PNode =
|
||||||
|
|
||||||
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||||
filter: TSymKinds, flags: TExprFlags): PNode =
|
filter: TSymKinds, flags: TExprFlags): PNode =
|
||||||
var errors: CandidateErrors = if efExplain in flags: @[]
|
var errors: CandidateErrors = if efExplain in flags: @[] else: nil
|
||||||
else: nil
|
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
|
||||||
var r = resolveOverloads(c, n, nOrig, filter, flags, errors)
|
|
||||||
if r.state == csMatch:
|
if r.state == csMatch:
|
||||||
# this may be triggered, when the explain pragma is used
|
# this may be triggered, when the explain pragma is used
|
||||||
if errors.len > 0:
|
if errors.len > 0:
|
||||||
|
|
@ -443,7 +448,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||||
# into sigmatch with hidden conversion produced there
|
# into sigmatch with hidden conversion produced there
|
||||||
#
|
#
|
||||||
n.sons[1] = n.sons[1].tryDeref
|
n.sons[1] = n.sons[1].tryDeref
|
||||||
var r = resolveOverloads(c, n, nOrig, filter, flags, errors)
|
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
|
||||||
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
||||||
else:
|
else:
|
||||||
# get rid of the deref again for a better error message:
|
# get rid of the deref again for a better error message:
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ type
|
||||||
# to the user.
|
# to the user.
|
||||||
efWantStmt, efAllowStmt, efDetermineType, efExplain,
|
efWantStmt, efAllowStmt, efDetermineType, efExplain,
|
||||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
|
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
|
||||||
efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo,
|
efNoEvaluateGeneric, efInCall, efFromHlo
|
||||||
|
|
||||||
TExprFlags* = set[TExprFlag]
|
TExprFlags* = set[TExprFlag]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
else:
|
else:
|
||||||
if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
|
|
||||||
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
||||||
|
|
||||||
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
|
|
@ -63,8 +62,6 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
localError(n.info, errExprXHasNoType,
|
localError(n.info, errExprXHasNoType,
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
else:
|
|
||||||
semProcvarCheck(c, result)
|
|
||||||
|
|
||||||
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
result = symChoice(c, n, s, scClosed)
|
result = symChoice(c, n, s, scClosed)
|
||||||
|
|
@ -308,7 +305,9 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
maybeLiftType(t2, c, n.info)
|
maybeLiftType(t2, c, n.info)
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(c, m, t2)
|
initCandidate(c, m, t2)
|
||||||
if efExplain in flags: m.diagnostics = @[]
|
if efExplain in flags:
|
||||||
|
m.diagnostics = @[]
|
||||||
|
m.diagnosticsEnabled = true
|
||||||
let match = typeRel(m, t2, t1) >= isSubtype # isNone
|
let match = typeRel(m, t2, t1) >= isSubtype # isNone
|
||||||
result = newIntNode(nkIntLit, ord(match))
|
result = newIntNode(nkIntLit, ord(match))
|
||||||
|
|
||||||
|
|
@ -540,7 +539,6 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||||
# we need to recurse explicitly here as converters can create nested
|
# we need to recurse explicitly here as converters can create nested
|
||||||
# calls and then they wouldn't be analysed otherwise
|
# calls and then they wouldn't be analysed otherwise
|
||||||
analyseIfAddressTakenInCall(c, n.sons[i])
|
analyseIfAddressTakenInCall(c, n.sons[i])
|
||||||
semProcvarCheck(c, n.sons[i])
|
|
||||||
if i < sonsLen(t) and
|
if i < sonsLen(t) and
|
||||||
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
|
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
|
||||||
if n.sons[i].kind != nkHiddenAddr:
|
if n.sons[i].kind != nkHiddenAddr:
|
||||||
|
|
@ -1245,7 +1243,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
# make sure we don't evaluate generic macros/templates
|
# make sure we don't evaluate generic macros/templates
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0],
|
n.sons[0] = semExprWithType(c, n.sons[0],
|
||||||
{efNoProcvarCheck, efNoEvaluateGeneric})
|
{efNoEvaluateGeneric})
|
||||||
let arr = skipTypes(n.sons[0].typ, {tyGenericInst,
|
let arr = skipTypes(n.sons[0].typ, {tyGenericInst,
|
||||||
tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
|
tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
|
||||||
case arr.kind
|
case arr.kind
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
import
|
import
|
||||||
strutils, options, ast, astalgo, trees, treetab, nimsets, times,
|
strutils, options, ast, astalgo, trees, treetab, nimsets, times,
|
||||||
nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
|
nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
|
||||||
commands, magicsys, saturate
|
commands, magicsys
|
||||||
|
|
||||||
proc getConstExpr*(m: PSym, n: PNode): PNode
|
proc getConstExpr*(m: PSym, n: PNode): PNode
|
||||||
# evaluates the constant expression or returns nil if it is no constant
|
# evaluates the constant expression or returns nil if it is no constant
|
||||||
|
|
@ -24,6 +24,63 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode
|
||||||
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
|
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
|
||||||
proc newStrNodeT*(strVal: string, n: PNode): PNode
|
proc newStrNodeT*(strVal: string, n: PNode): PNode
|
||||||
|
|
||||||
|
proc checkInRange(n: PNode, res: BiggestInt): bool =
|
||||||
|
if res in firstOrd(n.typ)..lastOrd(n.typ):
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc foldAdd(a, b: BiggestInt, n: PNode): PNode =
|
||||||
|
let res = a +% b
|
||||||
|
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
|
||||||
|
checkInRange(n, res):
|
||||||
|
result = newIntNodeT(res, n)
|
||||||
|
|
||||||
|
proc foldSub*(a, b: BiggestInt, n: PNode): PNode =
|
||||||
|
let res = a -% b
|
||||||
|
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
|
||||||
|
checkInRange(n, res):
|
||||||
|
result = newIntNodeT(res, n)
|
||||||
|
|
||||||
|
proc foldAbs*(a: BiggestInt, n: PNode): PNode =
|
||||||
|
if a != firstOrd(n.typ):
|
||||||
|
result = newIntNodeT(a, n)
|
||||||
|
|
||||||
|
proc foldMod*(a, b: BiggestInt, n: PNode): PNode =
|
||||||
|
if b != 0'i64:
|
||||||
|
result = newIntNodeT(a mod b, n)
|
||||||
|
|
||||||
|
proc foldModU*(a, b: BiggestInt, n: PNode): PNode =
|
||||||
|
if b != 0'i64:
|
||||||
|
result = newIntNodeT(a %% b, n)
|
||||||
|
|
||||||
|
proc foldDiv*(a, b: BiggestInt, n: PNode): PNode =
|
||||||
|
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
|
||||||
|
result = newIntNodeT(a div b, n)
|
||||||
|
|
||||||
|
proc foldDivU*(a, b: BiggestInt, n: PNode): PNode =
|
||||||
|
if b != 0'i64:
|
||||||
|
result = newIntNodeT(a /% b, n)
|
||||||
|
|
||||||
|
proc foldMul*(a, b: BiggestInt, n: PNode): PNode =
|
||||||
|
let res = a *% b
|
||||||
|
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
|
||||||
|
let resAsFloat = toBiggestFloat(res)
|
||||||
|
|
||||||
|
# Fast path for normal case: small multiplicands, and no info
|
||||||
|
# is lost in either method.
|
||||||
|
if resAsFloat == floatProd and checkInRange(n, res):
|
||||||
|
return newIntNodeT(res, n)
|
||||||
|
|
||||||
|
# Somebody somewhere lost info. Close enough, or way off? Note
|
||||||
|
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
|
||||||
|
# The difference either is or isn't significant compared to the
|
||||||
|
# true value (of which floatProd is a good approximation).
|
||||||
|
|
||||||
|
# abs(diff)/abs(prod) <= 1/32 iff
|
||||||
|
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
|
||||||
|
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
|
||||||
|
checkInRange(n, res):
|
||||||
|
return newIntNodeT(res, n)
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
|
proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
|
||||||
|
|
@ -172,23 +229,22 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
|
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
|
||||||
of mToFloat, mToBiggestFloat:
|
of mToFloat, mToBiggestFloat:
|
||||||
result = newFloatNodeT(toFloat(int(getInt(a))), n)
|
result = newFloatNodeT(toFloat(int(getInt(a))), n)
|
||||||
|
# XXX: Hides overflow/underflow
|
||||||
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
|
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
|
||||||
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
|
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
|
||||||
of mAbsI:
|
of mAbsI: result = foldAbs(getInt(a), n)
|
||||||
if getInt(a) >= 0: result = a
|
|
||||||
else: result = newIntNodeT(- getInt(a), n)
|
|
||||||
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
|
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
|
||||||
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
|
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
|
||||||
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
|
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
|
||||||
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
|
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
|
||||||
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
|
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
|
||||||
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
|
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
|
||||||
of mUnaryLt: result = newIntNodeT(getOrdValue(a) |-| 1, n)
|
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n)
|
||||||
of mSucc: result = newIntNodeT(getOrdValue(a) |+| getInt(b), n)
|
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n)
|
||||||
of mPred: result = newIntNodeT(getOrdValue(a) |-| getInt(b), n)
|
of mPred: result = foldSub(getOrdValue(a), getInt(b), n)
|
||||||
of mAddI: result = newIntNodeT(getInt(a) |+| getInt(b), n)
|
of mAddI: result = foldAdd(getInt(a), getInt(b), n)
|
||||||
of mSubI: result = newIntNodeT(getInt(a) |-| getInt(b), n)
|
of mSubI: result = foldSub(getInt(a), getInt(b), n)
|
||||||
of mMulI: result = newIntNodeT(getInt(a) |*| getInt(b), n)
|
of mMulI: result = foldMul(getInt(a), getInt(b), n)
|
||||||
of mMinI:
|
of mMinI:
|
||||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
|
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
|
||||||
else: result = newIntNodeT(getInt(a), n)
|
else: result = newIntNodeT(getInt(a), n)
|
||||||
|
|
@ -211,14 +267,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
||||||
else: internalError(n.info, "constant folding for shr")
|
else: internalError(n.info, "constant folding for shr")
|
||||||
of mDivI:
|
of mDivI: result = foldDiv(getInt(a), getInt(b), n)
|
||||||
let y = getInt(b)
|
of mModI: result = foldMod(getInt(a), getInt(b), n)
|
||||||
if y != 0:
|
|
||||||
result = newIntNodeT(`|div|`(getInt(a), y), n)
|
|
||||||
of mModI:
|
|
||||||
let y = getInt(b)
|
|
||||||
if y != 0:
|
|
||||||
result = newIntNodeT(`|mod|`(getInt(a), y), n)
|
|
||||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
||||||
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
|
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
|
||||||
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
|
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
|
||||||
|
|
@ -258,14 +308,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
|
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
|
||||||
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
|
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
|
||||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
||||||
of mModU:
|
of mModU: result = foldModU(getInt(a), getInt(b), n)
|
||||||
let y = getInt(b)
|
of mDivU: result = foldDivU(getInt(a), getInt(b), n)
|
||||||
if y != 0:
|
|
||||||
result = newIntNodeT(`%%`(getInt(a), y), n)
|
|
||||||
of mDivU:
|
|
||||||
let y = getInt(b)
|
|
||||||
if y != 0:
|
|
||||||
result = newIntNodeT(`/%`(getInt(a), y), n)
|
|
||||||
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
|
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
|
||||||
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
|
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
|
||||||
of mLtSet:
|
of mLtSet:
|
||||||
|
|
|
||||||
|
|
@ -71,37 +71,12 @@ proc toCover(t: PType): BiggestInt =
|
||||||
else:
|
else:
|
||||||
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
||||||
|
|
||||||
when false:
|
|
||||||
proc performProcvarCheck(c: PContext, info: TLineInfo, s: PSym) =
|
|
||||||
## Checks that the given symbol is a proper procedure variable, meaning
|
|
||||||
## that it
|
|
||||||
var smoduleId = getModule(s).id
|
|
||||||
if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
|
|
||||||
smoduleId != c.module.id:
|
|
||||||
block outer:
|
|
||||||
for module in c.friendModules:
|
|
||||||
if smoduleId == module.id:
|
|
||||||
break outer
|
|
||||||
localError(info, errXCannotBePassedToProcVar, s.name.s)
|
|
||||||
|
|
||||||
template semProcvarCheck(c: PContext, n: PNode) =
|
|
||||||
when false:
|
|
||||||
var n = n.skipConv
|
|
||||||
if n.kind in nkSymChoices:
|
|
||||||
for x in n:
|
|
||||||
if x.sym.kind in {skProc, skMethod, skConverter, skIterator}:
|
|
||||||
performProcvarCheck(c, n.info, x.sym)
|
|
||||||
elif n.kind == nkSym and n.sym.kind in {skProc, skMethod, skConverter,
|
|
||||||
skIterator}:
|
|
||||||
performProcvarCheck(c, n.info, n.sym)
|
|
||||||
|
|
||||||
proc semProc(c: PContext, n: PNode): PNode
|
proc semProc(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
proc semExprBranch(c: PContext, n: PNode): PNode =
|
proc semExprBranch(c: PContext, n: PNode): PNode =
|
||||||
result = semExpr(c, n)
|
result = semExpr(c, n)
|
||||||
if result.typ != nil:
|
if result.typ != nil:
|
||||||
# XXX tyGenericInst here?
|
# XXX tyGenericInst here?
|
||||||
semProcvarCheck(c, result)
|
|
||||||
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
||||||
|
|
||||||
proc semExprBranchScope(c: PContext, n: PNode): PNode =
|
proc semExprBranchScope(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -132,20 +107,13 @@ proc fixNilType(n: PNode) =
|
||||||
proc discardCheck(c: PContext, result: PNode) =
|
proc discardCheck(c: PContext, result: PNode) =
|
||||||
if c.matchedConcept != nil: return
|
if c.matchedConcept != nil: return
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||||
if result.kind == nkNilLit:
|
if implicitlyDiscardable(result):
|
||||||
result.typ = nil
|
|
||||||
message(result.info, warnNilStatement)
|
|
||||||
elif implicitlyDiscardable(result):
|
|
||||||
var n = result
|
var n = result
|
||||||
result.typ = nil
|
result.typ = nil
|
||||||
while n.kind in skipForDiscardable:
|
while n.kind in skipForDiscardable:
|
||||||
n = n.lastSon
|
n = n.lastSon
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
elif result.typ.kind != tyError and gCmd != cmdInteractive:
|
elif result.typ.kind != tyError and gCmd != cmdInteractive:
|
||||||
if result.typ.kind == tyNil:
|
|
||||||
fixNilType(result)
|
|
||||||
message(result.info, warnNilStatement)
|
|
||||||
else:
|
|
||||||
var n = result
|
var n = result
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
var s = "expression '" & $n & "' is of type '" &
|
var s = "expression '" & $n & "' is of type '" &
|
||||||
|
|
@ -384,7 +352,7 @@ proc checkNilable(v: PSym) =
|
||||||
|
|
||||||
include semasgn
|
include semasgn
|
||||||
|
|
||||||
proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
|
proc addToVarSection(c: PContext; result: PNode; orig, identDefs: PNode) =
|
||||||
let L = identDefs.len
|
let L = identDefs.len
|
||||||
let value = identDefs[L-1]
|
let value = identDefs[L-1]
|
||||||
if result.kind == nkStmtList:
|
if result.kind == nkStmtList:
|
||||||
|
|
@ -525,7 +493,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
localError(a.info, errXExpected, "tuple")
|
localError(a.info, errXExpected, "tuple")
|
||||||
elif length-2 != sonsLen(tup):
|
elif length-2 != sonsLen(tup):
|
||||||
localError(a.info, errWrongNumberOfVariables)
|
localError(a.info, errWrongNumberOfVariables)
|
||||||
else:
|
|
||||||
b = newNodeI(nkVarTuple, a.info)
|
b = newNodeI(nkVarTuple, a.info)
|
||||||
newSons(b, length)
|
newSons(b, length)
|
||||||
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
|
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
|
||||||
|
|
@ -572,7 +539,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
addToVarSection(c, result, n, b)
|
addToVarSection(c, result, n, b)
|
||||||
else:
|
else:
|
||||||
if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j]
|
if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j]
|
||||||
setVarType(v, tup.sons[j])
|
# bug #7663, for 'nim check' this can be a non-tuple:
|
||||||
|
if tup.kind == tyTuple: setVarType(v, tup.sons[j])
|
||||||
|
else: v.typ = tup
|
||||||
b.sons[j] = newSymNode(v)
|
b.sons[j] = newSymNode(v)
|
||||||
checkNilable(v)
|
checkNilable(v)
|
||||||
if sfCompileTime in v.flags: hasCompileTime = true
|
if sfCompileTime in v.flags: hasCompileTime = true
|
||||||
|
|
@ -1588,9 +1557,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
||||||
if s.name.s[0] in {'.', '('}:
|
if s.name.s[0] in {'.', '('}:
|
||||||
if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}:
|
if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}:
|
||||||
message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s)
|
localError(n.info, "the overloaded " & s.name.s &
|
||||||
|
" operator has to be enabled with {.experimental: \"dotOperators\".}")
|
||||||
elif s.name.s == "()" and callOperator notin c.features:
|
elif s.name.s == "()" and callOperator notin c.features:
|
||||||
message(n.info, warnDeprecated, "overloaded '()' operators are now .experimental; " & s.name.s)
|
localError(n.info, "the overloaded " & s.name.s &
|
||||||
|
" operator has to be enabled with {.experimental: \"callOperator\".}")
|
||||||
|
|
||||||
if n.sons[bodyPos].kind != nkEmpty:
|
if n.sons[bodyPos].kind != nkEmpty:
|
||||||
# for DLL generation it is annoying to check for sfImportc!
|
# for DLL generation it is annoying to check for sfImportc!
|
||||||
|
|
@ -1682,11 +1653,6 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
||||||
incl(s.typ.flags, tfCapturesEnv)
|
incl(s.typ.flags, tfCapturesEnv)
|
||||||
else:
|
else:
|
||||||
s.typ.callConv = ccInline
|
s.typ.callConv = ccInline
|
||||||
when false:
|
|
||||||
if s.typ.callConv != ccInline:
|
|
||||||
s.typ.callConv = ccClosure
|
|
||||||
# and they always at least use the 'env' for the state field:
|
|
||||||
incl(s.typ.flags, tfCapturesEnv)
|
|
||||||
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
|
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
|
||||||
localError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
||||||
|
|
@ -1792,14 +1758,6 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
evalStaticStmt(c.module, c.cache, a, c.p.owner)
|
evalStaticStmt(c.module, c.cache, a, c.p.owner)
|
||||||
result = newNodeI(nkDiscardStmt, n.info, 1)
|
result = newNodeI(nkDiscardStmt, n.info, 1)
|
||||||
result.sons[0] = emptyNode
|
result.sons[0] = emptyNode
|
||||||
when false:
|
|
||||||
result = evalStaticStmt(c.module, a, c.p.owner)
|
|
||||||
if result.isNil:
|
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
|
||||||
result = emptyNode
|
|
||||||
elif result.kind == nkEmpty:
|
|
||||||
result = newNodeI(nkDiscardStmt, n.info, 1)
|
|
||||||
result.sons[0] = emptyNode
|
|
||||||
|
|
||||||
proc usesResult(n: PNode): bool =
|
proc usesResult(n: PNode): bool =
|
||||||
# nkStmtList(expr) properly propagates the void context,
|
# nkStmtList(expr) properly propagates the void context,
|
||||||
|
|
@ -1841,40 +1799,6 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# nkNilLit, nkEmpty}:
|
# nkNilLit, nkEmpty}:
|
||||||
# dec last
|
# dec last
|
||||||
for i in countup(0, length - 1):
|
for i in countup(0, length - 1):
|
||||||
let k = n.sons[i].kind
|
|
||||||
case k
|
|
||||||
of nkFinally, nkExceptBranch:
|
|
||||||
# stand-alone finally and except blocks are
|
|
||||||
# transformed into regular try blocks:
|
|
||||||
#
|
|
||||||
# var f = fopen("somefile") | var f = fopen("somefile")
|
|
||||||
# finally: fclose(f) | try:
|
|
||||||
# ... | ...
|
|
||||||
# | finally:
|
|
||||||
# | fclose(f)
|
|
||||||
var deferPart: PNode
|
|
||||||
if k == nkDefer:
|
|
||||||
deferPart = newNodeI(nkFinally, n.sons[i].info)
|
|
||||||
deferPart.add n.sons[i].sons[0]
|
|
||||||
elif k == nkFinally:
|
|
||||||
message(n.info, warnDeprecated,
|
|
||||||
"use 'defer'; standalone 'finally'")
|
|
||||||
deferPart = n.sons[i]
|
|
||||||
else:
|
|
||||||
message(n.info, warnDeprecated,
|
|
||||||
"use an explicit 'try'; standalone 'except'")
|
|
||||||
deferPart = n.sons[i]
|
|
||||||
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
|
||||||
var body = newNodeI(nkStmtList, n.sons[i].info)
|
|
||||||
if i < n.sonsLen - 1:
|
|
||||||
body.sons = n.sons[(i+1)..n.len-1]
|
|
||||||
tryStmt.addSon(body)
|
|
||||||
tryStmt.addSon(deferPart)
|
|
||||||
n.sons[i] = semTry(c, tryStmt)
|
|
||||||
n.sons.setLen(i+1)
|
|
||||||
n.typ = n.sons[i].typ
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
var expr = semExpr(c, n.sons[i], flags)
|
var expr = semExpr(c, n.sons[i], flags)
|
||||||
n.sons[i] = expr
|
n.sons[i] = expr
|
||||||
if c.matchedConcept != nil and expr.typ != nil and
|
if c.matchedConcept != nil and expr.typ != nil and
|
||||||
|
|
@ -1908,7 +1832,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||||
if n.sons[i].kind in LastBlockStmts or
|
if n.sons[i].kind in LastBlockStmts or
|
||||||
n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and sfNoReturn in n.sons[i][0].sym.flags:
|
n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and
|
||||||
|
sfNoReturn in n.sons[i][0].sym.flags:
|
||||||
for j in countup(i + 1, length - 1):
|
for j in countup(i + 1, length - 1):
|
||||||
case n.sons[j].kind
|
case n.sons[j].kind
|
||||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr,
|
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr,
|
||||||
|
|
@ -1930,15 +1855,6 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
not (result.comment[0] == '#' and result.comment[1] == '#'):
|
not (result.comment[0] == '#' and result.comment[1] == '#'):
|
||||||
# it is an old-style comment statement: we replace it with 'discard ""':
|
# it is an old-style comment statement: we replace it with 'discard ""':
|
||||||
prettybase.replaceComment(result.info)
|
prettybase.replaceComment(result.info)
|
||||||
when false:
|
|
||||||
# a statement list (s; e) has the type 'e':
|
|
||||||
if result.kind == nkStmtList and result.len > 0:
|
|
||||||
var lastStmt = lastSon(result)
|
|
||||||
if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt):
|
|
||||||
result.typ = lastStmt.typ
|
|
||||||
#localError(lastStmt.info, errGenerated,
|
|
||||||
# "Last expression must be explicitly returned if it " &
|
|
||||||
# "is discardable or discarded")
|
|
||||||
|
|
||||||
proc semStmt(c: PContext, n: PNode): PNode =
|
proc semStmt(c: PContext, n: PNode): PNode =
|
||||||
# now: simply an alias:
|
# now: simply an alias:
|
||||||
|
|
|
||||||
|
|
@ -1389,6 +1389,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
n.sons[2].kind == nkNilLit:
|
n.sons[2].kind == nkNilLit:
|
||||||
result = freshType(result, prev)
|
result = freshType(result, prev)
|
||||||
result.flags.incl(tfNotNil)
|
result.flags.incl(tfNotNil)
|
||||||
|
if notnil notin c.features:
|
||||||
|
localError(n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}")
|
||||||
else:
|
else:
|
||||||
localError(n.info, errGenerated, "invalid type")
|
localError(n.info, errGenerated, "invalid type")
|
||||||
of 2:
|
of 2:
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ type
|
||||||
sym*: PSym
|
sym*: PSym
|
||||||
unmatchedVarParam*, firstMismatch*: int
|
unmatchedVarParam*, firstMismatch*: int
|
||||||
diagnostics*: seq[string]
|
diagnostics*: seq[string]
|
||||||
|
enabled*: bool
|
||||||
|
|
||||||
CandidateErrors* = seq[CandidateError]
|
CandidateErrors* = seq[CandidateError]
|
||||||
|
|
||||||
|
|
@ -60,7 +61,8 @@ type
|
||||||
# matching. they will be reset if the matching
|
# matching. they will be reset if the matching
|
||||||
# is not successful. may replace the bindings
|
# is not successful. may replace the bindings
|
||||||
# table in the future.
|
# table in the future.
|
||||||
diagnostics*: seq[string] # when this is not nil, the matching process
|
diagnostics*: seq[string] # \
|
||||||
|
# when diagnosticsEnabled, the matching process
|
||||||
# will collect extra diagnostics that will be
|
# will collect extra diagnostics that will be
|
||||||
# displayed to the user.
|
# displayed to the user.
|
||||||
# triggered when overload resolution fails
|
# triggered when overload resolution fails
|
||||||
|
|
@ -70,6 +72,7 @@ type
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
firstMismatch*: int # position of the first type mismatch for
|
firstMismatch*: int # position of the first type mismatch for
|
||||||
# better error messages
|
# better error messages
|
||||||
|
diagnosticsEnabled*: bool
|
||||||
|
|
||||||
TTypeRelFlag* = enum
|
TTypeRelFlag* = enum
|
||||||
trDontBind
|
trDontBind
|
||||||
|
|
@ -124,7 +127,8 @@ proc put(c: var TCandidate, key, val: PType) {.inline.} =
|
||||||
idTablePut(c.bindings, key, val.skipIntLit)
|
idTablePut(c.bindings, key, val.skipIntLit)
|
||||||
|
|
||||||
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
binding: PNode, calleeScope = -1, diagnostics = false) =
|
binding: PNode, calleeScope = -1,
|
||||||
|
diagnosticsEnabled = false) =
|
||||||
initCandidateAux(ctx, c, callee.typ)
|
initCandidateAux(ctx, c, callee.typ)
|
||||||
c.calleeSym = callee
|
c.calleeSym = callee
|
||||||
if callee.kind in skProcKinds and calleeScope == -1:
|
if callee.kind in skProcKinds and calleeScope == -1:
|
||||||
|
|
@ -139,7 +143,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
c.calleeScope = 1
|
c.calleeScope = 1
|
||||||
else:
|
else:
|
||||||
c.calleeScope = calleeScope
|
c.calleeScope = calleeScope
|
||||||
c.diagnostics = if diagnostics: @[] else: nil
|
c.diagnostics = if diagnosticsEnabled: @[] else: nil
|
||||||
|
c.diagnosticsEnabled = diagnosticsEnabled
|
||||||
c.magic = c.calleeSym.magic
|
c.magic = c.calleeSym.magic
|
||||||
initIdTable(c.bindings)
|
initIdTable(c.bindings)
|
||||||
if binding != nil and callee.kind in routineKinds:
|
if binding != nil and callee.kind in routineKinds:
|
||||||
|
|
@ -717,7 +722,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
|
||||||
diagnostics: seq[string]
|
diagnostics: seq[string]
|
||||||
errorPrefix: string
|
errorPrefix: string
|
||||||
flags: TExprFlags = {}
|
flags: TExprFlags = {}
|
||||||
collectDiagnostics = m.diagnostics != nil or
|
collectDiagnostics = m.diagnosticsEnabled or
|
||||||
sfExplain in typeClass.sym.flags
|
sfExplain in typeClass.sym.flags
|
||||||
|
|
||||||
if collectDiagnostics:
|
if collectDiagnostics:
|
||||||
|
|
@ -736,7 +741,9 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
|
||||||
|
|
||||||
if collectDiagnostics:
|
if collectDiagnostics:
|
||||||
writelnHook = oldWriteHook
|
writelnHook = oldWriteHook
|
||||||
for msg in diagnostics: m.diagnostics.safeAdd msg
|
for msg in diagnostics:
|
||||||
|
m.diagnostics.safeAdd msg
|
||||||
|
m.diagnosticsEnabled = true
|
||||||
|
|
||||||
if checkedBody == nil: return nil
|
if checkedBody == nil: return nil
|
||||||
|
|
||||||
|
|
@ -1388,7 +1395,12 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
|
|
||||||
var aAsObject = roota.lastSon
|
var aAsObject = roota.lastSon
|
||||||
|
|
||||||
if fKind in {tyRef, tyPtr} and aAsObject.kind == fKind:
|
if fKind in {tyRef, tyPtr}:
|
||||||
|
if aAsObject.kind == tyObject:
|
||||||
|
# bug #7600, tyObject cannot be passed
|
||||||
|
# as argument to tyRef/tyPtr
|
||||||
|
return isNone
|
||||||
|
elif aAsObject.kind == fKind:
|
||||||
aAsObject = aAsObject.base
|
aAsObject = aAsObject.base
|
||||||
|
|
||||||
if aAsObject.kind == tyObject:
|
if aAsObject.kind == tyObject:
|
||||||
|
|
|
||||||
|
|
@ -51,15 +51,15 @@ proc parseTopLevelStmt*(p: var TParsers): PNode =
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
|
|
||||||
proc utf8Bom(s: string): int =
|
proc utf8Bom(s: string): int =
|
||||||
if s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF':
|
if s.len >= 3 and s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF':
|
||||||
result = 3
|
result = 3
|
||||||
else:
|
else:
|
||||||
result = 0
|
result = 0
|
||||||
|
|
||||||
proc containsShebang(s: string, i: int): bool =
|
proc containsShebang(s: string, i: int): bool =
|
||||||
if s[i] == '#' and s[i+1] == '!':
|
if i+1 < s.len and s[i] == '#' and s[i+1] == '!':
|
||||||
var j = i + 2
|
var j = i + 2
|
||||||
while s[j] in Whitespace: inc(j)
|
while j < s.len and s[j] in Whitespace: inc(j)
|
||||||
result = s[j] == '/'
|
result = s[j] == '/'
|
||||||
|
|
||||||
proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode =
|
proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode =
|
||||||
|
|
@ -74,9 +74,9 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo
|
||||||
discard llStreamReadLine(s, line)
|
discard llStreamReadLine(s, line)
|
||||||
i = 0
|
i = 0
|
||||||
inc linenumber
|
inc linenumber
|
||||||
if line[i] == '#' and line[i+1] == '?':
|
if i+1 < line.len and line[i] == '#' and line[i+1] == '?':
|
||||||
inc(i, 2)
|
inc(i, 2)
|
||||||
while line[i] in Whitespace: inc(i)
|
while i < line.len and line[i] in Whitespace: inc(i)
|
||||||
var q: TParser
|
var q: TParser
|
||||||
parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache)
|
parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache)
|
||||||
result = parser.parseAll(q)
|
result = parser.parseAll(q)
|
||||||
|
|
|
||||||
|
|
@ -612,13 +612,13 @@ proc firstOrd*(t: PType): BiggestInt =
|
||||||
else:
|
else:
|
||||||
assert(t.n.sons[0].kind == nkSym)
|
assert(t.n.sons[0].kind == nkSym)
|
||||||
result = t.n.sons[0].sym.position
|
result = t.n.sons[0].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias:
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic:
|
||||||
result = firstOrd(lastSon(t))
|
result = firstOrd(lastSon(t))
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if t.len > 0: result = firstOrd(lastSon(t))
|
if t.len > 0: result = firstOrd(lastSon(t))
|
||||||
else: internalError("invalid kind for first(" & $t.kind & ')')
|
else: internalError("invalid kind for firstOrd(" & $t.kind & ')')
|
||||||
else:
|
else:
|
||||||
internalError("invalid kind for first(" & $t.kind & ')')
|
internalError("invalid kind for firstOrd(" & $t.kind & ')')
|
||||||
result = 0
|
result = 0
|
||||||
|
|
||||||
proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
|
proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
|
||||||
|
|
@ -651,14 +651,14 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
||||||
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias:
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic:
|
||||||
result = lastOrd(lastSon(t))
|
result = lastOrd(lastSon(t))
|
||||||
of tyProxy: result = 0
|
of tyProxy: result = 0
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if t.len > 0: result = lastOrd(lastSon(t))
|
if t.len > 0: result = lastOrd(lastSon(t))
|
||||||
else: internalError("invalid kind for last(" & $t.kind & ')')
|
else: internalError("invalid kind for lastOrd(" & $t.kind & ')')
|
||||||
else:
|
else:
|
||||||
internalError("invalid kind for last(" & $t.kind & ')')
|
internalError("invalid kind for lastOrd(" & $t.kind & ')')
|
||||||
result = 0
|
result = 0
|
||||||
|
|
||||||
proc lengthOrd*(t: PType): BiggestInt =
|
proc lengthOrd*(t: PType): BiggestInt =
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,12 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
|
||||||
result.add mapTypeToAst(t.sons[0], info)
|
result.add mapTypeToAst(t.sons[0], info)
|
||||||
else:
|
else:
|
||||||
result = mapTypeToBracket("ref", mRef, t, info)
|
result = mapTypeToBracket("ref", mRef, t, info)
|
||||||
of tyVar: result = mapTypeToBracket("var", mVar, t, info)
|
of tyVar:
|
||||||
|
if inst:
|
||||||
|
result = newNodeX(nkVarTy)
|
||||||
|
result.add mapTypeToAst(t.sons[0], info)
|
||||||
|
else:
|
||||||
|
result = mapTypeToBracket("var", mVar, t, info)
|
||||||
of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info)
|
of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info)
|
||||||
of tySink: result = mapTypeToBracket("sink", mBuiltinType, t, info)
|
of tySink: result = mapTypeToBracket("sink", mBuiltinType, t, info)
|
||||||
of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
|
of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
|
||||||
|
|
|
||||||
|
|
@ -1553,6 +1553,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||||
result = newNodeIT(nkFloatLit, info, t)
|
result = newNodeIT(nkFloatLit, info, t)
|
||||||
of tyCString, tyString:
|
of tyCString, tyString:
|
||||||
result = newNodeIT(nkStrLit, info, t)
|
result = newNodeIT(nkStrLit, info, t)
|
||||||
|
result.strVal = ""
|
||||||
of tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr,
|
of tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr,
|
||||||
tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
|
tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
|
||||||
result = newNodeIT(nkNilLit, info, t)
|
result = newNodeIT(nkNilLit, info, t)
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ Advanced options:
|
||||||
--excessiveStackTrace:on|off
|
--excessiveStackTrace:on|off
|
||||||
stack traces use full file paths
|
stack traces use full file paths
|
||||||
--oldNewlines:on|off turn on|off the old behaviour of "\n"
|
--oldNewlines:on|off turn on|off the old behaviour of "\n"
|
||||||
|
--laxStrings:on|off when turned on, accessing the zero terminator in
|
||||||
|
strings is allowed; only for backwards compatibility
|
||||||
--skipCfg do not read the general configuration file
|
--skipCfg do not read the general configuration file
|
||||||
--skipUserCfg do not read the user's configuration file
|
--skipUserCfg do not read the user's configuration file
|
||||||
--skipParentCfg do not read the parent dirs' configuration files
|
--skipParentCfg do not read the parent dirs' configuration files
|
||||||
|
|
|
||||||
|
|
@ -1471,7 +1471,7 @@ mysterious crashes.
|
||||||
|
|
||||||
**Note**: The example only works because the memory is initialized to zero
|
**Note**: The example only works because the memory is initialized to zero
|
||||||
(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to
|
(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to
|
||||||
``nil`` which the string assignment can handle. One needs to know low level
|
binary zero which the string assignment can handle. One needs to know low level
|
||||||
details like this when mixing garbage collected data with unmanaged memory.
|
details like this when mixing garbage collected data with unmanaged memory.
|
||||||
|
|
||||||
.. XXX finalizers for traced objects
|
.. XXX finalizers for traced objects
|
||||||
|
|
@ -2512,8 +2512,8 @@ char '\\0'
|
||||||
bool false
|
bool false
|
||||||
ref or pointer type nil
|
ref or pointer type nil
|
||||||
procedural type nil
|
procedural type nil
|
||||||
sequence nil (*not* ``@[]``)
|
sequence ``@[]``
|
||||||
string nil (*not* "")
|
string ``""``
|
||||||
tuple[x: A, y: B, ...] (default(A), default(B), ...)
|
tuple[x: A, y: B, ...] (default(A), default(B), ...)
|
||||||
(analogous for objects)
|
(analogous for objects)
|
||||||
array[0..., T] [default(T), ...]
|
array[0..., T] [default(T), ...]
|
||||||
|
|
@ -4270,7 +4270,7 @@ therefore very useful for type specialization within generic code:
|
||||||
Table[Key, Value] = object
|
Table[Key, Value] = object
|
||||||
keys: seq[Key]
|
keys: seq[Key]
|
||||||
values: seq[Value]
|
values: seq[Value]
|
||||||
when not (Key is string): # nil value for strings used for optimization
|
when not (Key is string): # empty value for strings used for optimization
|
||||||
deletedKeys: seq[bool]
|
deletedKeys: seq[bool]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -7434,8 +7434,8 @@ code generation directly, but their presence can be detected by macros.
|
||||||
Custom pragmas are defined using templates annotated with pragma ``pragma``:
|
Custom pragmas are defined using templates annotated with pragma ``pragma``:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
template dbTable(name: string, table_space: string = nil) {.pragma.}
|
template dbTable(name: string, table_space: string = "") {.pragma.}
|
||||||
template dbKey(name: string = nil, primary_key: bool = false) {.pragma.}
|
template dbKey(name: string = "", primary_key: bool = false) {.pragma.}
|
||||||
template dbForeignKey(t: typedesc) {.pragma.}
|
template dbForeignKey(t: typedesc) {.pragma.}
|
||||||
template dbIgnore {.pragma.}
|
template dbIgnore {.pragma.}
|
||||||
|
|
||||||
|
|
|
||||||
26
doc/tut1.rst
26
doc/tut1.rst
|
|
@ -944,12 +944,8 @@ String variables are **mutable**, so appending to a string
|
||||||
is possible, and quite efficient. Strings in Nim are both zero-terminated and have a
|
is possible, and quite efficient. Strings in Nim are both zero-terminated and have a
|
||||||
length field. A string's length can be retrieved with the builtin ``len``
|
length field. A string's length can be retrieved with the builtin ``len``
|
||||||
procedure; the length never counts the terminating zero. Accessing the
|
procedure; the length never counts the terminating zero. Accessing the
|
||||||
terminating zero is not an error and often leads to simpler code:
|
terminating zero is an error, it only exists so that a Nim string can be converted
|
||||||
|
to a ``cstring`` without doing a copy.
|
||||||
.. code-block:: nim
|
|
||||||
if s[i] == 'a' and s[i+1] == 'b':
|
|
||||||
# no need to check whether ``i < len(s)``!
|
|
||||||
...
|
|
||||||
|
|
||||||
The assignment operator for strings copies the string. You can use the ``&``
|
The assignment operator for strings copies the string. You can use the ``&``
|
||||||
operator to concatenate strings and ``add`` to append to a string.
|
operator to concatenate strings and ``add`` to append to a string.
|
||||||
|
|
@ -960,11 +956,7 @@ enforced. For example, when reading strings from binary files, they are merely
|
||||||
a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of
|
a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of
|
||||||
``s``, not the i-th *unichar*.
|
``s``, not the i-th *unichar*.
|
||||||
|
|
||||||
String variables are initialized with a special value, called ``nil``. However,
|
A string variable is initialized with the empty string ``""``.
|
||||||
most string operations cannot deal with ``nil`` (leading to an exception being
|
|
||||||
raised) for performance reasons. It is best to use empty strings ``""``
|
|
||||||
rather than ``nil`` as the *empty* value. But ``""`` often creates a string
|
|
||||||
object on the heap, so there is a trade-off to be made here.
|
|
||||||
|
|
||||||
|
|
||||||
Integers
|
Integers
|
||||||
|
|
@ -1309,11 +1301,7 @@ Example:
|
||||||
x: seq[int] # a reference to a sequence of integers
|
x: seq[int] # a reference to a sequence of integers
|
||||||
x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap
|
x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap
|
||||||
|
|
||||||
Sequence variables are initialized with ``nil``. However, most sequence
|
Sequence variables are initialized with ``@[]``.
|
||||||
operations cannot deal with ``nil`` (leading to an exception being
|
|
||||||
raised) for performance reasons. Thus one should use empty sequences ``@[]``
|
|
||||||
rather than ``nil`` as the *empty* value. But ``@[]`` creates a sequence
|
|
||||||
object on the heap, so there is a trade-off to be made here.
|
|
||||||
|
|
||||||
The ``for`` statement can be used with one or two variables when used with a
|
The ``for`` statement can be used with one or two variables when used with a
|
||||||
sequence. When you use the one variable form, the variable will hold the value
|
sequence. When you use the one variable form, the variable will hold the value
|
||||||
|
|
@ -1355,11 +1343,9 @@ type does not matter.
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
:test: "nim c $1"
|
:test: "nim c $1"
|
||||||
var
|
var
|
||||||
fruits: seq[string] # reference to a sequence of strings that is initialized with 'nil'
|
fruits: seq[string] # reference to a sequence of strings that is initialized with '@[]'
|
||||||
capitals: array[3, string] # array of strings with a fixed size
|
capitals: array[3, string] # array of strings with a fixed size
|
||||||
|
|
||||||
fruits = @[] # creates an empty sequence on the heap that will be referenced by 'fruits'
|
|
||||||
|
|
||||||
capitals = ["New York", "London", "Berlin"] # array 'capitals' allows assignment of only three elements
|
capitals = ["New York", "London", "Berlin"] # array 'capitals' allows assignment of only three elements
|
||||||
fruits.add("Banana") # sequence 'fruits' is dynamically expandable during runtime
|
fruits.add("Banana") # sequence 'fruits' is dynamically expandable during runtime
|
||||||
fruits.add("Mango")
|
fruits.add("Mango")
|
||||||
|
|
@ -1691,7 +1677,7 @@ rules apply:
|
||||||
write(stdout, x(3)) # no error: A.x is called
|
write(stdout, x(3)) # no error: A.x is called
|
||||||
write(stdout, x("")) # no error: B.x is called
|
write(stdout, x("")) # no error: B.x is called
|
||||||
|
|
||||||
proc x*(a: int): string = nil
|
proc x*(a: int): string = discard
|
||||||
write(stdout, x(3)) # ambiguous: which `x` is to call?
|
write(stdout, x(3)) # ambiguous: which `x` is to call?
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ proc executeCgi(server: var TServer, client: Socket, path, query: string,
|
||||||
dataAvail = recvLine(client, buf)
|
dataAvail = recvLine(client, buf)
|
||||||
if buf.len == 0:
|
if buf.len == 0:
|
||||||
break
|
break
|
||||||
var L = toLower(buf)
|
var L = toLowerAscii(buf)
|
||||||
if L.startsWith("content-length:"):
|
if L.startsWith("content-length:"):
|
||||||
var i = len("content-length:")
|
var i = len("content-length:")
|
||||||
while L[i] in Whitespace: inc(i)
|
while L[i] in Whitespace: inc(i)
|
||||||
|
|
@ -205,7 +205,7 @@ proc acceptRequest(server: var TServer, client: Socket) =
|
||||||
client.close()
|
client.close()
|
||||||
else:
|
else:
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var ext = splitFile(path).ext.toLower
|
var ext = splitFile(path).ext.toLowerAscii
|
||||||
if ext == ".exe" or ext == ".cgi":
|
if ext == ".exe" or ext == ".cgi":
|
||||||
# XXX: extract interpreter information here?
|
# XXX: extract interpreter information here?
|
||||||
cgi = true
|
cgi = true
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
from pcre import nil
|
from pcre import nil
|
||||||
import nre.private.util
|
import nre.private.util
|
||||||
import tables
|
import tables
|
||||||
from strutils import toLower, `%`
|
from strutils import `%`
|
||||||
from math import ceil
|
from math import ceil
|
||||||
import options
|
import options
|
||||||
from unicode import runeLenAt
|
from unicode import runeLenAt
|
||||||
|
|
@ -645,7 +645,6 @@ template replaceImpl(str: string, pattern: Regex,
|
||||||
let bounds = match.matchBounds
|
let bounds = match.matchBounds
|
||||||
result.add(str.substr(lastIdx, bounds.a - 1))
|
result.add(str.substr(lastIdx, bounds.a - 1))
|
||||||
let nextVal = replacement
|
let nextVal = replacement
|
||||||
assert(nextVal != nil)
|
|
||||||
result.add(nextVal)
|
result.add(nextVal)
|
||||||
|
|
||||||
lastIdx = bounds.b + 1
|
lastIdx = bounds.b + 1
|
||||||
|
|
|
||||||
|
|
@ -774,7 +774,7 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||||
Digits + Letters + WhiteSpace)
|
Digits + Letters + WhiteSpace)
|
||||||
let
|
let
|
||||||
arg = getArgument(n)
|
arg = getArgument(n)
|
||||||
isObject = arg.toLower().endsWith(".svg")
|
isObject = arg.toLowerAscii().endsWith(".svg")
|
||||||
var
|
var
|
||||||
options = ""
|
options = ""
|
||||||
content = ""
|
content = ""
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ proc fail*[T](future: Future[T], error: ref Exception) =
|
||||||
if getStackTrace(error) == "": getStackTrace() else: getStackTrace(error)
|
if getStackTrace(error) == "": getStackTrace() else: getStackTrace(error)
|
||||||
future.callbacks.call()
|
future.callbacks.call()
|
||||||
|
|
||||||
proc clearCallbacks(future: FutureBase) =
|
proc clearCallbacks*(future: FutureBase) =
|
||||||
future.callbacks.function = nil
|
future.callbacks.function = nil
|
||||||
future.callbacks.next = nil
|
future.callbacks.next = nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ when defineSsl:
|
||||||
flags: set[SocketFlag]) {.async.} =
|
flags: set[SocketFlag]) {.async.} =
|
||||||
let len = bioCtrlPending(socket.bioOut)
|
let len = bioCtrlPending(socket.bioOut)
|
||||||
if len > 0:
|
if len > 0:
|
||||||
var data = newStringOfCap(len)
|
var data = newString(len)
|
||||||
let read = bioRead(socket.bioOut, addr data[0], len)
|
let read = bioRead(socket.bioOut, addr data[0], len)
|
||||||
assert read != 0
|
assert read != 0
|
||||||
if read < 0:
|
if read < 0:
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ proc decode*(s: string): string =
|
||||||
i = 0
|
i = 0
|
||||||
r = 0
|
r = 0
|
||||||
while true:
|
while true:
|
||||||
while s[i] in Whitespace: inc(i)
|
while i < s.len and s[i] in Whitespace: inc(i)
|
||||||
if i < s.len-3:
|
if i < s.len-3:
|
||||||
let
|
let
|
||||||
a = s[i].decodeByte
|
a = s[i].decodeByte
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,10 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] =
|
||||||
var name = ""
|
var name = ""
|
||||||
var value = ""
|
var value = ""
|
||||||
# decode everything in one pass:
|
# decode everything in one pass:
|
||||||
while data[i] != '\0':
|
while i < data.len:
|
||||||
setLen(name, 0) # reuse memory
|
setLen(name, 0) # reuse memory
|
||||||
while true:
|
while i < data.len:
|
||||||
case data[i]
|
case data[i]
|
||||||
of '\0': break
|
|
||||||
of '%':
|
of '%':
|
||||||
var x = 0
|
var x = 0
|
||||||
handleHexChar(data[i+1], x)
|
handleHexChar(data[i+1], x)
|
||||||
|
|
@ -112,13 +111,14 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] =
|
||||||
of '=', '&': break
|
of '=', '&': break
|
||||||
else: add(name, data[i])
|
else: add(name, data[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
if data[i] != '=': cgiError("'=' expected")
|
if i >= data.len or data[i] != '=': cgiError("'=' expected")
|
||||||
inc(i) # skip '='
|
inc(i) # skip '='
|
||||||
setLen(value, 0) # reuse memory
|
setLen(value, 0) # reuse memory
|
||||||
while true:
|
while i < data.len:
|
||||||
case data[i]
|
case data[i]
|
||||||
of '%':
|
of '%':
|
||||||
var x = 0
|
var x = 0
|
||||||
|
if i+2 < data.len:
|
||||||
handleHexChar(data[i+1], x)
|
handleHexChar(data[i+1], x)
|
||||||
handleHexChar(data[i+2], x)
|
handleHexChar(data[i+2], x)
|
||||||
inc(i, 2)
|
inc(i, 2)
|
||||||
|
|
@ -128,8 +128,8 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] =
|
||||||
else: add(value, data[i])
|
else: add(value, data[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
yield (name.TaintedString, value.TaintedString)
|
yield (name.TaintedString, value.TaintedString)
|
||||||
|
if i < data.len:
|
||||||
if data[i] == '&': inc(i)
|
if data[i] == '&': inc(i)
|
||||||
elif data[i] == '\0': break
|
|
||||||
else: cgiError("'&' expected")
|
else: cgiError("'&' expected")
|
||||||
|
|
||||||
iterator decodeData*(allowedMethods: set[RequestMethod] =
|
iterator decodeData*(allowedMethods: set[RequestMethod] =
|
||||||
|
|
|
||||||
|
|
@ -74,18 +74,19 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
||||||
var newByte = 0
|
var newByte = 0
|
||||||
block blockX:
|
block blockX:
|
||||||
while newbyte < key.len:
|
while newbyte < key.len:
|
||||||
if it.key[newbyte] != key[newbyte]:
|
let ch = if newbyte < it.key.len: it.key[newbyte] else: '\0'
|
||||||
newotherbits = it.key[newbyte].ord xor key[newbyte].ord
|
if ch != key[newbyte]:
|
||||||
|
newotherbits = ch.ord xor key[newbyte].ord
|
||||||
break blockX
|
break blockX
|
||||||
inc newbyte
|
inc newbyte
|
||||||
if it.key[newbyte] != '\0':
|
if newbyte < it.key.len:
|
||||||
newotherbits = it.key[newbyte].ord
|
newotherbits = it.key[newbyte].ord
|
||||||
else:
|
else:
|
||||||
return it
|
return it
|
||||||
while (newOtherBits and (newOtherBits-1)) != 0:
|
while (newOtherBits and (newOtherBits-1)) != 0:
|
||||||
newOtherBits = newOtherBits and (newOtherBits-1)
|
newOtherBits = newOtherBits and (newOtherBits-1)
|
||||||
newOtherBits = newOtherBits xor 255
|
newOtherBits = newOtherBits xor 255
|
||||||
let ch = it.key[newByte]
|
let ch = if newByte < it.key.len: it.key[newByte] else: '\0'
|
||||||
let dir = (1 + (ord(ch) or newOtherBits)) shr 8
|
let dir = (1 + (ord(ch) or newOtherBits)) shr 8
|
||||||
|
|
||||||
var inner: Node[T]
|
var inner: Node[T]
|
||||||
|
|
|
||||||
|
|
@ -25,16 +25,16 @@ proc parseCookies*(s: string): StringTableRef =
|
||||||
result = newStringTable(modeCaseInsensitive)
|
result = newStringTable(modeCaseInsensitive)
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
while s[i] == ' ' or s[i] == '\t': inc(i)
|
while i < s.len and (s[i] == ' ' or s[i] == '\t'): inc(i)
|
||||||
var keystart = i
|
var keystart = i
|
||||||
while s[i] != '=' and s[i] != '\0': inc(i)
|
while i < s.len and s[i] != '=': inc(i)
|
||||||
var keyend = i-1
|
var keyend = i-1
|
||||||
if s[i] == '\0': break
|
if i >= s.len: break
|
||||||
inc(i) # skip '='
|
inc(i) # skip '='
|
||||||
var valstart = i
|
var valstart = i
|
||||||
while s[i] != ';' and s[i] != '\0': inc(i)
|
while i < s.len and s[i] != ';': inc(i)
|
||||||
result[substr(s, keystart, keyend)] = substr(s, valstart, i-1)
|
result[substr(s, keystart, keyend)] = substr(s, valstart, i-1)
|
||||||
if s[i] == '\0': break
|
if i >= s.len: break
|
||||||
inc(i) # skip ';'
|
inc(i) # skip ';'
|
||||||
|
|
||||||
proc setCookie*(key, value: string, domain = "", path = "",
|
proc setCookie*(key, value: string, domain = "", path = "",
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ when defined(windows):
|
||||||
while i < a.len and j < b.len:
|
while i < a.len and j < b.len:
|
||||||
if a[i] in {'-', '_'}: inc i
|
if a[i] in {'-', '_'}: inc i
|
||||||
if b[j] in {'-', '_'}: inc j
|
if b[j] in {'-', '_'}: inc j
|
||||||
if a[i].toLower != b[j].toLower: return false
|
if i < a.len and j < b.len and a[i].toLowerAscii != b[j].toLowerAscii: return false
|
||||||
inc i
|
inc i
|
||||||
inc j
|
inc j
|
||||||
result = i == a.len and j == b.len
|
result = i == a.len and j == b.len
|
||||||
|
|
|
||||||
|
|
@ -73,13 +73,19 @@
|
||||||
## progress of the HTTP request.
|
## progress of the HTTP request.
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## var client = newAsyncHttpClient()
|
## import asyncdispatch, httpclient
|
||||||
|
##
|
||||||
## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} =
|
## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} =
|
||||||
## echo("Downloaded ", progress, " of ", total)
|
## echo("Downloaded ", progress, " of ", total)
|
||||||
## echo("Current rate: ", speed div 1000, "kb/s")
|
## echo("Current rate: ", speed div 1000, "kb/s")
|
||||||
|
##
|
||||||
|
## proc asyncProc() {.async.} =
|
||||||
|
## var client = newAsyncHttpClient()
|
||||||
## client.onProgressChanged = onProgressChanged
|
## client.onProgressChanged = onProgressChanged
|
||||||
## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test")
|
## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test")
|
||||||
##
|
##
|
||||||
|
## waitFor asyncProc()
|
||||||
|
##
|
||||||
## If you would like to remove the callback simply set it to ``nil``.
|
## If you would like to remove the callback simply set it to ``nil``.
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
|
|
@ -241,7 +247,7 @@ proc parseChunks(s: Socket, timeout: int): string =
|
||||||
var i = 0
|
var i = 0
|
||||||
if chunkSizeStr == "":
|
if chunkSizeStr == "":
|
||||||
httpError("Server terminated connection prematurely")
|
httpError("Server terminated connection prematurely")
|
||||||
while true:
|
while i < chunkSizeStr.len:
|
||||||
case chunkSizeStr[i]
|
case chunkSizeStr[i]
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
|
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
|
||||||
|
|
@ -249,8 +255,6 @@ proc parseChunks(s: Socket, timeout: int): string =
|
||||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
|
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
|
||||||
of 'A'..'F':
|
of 'A'..'F':
|
||||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
|
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
|
||||||
of '\0':
|
|
||||||
break
|
|
||||||
of ';':
|
of ';':
|
||||||
# http://tools.ietf.org/html/rfc2616#section-3.6.1
|
# http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||||
# We don't care about chunk-extensions.
|
# We don't care about chunk-extensions.
|
||||||
|
|
@ -739,10 +743,11 @@ proc downloadFile*(url: string, outputFilename: string,
|
||||||
proc generateHeaders(requestUrl: Uri, httpMethod: string,
|
proc generateHeaders(requestUrl: Uri, httpMethod: string,
|
||||||
headers: HttpHeaders, body: string, proxy: Proxy): string =
|
headers: HttpHeaders, body: string, proxy: Proxy): string =
|
||||||
# GET
|
# GET
|
||||||
result = httpMethod.toUpperAscii()
|
let upperMethod = httpMethod.toUpperAscii()
|
||||||
|
result = upperMethod
|
||||||
result.add ' '
|
result.add ' '
|
||||||
|
|
||||||
if proxy.isNil or (not proxy.isNil and requestUrl.scheme == "https"):
|
if proxy.isNil or requestUrl.scheme == "https":
|
||||||
# /path?query
|
# /path?query
|
||||||
if requestUrl.path[0] != '/': result.add '/'
|
if requestUrl.path[0] != '/': result.add '/'
|
||||||
result.add(requestUrl.path)
|
result.add(requestUrl.path)
|
||||||
|
|
@ -768,7 +773,9 @@ proc generateHeaders(requestUrl: Uri, httpMethod: string,
|
||||||
add(result, "Connection: Keep-Alive\c\L")
|
add(result, "Connection: Keep-Alive\c\L")
|
||||||
|
|
||||||
# Content length header.
|
# Content length header.
|
||||||
if body.len > 0 and not headers.hasKey("Content-Length"):
|
const requiresBody = ["POST", "PUT", "PATCH"]
|
||||||
|
let needsContentLength = body.len > 0 or upperMethod in requiresBody
|
||||||
|
if needsContentLength and not headers.hasKey("Content-Length"):
|
||||||
add(result, "Content-Length: " & $body.len & "\c\L")
|
add(result, "Content-Length: " & $body.len & "\c\L")
|
||||||
|
|
||||||
# Proxy auth header.
|
# Proxy auth header.
|
||||||
|
|
@ -929,7 +936,7 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void]
|
||||||
var i = 0
|
var i = 0
|
||||||
if chunkSizeStr == "":
|
if chunkSizeStr == "":
|
||||||
httpError("Server terminated connection prematurely")
|
httpError("Server terminated connection prematurely")
|
||||||
while true:
|
while i < chunkSizeStr.len:
|
||||||
case chunkSizeStr[i]
|
case chunkSizeStr[i]
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
|
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
|
||||||
|
|
@ -937,8 +944,6 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void]
|
||||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
|
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
|
||||||
of 'A'..'F':
|
of 'A'..'F':
|
||||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
|
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
|
||||||
of '\0':
|
|
||||||
break
|
|
||||||
of ';':
|
of ';':
|
||||||
# http://tools.ietf.org/html/rfc2616#section-3.6.1
|
# http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||||
# We don't care about chunk-extensions.
|
# We don't care about chunk-extensions.
|
||||||
|
|
|
||||||
|
|
@ -190,11 +190,11 @@ proc len*(headers: HttpHeaders): int = return headers.table.len
|
||||||
proc parseList(line: string, list: var seq[string], start: int): int =
|
proc parseList(line: string, list: var seq[string], start: int): int =
|
||||||
var i = 0
|
var i = 0
|
||||||
var current = ""
|
var current = ""
|
||||||
while line[start + i] notin {'\c', '\l', '\0'}:
|
while start+i < line.len and line[start + i] notin {'\c', '\l'}:
|
||||||
i += line.skipWhitespace(start + i)
|
i += line.skipWhitespace(start + i)
|
||||||
i += line.parseUntil(current, {'\c', '\l', ','}, start + i)
|
i += line.parseUntil(current, {'\c', '\l', ','}, start + i)
|
||||||
list.add(current)
|
list.add(current)
|
||||||
if line[start + i] == ',':
|
if start+i < line.len and line[start + i] == ',':
|
||||||
i.inc # Skip ,
|
i.inc # Skip ,
|
||||||
current.setLen(0)
|
current.setLen(0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ when false:
|
||||||
var dataAvail = false
|
var dataAvail = false
|
||||||
while dataAvail:
|
while dataAvail:
|
||||||
dataAvail = recvLine(client, buf) # TODO: This is incorrect.
|
dataAvail = recvLine(client, buf) # TODO: This is incorrect.
|
||||||
var L = toLower(buf.string)
|
var L = toLowerAscii(buf.string)
|
||||||
if L.startsWith("content-length:"):
|
if L.startsWith("content-length:"):
|
||||||
var i = len("content-length:")
|
var i = len("content-length:")
|
||||||
while L[i] in Whitespace: inc(i)
|
while L[i] in Whitespace: inc(i)
|
||||||
|
|
@ -199,7 +199,7 @@ when false:
|
||||||
notFound(client)
|
notFound(client)
|
||||||
else:
|
else:
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var ext = splitFile(path).ext.toLower
|
var ext = splitFile(path).ext.toLowerAscii
|
||||||
if ext == ".exe" or ext == ".cgi":
|
if ext == ".exe" or ext == ".cgi":
|
||||||
# XXX: extract interpreter information here?
|
# XXX: extract interpreter information here?
|
||||||
cgi = true
|
cgi = true
|
||||||
|
|
@ -303,7 +303,7 @@ proc next*(s: var Server) =
|
||||||
if s.reqMethod == "POST":
|
if s.reqMethod == "POST":
|
||||||
# Check for Expect header
|
# Check for Expect header
|
||||||
if s.headers.hasKey("Expect"):
|
if s.headers.hasKey("Expect"):
|
||||||
if s.headers["Expect"].toLower == "100-continue":
|
if s.headers["Expect"].toLowerAscii == "100-continue":
|
||||||
s.client.sendStatus("100 Continue")
|
s.client.sendStatus("100 Continue")
|
||||||
else:
|
else:
|
||||||
s.client.sendStatus("417 Expectation Failed")
|
s.client.sendStatus("417 Expectation Failed")
|
||||||
|
|
@ -427,7 +427,7 @@ proc nextAsync(s: PAsyncHTTPServer) =
|
||||||
if s.reqMethod == "POST":
|
if s.reqMethod == "POST":
|
||||||
# Check for Expect header
|
# Check for Expect header
|
||||||
if s.headers.hasKey("Expect"):
|
if s.headers.hasKey("Expect"):
|
||||||
if s.headers["Expect"].toLower == "100-continue":
|
if s.headers["Expect"].toLowerAscii == "100-continue":
|
||||||
s.client.sendStatus("100 Continue")
|
s.client.sendStatus("100 Continue")
|
||||||
else:
|
else:
|
||||||
s.client.sendStatus("417 Expectation Failed")
|
s.client.sendStatus("417 Expectation Failed")
|
||||||
|
|
|
||||||
|
|
@ -696,7 +696,7 @@ proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
|
||||||
else: return n.num
|
else: return n.num
|
||||||
|
|
||||||
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} =
|
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} =
|
||||||
## Deprecated - use getInt or getBiggestInt instead
|
## **Deprecated since v0.18.2:** use ``getInt`` or ``getBiggestInt`` instead.
|
||||||
getBiggestInt(n, default)
|
getBiggestInt(n, default)
|
||||||
|
|
||||||
proc getFloat*(n: JsonNode, default: float = 0.0): float =
|
proc getFloat*(n: JsonNode, default: float = 0.0): float =
|
||||||
|
|
@ -710,7 +710,7 @@ proc getFloat*(n: JsonNode, default: float = 0.0): float =
|
||||||
else: return default
|
else: return default
|
||||||
|
|
||||||
proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} =
|
proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} =
|
||||||
## Deprecated - use getFloat instead
|
## **Deprecated since v0.18.2:** use ``getFloat`` instead.
|
||||||
getFloat(n, default)
|
getFloat(n, default)
|
||||||
|
|
||||||
proc getBool*(n: JsonNode, default: bool = false): bool =
|
proc getBool*(n: JsonNode, default: bool = false): bool =
|
||||||
|
|
@ -721,7 +721,7 @@ proc getBool*(n: JsonNode, default: bool = false): bool =
|
||||||
else: return n.bval
|
else: return n.bval
|
||||||
|
|
||||||
proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} =
|
proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} =
|
||||||
## Deprecated - use getBVal instead
|
## **Deprecated since v0.18.2:** use ``getBool`` instead.
|
||||||
getBool(n, default)
|
getBool(n, default)
|
||||||
|
|
||||||
proc getFields*(n: JsonNode,
|
proc getFields*(n: JsonNode,
|
||||||
|
|
@ -947,7 +947,7 @@ proc contains*(node: JsonNode, val: JsonNode): bool =
|
||||||
find(node.elems, val) >= 0
|
find(node.elems, val) >= 0
|
||||||
|
|
||||||
proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
|
proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
|
||||||
## Deprecated for `hasKey`
|
## **Deprecated:** use `hasKey` instead.
|
||||||
|
|
||||||
proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
|
proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
|
||||||
## Sets a field from a `JObject`.
|
## Sets a field from a `JObject`.
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
|
||||||
var v = ""
|
var v = ""
|
||||||
let app = when defined(js): "" else: getAppFilename()
|
let app = when defined(js): "" else: getAppFilename()
|
||||||
while frmt[i] in IdentChars:
|
while frmt[i] in IdentChars:
|
||||||
v.add(toLower(frmt[i]))
|
v.add(toLowerAscii(frmt[i]))
|
||||||
inc(i)
|
inc(i)
|
||||||
case v
|
case v
|
||||||
of "date": result.add(getDateStr())
|
of "date": result.add(getDateStr())
|
||||||
|
|
|
||||||
|
|
@ -29,21 +29,21 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
|
||||||
chars = Letters + Digits + {'!','#','$','%','&',
|
chars = Letters + Digits + {'!','#','$','%','&',
|
||||||
'\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
|
'\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
|
||||||
var i = 0
|
var i = 0
|
||||||
if s[i] notin chars or s[i] == '.': return false
|
if i >= s.len or s[i] notin chars or s[i] == '.': return false
|
||||||
while s[i] in chars:
|
while i < s.len and s[i] in chars:
|
||||||
if s[i] == '.' and s[i+1] == '.': return false
|
if i+1 < s.len and s[i] == '.' and s[i+1] == '.': return false
|
||||||
inc(i)
|
inc(i)
|
||||||
if s[i] != '@': return false
|
if i >= s.len or s[i] != '@': return false
|
||||||
var j = len(s)-1
|
var j = len(s)-1
|
||||||
if s[j] notin Letters: return false
|
if j >= 0 and s[j] notin Letters: return false
|
||||||
while j >= i and s[j] in Letters: dec(j)
|
while j >= i and s[j] in Letters: dec(j)
|
||||||
inc(i) # skip '@'
|
inc(i) # skip '@'
|
||||||
while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
|
while i < s.len and s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
|
||||||
if s[i] != '\0': return false
|
if i != s.len: return false
|
||||||
|
|
||||||
var x = substr(s, j+1)
|
var x = substr(s, j+1)
|
||||||
if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
|
if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
|
||||||
case toLower(x)
|
case toLowerAscii(x)
|
||||||
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
|
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
|
||||||
"aero", "jobs", "museum": return true
|
"aero", "jobs", "museum": return true
|
||||||
else: return false
|
else: return false
|
||||||
|
|
|
||||||
|
|
@ -1421,8 +1421,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
|
||||||
##
|
##
|
||||||
## **Note:** This proc is not available for SSL sockets.
|
## **Note:** This proc is not available for SSL sockets.
|
||||||
assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
|
assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
|
||||||
var aiList = getAddrInfo(address, port, af)
|
var aiList = getAddrInfo(address, port, af, socket.sockType, socket.protocol)
|
||||||
|
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
var it = aiList
|
var it = aiList
|
||||||
|
|
@ -1443,7 +1442,7 @@ proc sendTo*(socket: Socket, address: string, port: Port,
|
||||||
## this function will try each IP of that hostname.
|
## this function will try each IP of that hostname.
|
||||||
##
|
##
|
||||||
## This is the high-level version of the above ``sendTo`` function.
|
## This is the high-level version of the above ``sendTo`` function.
|
||||||
result = socket.sendTo(address, port, cstring(data), data.len)
|
result = socket.sendTo(address, port, cstring(data), data.len, socket.domain )
|
||||||
|
|
||||||
|
|
||||||
proc isSsl*(socket: Socket): bool =
|
proc isSsl*(socket: Socket): bool =
|
||||||
|
|
|
||||||
|
|
@ -1060,18 +1060,17 @@ proc parseCmdLine*(c: string): seq[string] {.
|
||||||
while true:
|
while true:
|
||||||
setLen(a, 0)
|
setLen(a, 0)
|
||||||
# eat all delimiting whitespace
|
# eat all delimiting whitespace
|
||||||
while c[i] == ' ' or c[i] == '\t' or c[i] == '\l' or c[i] == '\r' : inc(i)
|
while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i)
|
||||||
|
if i >= c.len: break
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# parse a single argument according to the above rules:
|
# parse a single argument according to the above rules:
|
||||||
if c[i] == '\0': break
|
|
||||||
var inQuote = false
|
var inQuote = false
|
||||||
while true:
|
while i < c.len:
|
||||||
case c[i]
|
case c[i]
|
||||||
of '\0': break
|
|
||||||
of '\\':
|
of '\\':
|
||||||
var j = i
|
var j = i
|
||||||
while c[j] == '\\': inc(j)
|
while j < c.len and c[j] == '\\': inc(j)
|
||||||
if c[j] == '"':
|
if j < c.len and c[j] == '"':
|
||||||
for k in 1..(j-i) div 2: a.add('\\')
|
for k in 1..(j-i) div 2: a.add('\\')
|
||||||
if (j-i) mod 2 == 0:
|
if (j-i) mod 2 == 0:
|
||||||
i = j
|
i = j
|
||||||
|
|
@ -1084,7 +1083,7 @@ proc parseCmdLine*(c: string): seq[string] {.
|
||||||
of '"':
|
of '"':
|
||||||
inc(i)
|
inc(i)
|
||||||
if not inQuote: inQuote = true
|
if not inQuote: inQuote = true
|
||||||
elif c[i] == '"':
|
elif i < c.len and c[i] == '"':
|
||||||
a.add(c[i])
|
a.add(c[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1102,13 +1101,12 @@ proc parseCmdLine*(c: string): seq[string] {.
|
||||||
of '\'', '\"':
|
of '\'', '\"':
|
||||||
var delim = c[i]
|
var delim = c[i]
|
||||||
inc(i) # skip ' or "
|
inc(i) # skip ' or "
|
||||||
while c[i] != '\0' and c[i] != delim:
|
while i < c.len and c[i] != delim:
|
||||||
add a, c[i]
|
add a, c[i]
|
||||||
inc(i)
|
inc(i)
|
||||||
if c[i] != '\0': inc(i)
|
if i < c.len: inc(i)
|
||||||
of '\0': break
|
|
||||||
else:
|
else:
|
||||||
while c[i] > ' ':
|
while i < c.len and c[i] > ' ':
|
||||||
add(a, c[i])
|
add(a, c[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
add(result, a)
|
add(result, a)
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ proc joinPath*(head, tail: string): string {.
|
||||||
else:
|
else:
|
||||||
result = head & tail
|
result = head & tail
|
||||||
else:
|
else:
|
||||||
if tail[0] in {DirSep, AltSep}:
|
if tail.len > 0 and tail[0] in {DirSep, AltSep}:
|
||||||
result = head & tail
|
result = head & tail
|
||||||
else:
|
else:
|
||||||
result = head & DirSep & tail
|
result = head & DirSep & tail
|
||||||
|
|
@ -477,7 +477,7 @@ proc unixToNativePath*(path: string, drive=""): string {.
|
||||||
|
|
||||||
var i = start
|
var i = start
|
||||||
while i < len(path): # ../../../ --> ::::
|
while i < len(path): # ../../../ --> ::::
|
||||||
if path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
|
if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
|
||||||
# parent directory
|
# parent directory
|
||||||
when defined(macos):
|
when defined(macos):
|
||||||
if result[high(result)] == ':':
|
if result[high(result)] == ':':
|
||||||
|
|
|
||||||
|
|
@ -57,26 +57,26 @@ type
|
||||||
{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
|
{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
|
||||||
|
|
||||||
proc parseWord(s: string, i: int, w: var string,
|
proc parseWord(s: string, i: int, w: var string,
|
||||||
delim: set[char] = {'\x09', ' ', '\0'}): int =
|
delim: set[char] = {'\x09', ' '}): int =
|
||||||
result = i
|
result = i
|
||||||
if s[result] == '\"':
|
if result < s.len and s[result] == '\"':
|
||||||
inc(result)
|
inc(result)
|
||||||
while not (s[result] in {'\0', '\"'}):
|
while result < s.len and s[result] != '\"':
|
||||||
add(w, s[result])
|
add(w, s[result])
|
||||||
inc(result)
|
inc(result)
|
||||||
if s[result] == '\"': inc(result)
|
if result < s.len and s[result] == '\"': inc(result)
|
||||||
else:
|
else:
|
||||||
while not (s[result] in delim):
|
while result < s.len and s[result] notin delim:
|
||||||
add(w, s[result])
|
add(w, s[result])
|
||||||
inc(result)
|
inc(result)
|
||||||
|
|
||||||
when declared(os.paramCount):
|
when declared(os.paramCount):
|
||||||
proc quote(s: string): string =
|
proc quote(s: string): string =
|
||||||
if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
|
if find(s, {' ', '\t'}) >= 0 and s.len > 0 and s[0] != '"':
|
||||||
if s[0] == '-':
|
if s[0] == '-':
|
||||||
result = newStringOfCap(s.len)
|
result = newStringOfCap(s.len)
|
||||||
var i = parseWord(s, 0, result, {'\0', ' ', '\x09', ':', '='})
|
var i = parseWord(s, 0, result, {' ', '\x09', ':', '='})
|
||||||
if s[i] in {':','='}:
|
if i < s.len and s[i] in {':','='}:
|
||||||
result.add s[i]
|
result.add s[i]
|
||||||
inc i
|
inc i
|
||||||
result.add '"'
|
result.add '"'
|
||||||
|
|
@ -144,43 +144,45 @@ proc handleShortOption(p: var OptParser) =
|
||||||
add(p.key.string, p.cmd[i])
|
add(p.key.string, p.cmd[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
p.inShortState = true
|
p.inShortState = true
|
||||||
while p.cmd[i] in {'\x09', ' '}:
|
while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}:
|
||||||
inc(i)
|
inc(i)
|
||||||
p.inShortState = false
|
p.inShortState = false
|
||||||
if p.cmd[i] in {':', '='} or card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal:
|
if i < p.cmd.len and p.cmd[i] in {':', '='} or
|
||||||
if p.cmd[i] in {':', '='}:
|
card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal:
|
||||||
|
if i < p.cmd.len and p.cmd[i] in {':', '='}:
|
||||||
inc(i)
|
inc(i)
|
||||||
p.inShortState = false
|
p.inShortState = false
|
||||||
while p.cmd[i] in {'\x09', ' '}: inc(i)
|
while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
|
||||||
i = parseWord(p.cmd, i, p.val.string)
|
i = parseWord(p.cmd, i, p.val.string)
|
||||||
if p.cmd[i] == '\0': p.inShortState = false
|
if i >= p.cmd.len: p.inShortState = false
|
||||||
p.pos = i
|
p.pos = i
|
||||||
|
|
||||||
proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
|
proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
|
||||||
## parses the first or next option; ``p.kind`` describes what token has been
|
## parses the first or next option; ``p.kind`` describes what token has been
|
||||||
## parsed. ``p.key`` and ``p.val`` are set accordingly.
|
## parsed. ``p.key`` and ``p.val`` are set accordingly.
|
||||||
var i = p.pos
|
var i = p.pos
|
||||||
while p.cmd[i] in {'\x09', ' '}: inc(i)
|
while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
|
||||||
p.pos = i
|
p.pos = i
|
||||||
setLen(p.key.string, 0)
|
setLen(p.key.string, 0)
|
||||||
setLen(p.val.string, 0)
|
setLen(p.val.string, 0)
|
||||||
if p.inShortState:
|
if p.inShortState:
|
||||||
handleShortOption(p)
|
handleShortOption(p)
|
||||||
return
|
return
|
||||||
case p.cmd[i]
|
if i >= p.cmd.len:
|
||||||
of '\0':
|
|
||||||
p.kind = cmdEnd
|
p.kind = cmdEnd
|
||||||
of '-':
|
return
|
||||||
inc(i)
|
|
||||||
if p.cmd[i] == '-':
|
if p.cmd[i] == '-':
|
||||||
|
inc(i)
|
||||||
|
if i < p.cmd.len and p.cmd[i] == '-':
|
||||||
p.kind = cmdLongOption
|
p.kind = cmdLongOption
|
||||||
inc(i)
|
inc(i)
|
||||||
i = parseWord(p.cmd, i, p.key.string, {'\0', ' ', '\x09', ':', '='})
|
i = parseWord(p.cmd, i, p.key.string, {' ', '\x09', ':', '='})
|
||||||
while p.cmd[i] in {'\x09', ' '}: inc(i)
|
while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
|
||||||
if p.cmd[i] in {':', '='} or len(p.longNoVal) > 0 and p.key.string notin p.longNoVal:
|
if i < p.cmd.len and p.cmd[i] in {':', '='} or
|
||||||
if p.cmd[i] in {':', '='}:
|
len(p.longNoVal) > 0 and p.key.string notin p.longNoVal:
|
||||||
|
if i < p.cmd.len and p.cmd[i] in {':', '='}:
|
||||||
inc(i)
|
inc(i)
|
||||||
while p.cmd[i] in {'\x09', ' '}: inc(i)
|
while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
|
||||||
p.pos = parseWord(p.cmd, i, p.val.string)
|
p.pos = parseWord(p.cmd, i, p.val.string)
|
||||||
else:
|
else:
|
||||||
p.pos = i
|
p.pos = i
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,9 @@ proc parseHex*(s: string, number: var int, start = 0; maxLen = 0): int {.
|
||||||
## upper bound. Not more than ```maxLen`` characters are parsed.
|
## upper bound. Not more than ```maxLen`` characters are parsed.
|
||||||
var i = start
|
var i = start
|
||||||
var foundDigit = false
|
var foundDigit = false
|
||||||
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
|
||||||
elif s[i] == '#': inc(i)
|
|
||||||
let last = if maxLen == 0: s.len else: i+maxLen
|
let last = if maxLen == 0: s.len else: i+maxLen
|
||||||
|
if i+1 < last and s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||||
|
elif i < last and s[i] == '#': inc(i)
|
||||||
while i < last:
|
while i < last:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '_': discard
|
of '_': discard
|
||||||
|
|
@ -76,8 +76,8 @@ proc parseOct*(s: string, number: var int, start = 0): int {.
|
||||||
## the number of the parsed characters or 0 in case of an error.
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
var i = start
|
var i = start
|
||||||
var foundDigit = false
|
var foundDigit = false
|
||||||
if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
||||||
while true:
|
while i < s.len:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '_': discard
|
of '_': discard
|
||||||
of '0'..'7':
|
of '0'..'7':
|
||||||
|
|
@ -93,8 +93,8 @@ proc parseBin*(s: string, number: var int, start = 0): int {.
|
||||||
## the number of the parsed characters or 0 in case of an error.
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
var i = start
|
var i = start
|
||||||
var foundDigit = false
|
var foundDigit = false
|
||||||
if s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2)
|
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2)
|
||||||
while true:
|
while i < s.len:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '_': discard
|
of '_': discard
|
||||||
of '0'..'1':
|
of '0'..'1':
|
||||||
|
|
@ -108,9 +108,9 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
|
||||||
## parses an identifier and stores it in ``ident``. Returns
|
## parses an identifier and stores it in ``ident``. Returns
|
||||||
## the number of the parsed characters or 0 in case of an error.
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
var i = start
|
var i = start
|
||||||
if s[i] in IdentStartChars:
|
if i < s.len and s[i] in IdentStartChars:
|
||||||
inc(i)
|
inc(i)
|
||||||
while s[i] in IdentChars: inc(i)
|
while i < s.len and s[i] in IdentChars: inc(i)
|
||||||
ident = substr(s, start, i-1)
|
ident = substr(s, start, i-1)
|
||||||
result = i-start
|
result = i-start
|
||||||
|
|
||||||
|
|
@ -119,11 +119,9 @@ proc parseIdent*(s: string, start = 0): string =
|
||||||
## Returns the parsed identifier or an empty string in case of an error.
|
## Returns the parsed identifier or an empty string in case of an error.
|
||||||
result = ""
|
result = ""
|
||||||
var i = start
|
var i = start
|
||||||
|
if i < s.len and s[i] in IdentStartChars:
|
||||||
if s[i] in IdentStartChars:
|
|
||||||
inc(i)
|
inc(i)
|
||||||
while s[i] in IdentChars: inc(i)
|
while i < s.len and s[i] in IdentChars: inc(i)
|
||||||
|
|
||||||
result = substr(s, start, i-1)
|
result = substr(s, start, i-1)
|
||||||
|
|
||||||
proc parseToken*(s: string, token: var string, validChars: set[char],
|
proc parseToken*(s: string, token: var string, validChars: set[char],
|
||||||
|
|
@ -134,24 +132,26 @@ proc parseToken*(s: string, token: var string, validChars: set[char],
|
||||||
##
|
##
|
||||||
## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead.
|
## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead.
|
||||||
var i = start
|
var i = start
|
||||||
while s[i] in validChars: inc(i)
|
while i < s.len and s[i] in validChars: inc(i)
|
||||||
result = i-start
|
result = i-start
|
||||||
token = substr(s, start, i-1)
|
token = substr(s, start, i-1)
|
||||||
|
|
||||||
proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
||||||
## skips the whitespace starting at ``s[start]``. Returns the number of
|
## skips the whitespace starting at ``s[start]``. Returns the number of
|
||||||
## skipped characters.
|
## skipped characters.
|
||||||
while s[start+result] in Whitespace: inc(result)
|
while start+result < s.len and s[start+result] in Whitespace: inc(result)
|
||||||
|
|
||||||
proc skip*(s, token: string, start = 0): int {.inline.} =
|
proc skip*(s, token: string, start = 0): int {.inline.} =
|
||||||
## skips the `token` starting at ``s[start]``. Returns the length of `token`
|
## skips the `token` starting at ``s[start]``. Returns the length of `token`
|
||||||
## or 0 if there was no `token` at ``s[start]``.
|
## or 0 if there was no `token` at ``s[start]``.
|
||||||
while result < token.len and s[result+start] == token[result]: inc(result)
|
while start+result < s.len and result < token.len and
|
||||||
|
s[result+start] == token[result]:
|
||||||
|
inc(result)
|
||||||
if result != token.len: result = 0
|
if result != token.len: result = 0
|
||||||
|
|
||||||
proc skipIgnoreCase*(s, token: string, start = 0): int =
|
proc skipIgnoreCase*(s, token: string, start = 0): int =
|
||||||
## same as `skip` but case is ignored for token matching.
|
## same as `skip` but case is ignored for token matching.
|
||||||
while result < token.len and
|
while start+result < s.len and result < token.len and
|
||||||
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
||||||
if result != token.len: result = 0
|
if result != token.len: result = 0
|
||||||
|
|
||||||
|
|
@ -159,18 +159,18 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
|
||||||
## Skips all characters until one char from the set `until` is found
|
## Skips all characters until one char from the set `until` is found
|
||||||
## or the end is reached.
|
## or the end is reached.
|
||||||
## Returns number of characters skipped.
|
## Returns number of characters skipped.
|
||||||
while s[result+start] notin until and s[result+start] != '\0': inc(result)
|
while start+result < s.len and s[result+start] notin until: inc(result)
|
||||||
|
|
||||||
proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
||||||
## Skips all characters until the char `until` is found
|
## Skips all characters until the char `until` is found
|
||||||
## or the end is reached.
|
## or the end is reached.
|
||||||
## Returns number of characters skipped.
|
## Returns number of characters skipped.
|
||||||
while s[result+start] != until and s[result+start] != '\0': inc(result)
|
while start+result < s.len and s[result+start] != until: inc(result)
|
||||||
|
|
||||||
proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
||||||
## Skips all characters while one char from the set `token` is found.
|
## Skips all characters while one char from the set `token` is found.
|
||||||
## Returns number of characters skipped.
|
## Returns number of characters skipped.
|
||||||
while s[result+start] in toSkip and s[result+start] != '\0': inc(result)
|
while start+result < s.len and s[result+start] in toSkip: inc(result)
|
||||||
|
|
||||||
proc parseUntil*(s: string, token: var string, until: set[char],
|
proc parseUntil*(s: string, token: var string, until: set[char],
|
||||||
start = 0): int {.inline.} =
|
start = 0): int {.inline.} =
|
||||||
|
|
@ -214,7 +214,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
|
||||||
## the number of the parsed characters or 0 in case of an error. A token
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
## consists of the characters in `validChars`.
|
## consists of the characters in `validChars`.
|
||||||
var i = start
|
var i = start
|
||||||
while s[i] in validChars: inc(i)
|
while i < s.len and s[i] in validChars: inc(i)
|
||||||
result = i-start
|
result = i-start
|
||||||
token = substr(s, start, i-1)
|
token = substr(s, start, i-1)
|
||||||
|
|
||||||
|
|
@ -231,16 +231,17 @@ proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
|
||||||
var
|
var
|
||||||
sign: BiggestInt = -1
|
sign: BiggestInt = -1
|
||||||
i = start
|
i = start
|
||||||
|
if i < s.len:
|
||||||
if s[i] == '+': inc(i)
|
if s[i] == '+': inc(i)
|
||||||
elif s[i] == '-':
|
elif s[i] == '-':
|
||||||
inc(i)
|
inc(i)
|
||||||
sign = 1
|
sign = 1
|
||||||
if s[i] in {'0'..'9'}:
|
if i < s.len and s[i] in {'0'..'9'}:
|
||||||
b = 0
|
b = 0
|
||||||
while s[i] in {'0'..'9'}:
|
while i < s.len and s[i] in {'0'..'9'}:
|
||||||
b = b * 10 - (ord(s[i]) - ord('0'))
|
b = b * 10 - (ord(s[i]) - ord('0'))
|
||||||
inc(i)
|
inc(i)
|
||||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
b = b * sign
|
b = b * sign
|
||||||
result = i - start
|
result = i - start
|
||||||
{.pop.} # overflowChecks
|
{.pop.} # overflowChecks
|
||||||
|
|
@ -281,17 +282,17 @@ proc parseSaturatedNatural*(s: string, b: var int, start = 0): int =
|
||||||
## discard parseSaturatedNatural("848", res)
|
## discard parseSaturatedNatural("848", res)
|
||||||
## doAssert res == 848
|
## doAssert res == 848
|
||||||
var i = start
|
var i = start
|
||||||
if s[i] == '+': inc(i)
|
if i < s.len and s[i] == '+': inc(i)
|
||||||
if s[i] in {'0'..'9'}:
|
if i < s.len and s[i] in {'0'..'9'}:
|
||||||
b = 0
|
b = 0
|
||||||
while s[i] in {'0'..'9'}:
|
while i < s.len and s[i] in {'0'..'9'}:
|
||||||
let c = ord(s[i]) - ord('0')
|
let c = ord(s[i]) - ord('0')
|
||||||
if b <= (high(int) - c) div 10:
|
if b <= (high(int) - c) div 10:
|
||||||
b = b * 10 + c
|
b = b * 10 + c
|
||||||
else:
|
else:
|
||||||
b = high(int)
|
b = high(int)
|
||||||
inc(i)
|
inc(i)
|
||||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
result = i - start
|
result = i - start
|
||||||
|
|
||||||
# overflowChecks doesn't work with BiggestUInt
|
# overflowChecks doesn't work with BiggestUInt
|
||||||
|
|
@ -300,16 +301,16 @@ proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
|
||||||
res = 0.BiggestUInt
|
res = 0.BiggestUInt
|
||||||
prev = 0.BiggestUInt
|
prev = 0.BiggestUInt
|
||||||
i = start
|
i = start
|
||||||
if s[i] == '+': inc(i) # Allow
|
if i < s.len and s[i] == '+': inc(i) # Allow
|
||||||
if s[i] in {'0'..'9'}:
|
if i < s.len and s[i] in {'0'..'9'}:
|
||||||
b = 0
|
b = 0
|
||||||
while s[i] in {'0'..'9'}:
|
while i < s.len and s[i] in {'0'..'9'}:
|
||||||
prev = res
|
prev = res
|
||||||
res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
|
res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
|
||||||
if prev > res:
|
if prev > res:
|
||||||
return 0 # overflowChecks emulation
|
return 0 # overflowChecks emulation
|
||||||
inc(i)
|
inc(i)
|
||||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
b = res
|
b = res
|
||||||
result = i - start
|
result = i - start
|
||||||
|
|
||||||
|
|
@ -389,31 +390,31 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
||||||
var kind: InterpolatedKind
|
var kind: InterpolatedKind
|
||||||
while true:
|
while true:
|
||||||
var j = i
|
var j = i
|
||||||
if s[j] == '$':
|
if j < s.len and s[j] == '$':
|
||||||
if s[j+1] == '{':
|
if j+1 < s.len and s[j+1] == '{':
|
||||||
inc j, 2
|
inc j, 2
|
||||||
var nesting = 0
|
var nesting = 0
|
||||||
while true:
|
block curlies:
|
||||||
|
while j < s.len:
|
||||||
case s[j]
|
case s[j]
|
||||||
of '{': inc nesting
|
of '{': inc nesting
|
||||||
of '}':
|
of '}':
|
||||||
if nesting == 0:
|
if nesting == 0:
|
||||||
inc j
|
inc j
|
||||||
break
|
break curlies
|
||||||
dec nesting
|
dec nesting
|
||||||
of '\0':
|
|
||||||
raise newException(ValueError,
|
|
||||||
"Expected closing '}': " & substr(s, i, s.high))
|
|
||||||
else: discard
|
else: discard
|
||||||
inc j
|
inc j
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Expected closing '}': " & substr(s, i, s.high))
|
||||||
inc i, 2 # skip ${
|
inc i, 2 # skip ${
|
||||||
kind = ikExpr
|
kind = ikExpr
|
||||||
elif s[j+1] in IdentStartChars:
|
elif j+1 < s.len and s[j+1] in IdentStartChars:
|
||||||
inc j, 2
|
inc j, 2
|
||||||
while s[j] in IdentChars: inc(j)
|
while j < s.len and s[j] in IdentChars: inc(j)
|
||||||
inc i # skip $
|
inc i # skip $
|
||||||
kind = ikVar
|
kind = ikVar
|
||||||
elif s[j+1] == '$':
|
elif j+1 < s.len and s[j+1] == '$':
|
||||||
inc j, 2
|
inc j, 2
|
||||||
inc i # skip $
|
inc i # skip $
|
||||||
kind = ikDollar
|
kind = ikDollar
|
||||||
|
|
|
||||||
|
|
@ -534,15 +534,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
case p.kind
|
case p.kind
|
||||||
of pkEmpty: result = 0 # match of length 0
|
of pkEmpty: result = 0 # match of length 0
|
||||||
of pkAny:
|
of pkAny:
|
||||||
if s[start] != '\0': result = 1
|
if start < s.len: result = 1
|
||||||
else: result = -1
|
else: result = -1
|
||||||
of pkAnyRune:
|
of pkAnyRune:
|
||||||
if s[start] != '\0':
|
if start < s.len:
|
||||||
result = runeLenAt(s, start)
|
result = runeLenAt(s, start)
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkLetter:
|
of pkLetter:
|
||||||
if s[start] != '\0':
|
if start < s.len:
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
fastRuneAt(s, result, a)
|
fastRuneAt(s, result, a)
|
||||||
|
|
@ -551,7 +551,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkLower:
|
of pkLower:
|
||||||
if s[start] != '\0':
|
if start < s.len:
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
fastRuneAt(s, result, a)
|
fastRuneAt(s, result, a)
|
||||||
|
|
@ -560,7 +560,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkUpper:
|
of pkUpper:
|
||||||
if s[start] != '\0':
|
if start < s.len:
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
fastRuneAt(s, result, a)
|
fastRuneAt(s, result, a)
|
||||||
|
|
@ -569,7 +569,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkTitle:
|
of pkTitle:
|
||||||
if s[start] != '\0':
|
if start < s.len:
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
fastRuneAt(s, result, a)
|
fastRuneAt(s, result, a)
|
||||||
|
|
@ -578,7 +578,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkWhitespace:
|
of pkWhitespace:
|
||||||
if s[start] != '\0':
|
if start < s.len:
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
fastRuneAt(s, result, a)
|
fastRuneAt(s, result, a)
|
||||||
|
|
@ -589,15 +589,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
of pkGreedyAny:
|
of pkGreedyAny:
|
||||||
result = len(s) - start
|
result = len(s) - start
|
||||||
of pkNewLine:
|
of pkNewLine:
|
||||||
if s[start] == '\L': result = 1
|
if start < s.len and s[start] == '\L': result = 1
|
||||||
elif s[start] == '\C':
|
elif start < s.len and s[start] == '\C':
|
||||||
if s[start+1] == '\L': result = 2
|
if start+1 < s.len and s[start+1] == '\L': result = 2
|
||||||
else: result = 1
|
else: result = 1
|
||||||
else: result = -1
|
else: result = -1
|
||||||
of pkTerminal:
|
of pkTerminal:
|
||||||
result = len(p.term)
|
result = len(p.term)
|
||||||
for i in 0..result-1:
|
for i in 0..result-1:
|
||||||
if p.term[i] != s[start+i]:
|
if start+i >= s.len or p.term[i] != s[start+i]:
|
||||||
result = -1
|
result = -1
|
||||||
break
|
break
|
||||||
of pkTerminalIgnoreCase:
|
of pkTerminalIgnoreCase:
|
||||||
|
|
@ -606,6 +606,9 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
a, b: Rune
|
a, b: Rune
|
||||||
result = start
|
result = start
|
||||||
while i < len(p.term):
|
while i < len(p.term):
|
||||||
|
if result >= s.len:
|
||||||
|
result = -1
|
||||||
|
break
|
||||||
fastRuneAt(p.term, i, a)
|
fastRuneAt(p.term, i, a)
|
||||||
fastRuneAt(s, result, b)
|
fastRuneAt(s, result, b)
|
||||||
if toLower(a) != toLower(b):
|
if toLower(a) != toLower(b):
|
||||||
|
|
@ -621,18 +624,23 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
while true:
|
while true:
|
||||||
fastRuneAt(p.term, i, a)
|
fastRuneAt(p.term, i, a)
|
||||||
if a != Rune('_'): break
|
if a != Rune('_'): break
|
||||||
while true:
|
while result < s.len:
|
||||||
fastRuneAt(s, result, b)
|
fastRuneAt(s, result, b)
|
||||||
if b != Rune('_'): break
|
if b != Rune('_'): break
|
||||||
if toLower(a) != toLower(b):
|
if result >= s.len:
|
||||||
|
if i >= p.term.len: break
|
||||||
|
else:
|
||||||
|
result = -1
|
||||||
|
break
|
||||||
|
elif toLower(a) != toLower(b):
|
||||||
result = -1
|
result = -1
|
||||||
break
|
break
|
||||||
dec(result, start)
|
dec(result, start)
|
||||||
of pkChar:
|
of pkChar:
|
||||||
if p.ch == s[start]: result = 1
|
if start < s.len and p.ch == s[start]: result = 1
|
||||||
else: result = -1
|
else: result = -1
|
||||||
of pkCharChoice:
|
of pkCharChoice:
|
||||||
if contains(p.charChoice[], s[start]): result = 1
|
if start < s.len and contains(p.charChoice[], s[start]): result = 1
|
||||||
else: result = -1
|
else: result = -1
|
||||||
of pkNonTerminal:
|
of pkNonTerminal:
|
||||||
var oldMl = c.ml
|
var oldMl = c.ml
|
||||||
|
|
@ -695,10 +703,10 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
of pkGreedyRepChar:
|
of pkGreedyRepChar:
|
||||||
result = 0
|
result = 0
|
||||||
var ch = p.ch
|
var ch = p.ch
|
||||||
while ch == s[start+result]: inc(result)
|
while start+result < s.len and ch == s[start+result]: inc(result)
|
||||||
of pkGreedyRepSet:
|
of pkGreedyRepSet:
|
||||||
result = 0
|
result = 0
|
||||||
while contains(p.charChoice[], s[start+result]): inc(result)
|
while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result)
|
||||||
of pkOption:
|
of pkOption:
|
||||||
result = max(0, rawMatch(s, p.sons[0], start, c))
|
result = max(0, rawMatch(s, p.sons[0], start, c))
|
||||||
of pkAndPredicate:
|
of pkAndPredicate:
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ template callFormatOption(res, arg, option) {.dirty.} =
|
||||||
macro `&`*(pattern: string): untyped =
|
macro `&`*(pattern: string): untyped =
|
||||||
## For a specification of the ``&`` macro, see the module level documentation.
|
## For a specification of the ``&`` macro, see the module level documentation.
|
||||||
if pattern.kind notin {nnkStrLit..nnkTripleStrLit}:
|
if pattern.kind notin {nnkStrLit..nnkTripleStrLit}:
|
||||||
error "& only works with string literals", pattern
|
error "string formatting (fmt(), &) only works with string literals", pattern
|
||||||
let f = pattern.strVal
|
let f = pattern.strVal
|
||||||
var i = 0
|
var i = 0
|
||||||
let res = genSym(nskVar, "fmtRes")
|
let res = genSym(nskVar, "fmtRes")
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ which we then use in our scanf pattern to help us in the matching process:
|
||||||
proc someSep(input: string; start: int; seps: set[char] = {':','-','.'}): int =
|
proc someSep(input: string; start: int; seps: set[char] = {':','-','.'}): int =
|
||||||
# Note: The parameters and return value must match to what ``scanf`` requires
|
# Note: The parameters and return value must match to what ``scanf`` requires
|
||||||
result = 0
|
result = 0
|
||||||
while input[start+result] in seps: inc result
|
while start+result < input.len and input[start+result] in seps: inc result
|
||||||
|
|
||||||
if scanf(input, "$w$[someSep]$w", key, value):
|
if scanf(input, "$w$[someSep]$w", key, value):
|
||||||
...
|
...
|
||||||
|
|
@ -231,7 +231,7 @@ is performed.
|
||||||
var i = start
|
var i = start
|
||||||
var u = 0
|
var u = 0
|
||||||
while true:
|
while true:
|
||||||
if s[i] == '\0' or s[i] == unless:
|
if i >= s.len or s[i] == unless:
|
||||||
return 0
|
return 0
|
||||||
elif s[i] == until[0]:
|
elif s[i] == until[0]:
|
||||||
u = 1
|
u = 1
|
||||||
|
|
@ -315,6 +315,8 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
conds.add resLen.notZero
|
conds.add resLen.notZero
|
||||||
conds.add resLen
|
conds.add resLen
|
||||||
|
|
||||||
|
template at(s: string; i: int): char = (if i < s.len: s[i] else: '\0')
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
var p = 0
|
var p = 0
|
||||||
var idx = genSym(nskVar, "idx")
|
var idx = genSym(nskVar, "idx")
|
||||||
|
|
@ -397,7 +399,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
var nesting = 0
|
var nesting = 0
|
||||||
let start = p
|
let start = p
|
||||||
while true:
|
while true:
|
||||||
case pattern[p]
|
case pattern.at(p)
|
||||||
of '{': inc nesting
|
of '{': inc nesting
|
||||||
of '}':
|
of '}':
|
||||||
if nesting == 0: break
|
if nesting == 0: break
|
||||||
|
|
@ -419,7 +421,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
var nesting = 0
|
var nesting = 0
|
||||||
let start = p
|
let start = p
|
||||||
while true:
|
while true:
|
||||||
case pattern[p]
|
case pattern.at(p)
|
||||||
of '[': inc nesting
|
of '[': inc nesting
|
||||||
of ']':
|
of ']':
|
||||||
if nesting == 0: break
|
if nesting == 0: break
|
||||||
|
|
@ -451,10 +453,12 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||||
|
|
||||||
template atom*(input: string; idx: int; c: char): bool =
|
template atom*(input: string; idx: int; c: char): bool =
|
||||||
## Used in scanp for the matching of atoms (usually chars).
|
## Used in scanp for the matching of atoms (usually chars).
|
||||||
input[idx] == c
|
idx < input.len and input[idx] == c
|
||||||
|
|
||||||
template atom*(input: string; idx: int; s: set[char]): bool =
|
template atom*(input: string; idx: int; s: set[char]): bool =
|
||||||
input[idx] in s
|
idx < input.len and input[idx] in s
|
||||||
|
|
||||||
|
template hasNxt*(input: string; idx: int): bool = idx < input.len
|
||||||
|
|
||||||
#template prepare*(input: string): int = 0
|
#template prepare*(input: string): int = 0
|
||||||
template success*(x: int): bool = x != 0
|
template success*(x: int): bool = x != 0
|
||||||
|
|
@ -462,7 +466,7 @@ template success*(x: int): bool = x != 0
|
||||||
template nxt*(input: string; idx, step: int = 1) = inc(idx, step)
|
template nxt*(input: string; idx, step: int = 1) = inc(idx, step)
|
||||||
|
|
||||||
macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||||
## ``scanp`` is currently undocumented.
|
## See top level documentation of his module of how ``scanf`` works.
|
||||||
type StmtTriple = tuple[init, cond, action: NimNode]
|
type StmtTriple = tuple[init, cond, action: NimNode]
|
||||||
|
|
||||||
template interf(x): untyped = bindSym(x, brForceOpen)
|
template interf(x): untyped = bindSym(x, brForceOpen)
|
||||||
|
|
@ -508,8 +512,8 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||||
!!newCall(interf"nxt", input, idx, resLen))
|
!!newCall(interf"nxt", input, idx, resLen))
|
||||||
of nnkCallKinds:
|
of nnkCallKinds:
|
||||||
# *{'A'..'Z'} !! s.add(!_)
|
# *{'A'..'Z'} !! s.add(!_)
|
||||||
template buildWhile(init, cond, action): untyped =
|
template buildWhile(input, idx, init, cond, action): untyped =
|
||||||
while true:
|
while hasNxt(input, idx):
|
||||||
init
|
init
|
||||||
if not cond: break
|
if not cond: break
|
||||||
action
|
action
|
||||||
|
|
@ -528,7 +532,7 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||||
!!newCall(interf"nxt", input, idx, it[2]))
|
!!newCall(interf"nxt", input, idx, it[2]))
|
||||||
elif it.kind == nnkPrefix and it[0].eqIdent"*":
|
elif it.kind == nnkPrefix and it[0].eqIdent"*":
|
||||||
let (init, cond, action) = atm(it[1], input, idx, attached)
|
let (init, cond, action) = atm(it[1], input, idx, attached)
|
||||||
result = (getAst(buildWhile(init, cond, action)),
|
result = (getAst(buildWhile(input, idx, init, cond, action)),
|
||||||
newEmptyNode(), newEmptyNode())
|
newEmptyNode(), newEmptyNode())
|
||||||
elif it.kind == nnkPrefix and it[0].eqIdent"+":
|
elif it.kind == nnkPrefix and it[0].eqIdent"+":
|
||||||
# x+ is the same as xx*
|
# x+ is the same as xx*
|
||||||
|
|
@ -621,7 +625,7 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
proc twoDigits(input: string; x: var int; start: int): int =
|
proc twoDigits(input: string; x: var int; start: int): int =
|
||||||
if input[start] == '0' and input[start+1] == '0':
|
if start+1 < input.len and input[start] == '0' and input[start+1] == '0':
|
||||||
result = 2
|
result = 2
|
||||||
x = 13
|
x = 13
|
||||||
else:
|
else:
|
||||||
|
|
@ -629,10 +633,10 @@ when isMainModule:
|
||||||
|
|
||||||
proc someSep(input: string; start: int; seps: set[char] = {';',',','-','.'}): int =
|
proc someSep(input: string; start: int; seps: set[char] = {';',',','-','.'}): int =
|
||||||
result = 0
|
result = 0
|
||||||
while input[start+result] in seps: inc result
|
while start+result < input.len and input[start+result] in seps: inc result
|
||||||
|
|
||||||
proc demangle(s: string; res: var string; start: int): int =
|
proc demangle(s: string; res: var string; start: int): int =
|
||||||
while s[result+start] in {'_', '@'}: inc result
|
while result+start < s.len and s[result+start] in {'_', '@'}: inc result
|
||||||
res = ""
|
res = ""
|
||||||
while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_':
|
while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_':
|
||||||
res.add s[result+start]
|
res.add s[result+start]
|
||||||
|
|
@ -652,7 +656,7 @@ when isMainModule:
|
||||||
var info = ""
|
var info = ""
|
||||||
if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "),
|
if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "),
|
||||||
demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')',
|
demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')',
|
||||||
*`whites`, "at ", +(~{'\C', '\L', '\0'} -> info.add($_)) ):
|
*`whites`, "at ", +(~{'\C', '\L'} -> info.add($_)) ):
|
||||||
result.add prc & " " & info
|
result.add prc & " " & info
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
@ -713,7 +717,7 @@ when isMainModule:
|
||||||
"NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605",
|
"NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605",
|
||||||
"NimMain c:/users/anwender/projects/nim/lib/system.nim:2613",
|
"NimMain c:/users/anwender/projects/nim/lib/system.nim:2613",
|
||||||
"main c:/users/anwender/projects/nim/lib/system.nim:2620"]
|
"main c:/users/anwender/projects/nim/lib/system.nim:2620"]
|
||||||
doAssert parseGDB(gdbOut) == result
|
#doAssert parseGDB(gdbOut) == result
|
||||||
|
|
||||||
# bug #6487
|
# bug #6487
|
||||||
var count = 0
|
var count = 0
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ type
|
||||||
modeCaseSensitive, ## the table is case sensitive
|
modeCaseSensitive, ## the table is case sensitive
|
||||||
modeCaseInsensitive, ## the table is case insensitive
|
modeCaseInsensitive, ## the table is case insensitive
|
||||||
modeStyleInsensitive ## the table is style insensitive
|
modeStyleInsensitive ## the table is style insensitive
|
||||||
KeyValuePair = tuple[key, val: string]
|
KeyValuePair = tuple[key, val: string, hasValue: bool]
|
||||||
KeyValuePairSeq = seq[KeyValuePair]
|
KeyValuePairSeq = seq[KeyValuePair]
|
||||||
StringTableObj* = object of RootObj
|
StringTableObj* = object of RootObj
|
||||||
counter: int
|
counter: int
|
||||||
|
|
@ -48,19 +48,19 @@ proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} =
|
||||||
iterator pairs*(t: StringTableRef): tuple[key, value: string] =
|
iterator pairs*(t: StringTableRef): tuple[key, value: string] =
|
||||||
## iterates over every (key, value) pair in the table `t`.
|
## iterates over every (key, value) pair in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if not isNil(t.data[h].key):
|
if t.data[h].hasValue:
|
||||||
yield (t.data[h].key, t.data[h].val)
|
yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator keys*(t: StringTableRef): string =
|
iterator keys*(t: StringTableRef): string =
|
||||||
## iterates over every key in the table `t`.
|
## iterates over every key in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if not isNil(t.data[h].key):
|
if t.data[h].hasValue:
|
||||||
yield t.data[h].key
|
yield t.data[h].key
|
||||||
|
|
||||||
iterator values*(t: StringTableRef): string =
|
iterator values*(t: StringTableRef): string =
|
||||||
## iterates over every value in the table `t`.
|
## iterates over every value in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if not isNil(t.data[h].key):
|
if t.data[h].hasValue:
|
||||||
yield t.data[h].val
|
yield t.data[h].val
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -102,7 +102,7 @@ proc nextTry(h, maxHash: Hash): Hash {.inline.} =
|
||||||
|
|
||||||
proc rawGet(t: StringTableRef, key: string): int =
|
proc rawGet(t: StringTableRef, key: string): int =
|
||||||
var h: Hash = myhash(t, key) and high(t.data) # start with real hash value
|
var h: Hash = myhash(t, key) and high(t.data) # start with real hash value
|
||||||
while not isNil(t.data[h].key):
|
while t.data[h].hasValue:
|
||||||
if myCmp(t, t.data[h].key, key):
|
if myCmp(t, t.data[h].key, key):
|
||||||
return h
|
return h
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
|
|
@ -144,16 +144,17 @@ proc contains*(t: StringTableRef, key: string): bool =
|
||||||
|
|
||||||
proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) =
|
proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) =
|
||||||
var h: Hash = myhash(t, key) and high(data)
|
var h: Hash = myhash(t, key) and high(data)
|
||||||
while not isNil(data[h].key):
|
while data[h].hasValue:
|
||||||
h = nextTry(h, high(data))
|
h = nextTry(h, high(data))
|
||||||
data[h].key = key
|
data[h].key = key
|
||||||
data[h].val = val
|
data[h].val = val
|
||||||
|
data[h].hasValue = true
|
||||||
|
|
||||||
proc enlarge(t: StringTableRef) =
|
proc enlarge(t: StringTableRef) =
|
||||||
var n: KeyValuePairSeq
|
var n: KeyValuePairSeq
|
||||||
newSeq(n, len(t.data) * growthFactor)
|
newSeq(n, len(t.data) * growthFactor)
|
||||||
for i in countup(0, high(t.data)):
|
for i in countup(0, high(t.data)):
|
||||||
if not isNil(t.data[i].key): rawInsert(t, n, t.data[i].key, t.data[i].val)
|
if t.data[i].hasValue: rawInsert(t, n, t.data[i].key, t.data[i].val)
|
||||||
swap(t.data, n)
|
swap(t.data, n)
|
||||||
|
|
||||||
proc `[]=`*(t: StringTableRef, key, val: string) {.rtlFunc, extern: "nstPut".} =
|
proc `[]=`*(t: StringTableRef, key, val: string) {.rtlFunc, extern: "nstPut".} =
|
||||||
|
|
@ -198,8 +199,7 @@ proc clear*(s: StringTableRef, mode: StringTableMode) =
|
||||||
s.counter = 0
|
s.counter = 0
|
||||||
s.data.setLen(startSize)
|
s.data.setLen(startSize)
|
||||||
for i in 0..<s.data.len:
|
for i in 0..<s.data.len:
|
||||||
if not isNil(s.data[i].key):
|
s.data[i].hasValue = false
|
||||||
s.data[i].key = nil
|
|
||||||
|
|
||||||
proc newStringTable*(keyValuePairs: varargs[string],
|
proc newStringTable*(keyValuePairs: varargs[string],
|
||||||
mode: StringTableMode): StringTableRef {.
|
mode: StringTableMode): StringTableRef {.
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,12 @@ proc isUpperAscii*(c: char): bool {.noSideEffect, procvar,
|
||||||
## This checks ASCII characters only.
|
## This checks ASCII characters only.
|
||||||
return c in {'A'..'Z'}
|
return c in {'A'..'Z'}
|
||||||
|
|
||||||
|
template isImpl(call) =
|
||||||
|
if s.len == 0: return false
|
||||||
|
result = true
|
||||||
|
for c in s:
|
||||||
|
if not call(c): return false
|
||||||
|
|
||||||
proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
|
proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuIsAlphaAsciiStr".} =
|
rtl, extern: "nsuIsAlphaAsciiStr".} =
|
||||||
## Checks whether or not `s` is alphabetical.
|
## Checks whether or not `s` is alphabetical.
|
||||||
|
|
@ -114,12 +120,7 @@ proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
## Returns true if all characters in `s` are
|
## Returns true if all characters in `s` are
|
||||||
## alphabetic and there is at least one character
|
## alphabetic and there is at least one character
|
||||||
## in `s`.
|
## in `s`.
|
||||||
if s.len() == 0:
|
isImpl isAlphaAscii
|
||||||
return false
|
|
||||||
|
|
||||||
result = true
|
|
||||||
for c in s:
|
|
||||||
if not c.isAlphaAscii(): return false
|
|
||||||
|
|
||||||
proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuIsAlphaNumericStr".} =
|
rtl, extern: "nsuIsAlphaNumericStr".} =
|
||||||
|
|
@ -129,13 +130,7 @@ proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
||||||
## Returns true if all characters in `s` are
|
## Returns true if all characters in `s` are
|
||||||
## alpanumeric and there is at least one character
|
## alpanumeric and there is at least one character
|
||||||
## in `s`.
|
## in `s`.
|
||||||
if s.len() == 0:
|
isImpl isAlphaNumeric
|
||||||
return false
|
|
||||||
|
|
||||||
result = true
|
|
||||||
for c in s:
|
|
||||||
if not c.isAlphaNumeric():
|
|
||||||
return false
|
|
||||||
|
|
||||||
proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuIsDigitStr".} =
|
rtl, extern: "nsuIsDigitStr".} =
|
||||||
|
|
@ -145,13 +140,7 @@ proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
||||||
## Returns true if all characters in `s` are
|
## Returns true if all characters in `s` are
|
||||||
## numeric and there is at least one character
|
## numeric and there is at least one character
|
||||||
## in `s`.
|
## in `s`.
|
||||||
if s.len() == 0:
|
isImpl isDigit
|
||||||
return false
|
|
||||||
|
|
||||||
result = true
|
|
||||||
for c in s:
|
|
||||||
if not c.isDigit():
|
|
||||||
return false
|
|
||||||
|
|
||||||
proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
|
proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuIsSpaceAsciiStr".} =
|
rtl, extern: "nsuIsSpaceAsciiStr".} =
|
||||||
|
|
@ -159,13 +148,7 @@ proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
##
|
##
|
||||||
## Returns true if all characters in `s` are whitespace
|
## Returns true if all characters in `s` are whitespace
|
||||||
## characters and there is at least one character in `s`.
|
## characters and there is at least one character in `s`.
|
||||||
if s.len() == 0:
|
isImpl isSpaceAscii
|
||||||
return false
|
|
||||||
|
|
||||||
result = true
|
|
||||||
for c in s:
|
|
||||||
if not c.isSpaceAscii():
|
|
||||||
return false
|
|
||||||
|
|
||||||
proc isLowerAscii*(s: string): bool {.noSideEffect, procvar,
|
proc isLowerAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuIsLowerAsciiStr".} =
|
rtl, extern: "nsuIsLowerAsciiStr".} =
|
||||||
|
|
@ -174,13 +157,7 @@ proc isLowerAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
## This checks ASCII characters only.
|
## This checks ASCII characters only.
|
||||||
## Returns true if all characters in `s` are lower case
|
## Returns true if all characters in `s` are lower case
|
||||||
## and there is at least one character in `s`.
|
## and there is at least one character in `s`.
|
||||||
if s.len() == 0:
|
isImpl isLowerAscii
|
||||||
return false
|
|
||||||
|
|
||||||
for c in s:
|
|
||||||
if not c.isLowerAscii():
|
|
||||||
return false
|
|
||||||
true
|
|
||||||
|
|
||||||
proc isUpperAscii*(s: string): bool {.noSideEffect, procvar,
|
proc isUpperAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuIsUpperAsciiStr".} =
|
rtl, extern: "nsuIsUpperAsciiStr".} =
|
||||||
|
|
@ -189,13 +166,7 @@ proc isUpperAscii*(s: string): bool {.noSideEffect, procvar,
|
||||||
## This checks ASCII characters only.
|
## This checks ASCII characters only.
|
||||||
## Returns true if all characters in `s` are upper case
|
## Returns true if all characters in `s` are upper case
|
||||||
## and there is at least one character in `s`.
|
## and there is at least one character in `s`.
|
||||||
if s.len() == 0:
|
isImpl isUpperAscii
|
||||||
return false
|
|
||||||
|
|
||||||
for c in s:
|
|
||||||
if not c.isUpperAscii():
|
|
||||||
return false
|
|
||||||
true
|
|
||||||
|
|
||||||
proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
|
proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuToLowerAsciiChar".} =
|
rtl, extern: "nsuToLowerAsciiChar".} =
|
||||||
|
|
@ -209,6 +180,11 @@ proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
|
||||||
else:
|
else:
|
||||||
result = c
|
result = c
|
||||||
|
|
||||||
|
template toImpl(call) =
|
||||||
|
result = newString(len(s))
|
||||||
|
for i in 0..len(s) - 1:
|
||||||
|
result[i] = call(s[i])
|
||||||
|
|
||||||
proc toLowerAscii*(s: string): string {.noSideEffect, procvar,
|
proc toLowerAscii*(s: string): string {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuToLowerAsciiStr".} =
|
rtl, extern: "nsuToLowerAsciiStr".} =
|
||||||
## Converts `s` into lower case.
|
## Converts `s` into lower case.
|
||||||
|
|
@ -216,9 +192,7 @@ proc toLowerAscii*(s: string): string {.noSideEffect, procvar,
|
||||||
## This works only for the letters ``A-Z``. See `unicode.toLower
|
## This works only for the letters ``A-Z``. See `unicode.toLower
|
||||||
## <unicode.html#toLower>`_ for a version that works for any Unicode
|
## <unicode.html#toLower>`_ for a version that works for any Unicode
|
||||||
## character.
|
## character.
|
||||||
result = newString(len(s))
|
toImpl toLowerAscii
|
||||||
for i in 0..len(s) - 1:
|
|
||||||
result[i] = toLowerAscii(s[i])
|
|
||||||
|
|
||||||
proc toUpperAscii*(c: char): char {.noSideEffect, procvar,
|
proc toUpperAscii*(c: char): char {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuToUpperAsciiChar".} =
|
rtl, extern: "nsuToUpperAsciiChar".} =
|
||||||
|
|
@ -239,147 +213,15 @@ proc toUpperAscii*(s: string): string {.noSideEffect, procvar,
|
||||||
## This works only for the letters ``A-Z``. See `unicode.toUpper
|
## This works only for the letters ``A-Z``. See `unicode.toUpper
|
||||||
## <unicode.html#toUpper>`_ for a version that works for any Unicode
|
## <unicode.html#toUpper>`_ for a version that works for any Unicode
|
||||||
## character.
|
## character.
|
||||||
result = newString(len(s))
|
toImpl toUpperAscii
|
||||||
for i in 0..len(s) - 1:
|
|
||||||
result[i] = toUpperAscii(s[i])
|
|
||||||
|
|
||||||
proc capitalizeAscii*(s: string): string {.noSideEffect, procvar,
|
proc capitalizeAscii*(s: string): string {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuCapitalizeAscii".} =
|
rtl, extern: "nsuCapitalizeAscii".} =
|
||||||
## Converts the first character of `s` into upper case.
|
## Converts the first character of `s` into upper case.
|
||||||
##
|
##
|
||||||
## This works only for the letters ``A-Z``.
|
## This works only for the letters ``A-Z``.
|
||||||
result = toUpperAscii(s[0]) & substr(s, 1)
|
if s.len == 0: result = ""
|
||||||
|
else: result = toUpperAscii(s[0]) & substr(s, 1)
|
||||||
proc isSpace*(c: char): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsSpaceChar".}=
|
|
||||||
## Checks whether or not `c` is a whitespace character.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isSpaceAscii`` instead.
|
|
||||||
isSpaceAscii(c)
|
|
||||||
|
|
||||||
proc isLower*(c: char): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsLowerChar".}=
|
|
||||||
## Checks whether or not `c` is a lower case character.
|
|
||||||
##
|
|
||||||
## This checks ASCII characters only.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isLowerAscii`` instead.
|
|
||||||
isLowerAscii(c)
|
|
||||||
|
|
||||||
proc isUpper*(c: char): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsUpperChar".}=
|
|
||||||
## Checks whether or not `c` is an upper case character.
|
|
||||||
##
|
|
||||||
## This checks ASCII characters only.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isUpperAscii`` instead.
|
|
||||||
isUpperAscii(c)
|
|
||||||
|
|
||||||
proc isAlpha*(c: char): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsAlphaChar".}=
|
|
||||||
## Checks whether or not `c` is alphabetical.
|
|
||||||
##
|
|
||||||
## This checks a-z, A-Z ASCII characters only.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isAlphaAscii`` instead.
|
|
||||||
isAlphaAscii(c)
|
|
||||||
|
|
||||||
proc isAlpha*(s: string): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsAlphaStr".}=
|
|
||||||
## Checks whether or not `s` is alphabetical.
|
|
||||||
##
|
|
||||||
## This checks a-z, A-Z ASCII characters only.
|
|
||||||
## Returns true if all characters in `s` are
|
|
||||||
## alphabetic and there is at least one character
|
|
||||||
## in `s`.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isAlphaAscii`` instead.
|
|
||||||
isAlphaAscii(s)
|
|
||||||
|
|
||||||
proc isSpace*(s: string): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsSpaceStr".}=
|
|
||||||
## Checks whether or not `s` is completely whitespace.
|
|
||||||
##
|
|
||||||
## Returns true if all characters in `s` are whitespace
|
|
||||||
## characters and there is at least one character in `s`.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isSpaceAscii`` instead.
|
|
||||||
isSpaceAscii(s)
|
|
||||||
|
|
||||||
proc isLower*(s: string): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsLowerStr".}=
|
|
||||||
## Checks whether or not `s` contains all lower case characters.
|
|
||||||
##
|
|
||||||
## This checks ASCII characters only.
|
|
||||||
## Returns true if all characters in `s` are lower case
|
|
||||||
## and there is at least one character in `s`.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isLowerAscii`` instead.
|
|
||||||
isLowerAscii(s)
|
|
||||||
|
|
||||||
proc isUpper*(s: string): bool {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuIsUpperStr".}=
|
|
||||||
## Checks whether or not `s` contains all upper case characters.
|
|
||||||
##
|
|
||||||
## This checks ASCII characters only.
|
|
||||||
## Returns true if all characters in `s` are upper case
|
|
||||||
## and there is at least one character in `s`.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``isUpperAscii`` instead.
|
|
||||||
isUpperAscii(s)
|
|
||||||
|
|
||||||
proc toLower*(c: char): char {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuToLowerChar".} =
|
|
||||||
## Converts `c` into lower case.
|
|
||||||
##
|
|
||||||
## This works only for the letters ``A-Z``. See `unicode.toLower
|
|
||||||
## <unicode.html#toLower>`_ for a version that works for any Unicode
|
|
||||||
## character.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``toLowerAscii`` instead.
|
|
||||||
toLowerAscii(c)
|
|
||||||
|
|
||||||
proc toLower*(s: string): string {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuToLowerStr".} =
|
|
||||||
## Converts `s` into lower case.
|
|
||||||
##
|
|
||||||
## This works only for the letters ``A-Z``. See `unicode.toLower
|
|
||||||
## <unicode.html#toLower>`_ for a version that works for any Unicode
|
|
||||||
## character.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``toLowerAscii`` instead.
|
|
||||||
toLowerAscii(s)
|
|
||||||
|
|
||||||
proc toUpper*(c: char): char {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuToUpperChar".} =
|
|
||||||
## Converts `c` into upper case.
|
|
||||||
##
|
|
||||||
## This works only for the letters ``A-Z``. See `unicode.toUpper
|
|
||||||
## <unicode.html#toUpper>`_ for a version that works for any Unicode
|
|
||||||
## character.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``toUpperAscii`` instead.
|
|
||||||
toUpperAscii(c)
|
|
||||||
|
|
||||||
proc toUpper*(s: string): string {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuToUpperStr".} =
|
|
||||||
## Converts `s` into upper case.
|
|
||||||
##
|
|
||||||
## This works only for the letters ``A-Z``. See `unicode.toUpper
|
|
||||||
## <unicode.html#toUpper>`_ for a version that works for any Unicode
|
|
||||||
## character.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``toUpperAscii`` instead.
|
|
||||||
toUpperAscii(s)
|
|
||||||
|
|
||||||
proc capitalize*(s: string): string {.noSideEffect, procvar,
|
|
||||||
rtl, deprecated, extern: "nsuCapitalize".} =
|
|
||||||
## Converts the first character of `s` into upper case.
|
|
||||||
##
|
|
||||||
## This works only for the letters ``A-Z``.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.15.0**: use ``capitalizeAscii`` instead.
|
|
||||||
capitalizeAscii(s)
|
|
||||||
|
|
||||||
proc normalize*(s: string): string {.noSideEffect, procvar,
|
proc normalize*(s: string): string {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuNormalize".} =
|
rtl, extern: "nsuNormalize".} =
|
||||||
|
|
@ -429,14 +271,22 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
||||||
var i = 0
|
var i = 0
|
||||||
var j = 0
|
var j = 0
|
||||||
while true:
|
while true:
|
||||||
while a[i] == '_': inc(i)
|
while i < a.len and a[i] == '_': inc i
|
||||||
while b[j] == '_': inc(j) # BUGFIX: typo
|
while j < b.len and b[j] == '_': inc j
|
||||||
var aa = toLowerAscii(a[i])
|
var aa = if i < a.len: toLowerAscii(a[i]) else: '\0'
|
||||||
var bb = toLowerAscii(b[j])
|
var bb = if j < b.len: toLowerAscii(b[j]) else: '\0'
|
||||||
result = ord(aa) - ord(bb)
|
result = ord(aa) - ord(bb)
|
||||||
if result != 0 or aa == '\0': break
|
if result != 0: return result
|
||||||
inc(i)
|
# the characters are identical:
|
||||||
inc(j)
|
if i >= a.len:
|
||||||
|
# both cursors at the end:
|
||||||
|
if j >= b.len: return 0
|
||||||
|
# not yet at the end of 'b':
|
||||||
|
return -1
|
||||||
|
elif j >= b.len:
|
||||||
|
return 1
|
||||||
|
inc i
|
||||||
|
inc j
|
||||||
|
|
||||||
proc strip*(s: string, leading = true, trailing = true,
|
proc strip*(s: string, leading = true, trailing = true,
|
||||||
chars: set[char] = Whitespace): string
|
chars: set[char] = Whitespace): string
|
||||||
|
|
@ -451,7 +301,7 @@ proc strip*(s: string, leading = true, trailing = true,
|
||||||
first = 0
|
first = 0
|
||||||
last = len(s)-1
|
last = len(s)-1
|
||||||
if leading:
|
if leading:
|
||||||
while s[first] in chars: inc(first)
|
while first <= last and s[first] in chars: inc(first)
|
||||||
if trailing:
|
if trailing:
|
||||||
while last >= 0 and s[last] in chars: dec(last)
|
while last >= 0 and s[last] in chars: dec(last)
|
||||||
result = substr(s, first, last)
|
result = substr(s, first, last)
|
||||||
|
|
@ -467,7 +317,9 @@ proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
|
||||||
result[i] = chr(val mod 8 + ord('0'))
|
result[i] = chr(val mod 8 + ord('0'))
|
||||||
val = val div 8
|
val = val div 8
|
||||||
|
|
||||||
proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrEmpty".} =
|
proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl,
|
||||||
|
extern: "nsuIsNilOrEmpty",
|
||||||
|
deprecated: "use 'x.len == 0' instead".} =
|
||||||
## Checks if `s` is nil or empty.
|
## Checks if `s` is nil or empty.
|
||||||
result = len(s) == 0
|
result = len(s) == 0
|
||||||
|
|
||||||
|
|
@ -486,7 +338,6 @@ proc substrEq(s: string, pos: int, substr: string): bool =
|
||||||
var length = substr.len
|
var length = substr.len
|
||||||
while i < length and s[pos+i] == substr[i]:
|
while i < length and s[pos+i] == substr[i]:
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
return i == length
|
return i == length
|
||||||
|
|
||||||
# --------- Private templates for different split separators -----------
|
# --------- Private templates for different split separators -----------
|
||||||
|
|
@ -520,7 +371,7 @@ template oldSplit(s, seps, maxsplit) =
|
||||||
var splits = maxsplit
|
var splits = maxsplit
|
||||||
assert(not ('\0' in seps))
|
assert(not ('\0' in seps))
|
||||||
while last < len(s):
|
while last < len(s):
|
||||||
while s[last] in seps: inc(last)
|
while last < len(s) and s[last] in seps: inc(last)
|
||||||
var first = last
|
var first = last
|
||||||
while last < len(s) and s[last] notin seps: inc(last)
|
while last < len(s) and s[last] notin seps: inc(last)
|
||||||
if first <= last-1:
|
if first <= last-1:
|
||||||
|
|
@ -571,9 +422,6 @@ iterator split*(s: string, seps: set[char] = Whitespace,
|
||||||
## "08"
|
## "08"
|
||||||
## "08.398990"
|
## "08.398990"
|
||||||
##
|
##
|
||||||
when defined(nimOldSplit):
|
|
||||||
oldSplit(s, seps, maxsplit)
|
|
||||||
else:
|
|
||||||
splitCommon(s, seps, maxsplit, 1)
|
splitCommon(s, seps, maxsplit, 1)
|
||||||
|
|
||||||
iterator splitWhitespace*(s: string, maxsplit: int = -1): string =
|
iterator splitWhitespace*(s: string, maxsplit: int = -1): string =
|
||||||
|
|
@ -660,7 +508,6 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string =
|
||||||
## "is"
|
## "is"
|
||||||
## "corrupted"
|
## "corrupted"
|
||||||
##
|
##
|
||||||
|
|
||||||
splitCommon(s, sep, maxsplit, sep.len)
|
splitCommon(s, sep, maxsplit, sep.len)
|
||||||
|
|
||||||
template rsplitCommon(s, sep, maxsplit, sepLen) =
|
template rsplitCommon(s, sep, maxsplit, sepLen) =
|
||||||
|
|
@ -670,29 +517,21 @@ template rsplitCommon(s, sep, maxsplit, sepLen) =
|
||||||
first = last
|
first = last
|
||||||
splits = maxsplit
|
splits = maxsplit
|
||||||
startPos = 0
|
startPos = 0
|
||||||
|
|
||||||
# go to -1 in order to get separators at the beginning
|
# go to -1 in order to get separators at the beginning
|
||||||
while first >= -1:
|
while first >= -1:
|
||||||
while first >= 0 and not stringHasSep(s, first, sep):
|
while first >= 0 and not stringHasSep(s, first, sep):
|
||||||
dec(first)
|
dec(first)
|
||||||
|
|
||||||
if splits == 0:
|
if splits == 0:
|
||||||
# No more splits means set first to the beginning
|
# No more splits means set first to the beginning
|
||||||
first = -1
|
first = -1
|
||||||
|
|
||||||
if first == -1:
|
if first == -1:
|
||||||
startPos = 0
|
startPos = 0
|
||||||
else:
|
else:
|
||||||
startPos = first + sepLen
|
startPos = first + sepLen
|
||||||
|
|
||||||
yield substr(s, startPos, last)
|
yield substr(s, startPos, last)
|
||||||
|
if splits == 0: break
|
||||||
if splits == 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
dec(splits)
|
dec(splits)
|
||||||
dec(first)
|
dec(first)
|
||||||
|
|
||||||
last = first
|
last = first
|
||||||
|
|
||||||
iterator rsplit*(s: string, seps: set[char] = Whitespace,
|
iterator rsplit*(s: string, seps: set[char] = Whitespace,
|
||||||
|
|
@ -712,7 +551,6 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace,
|
||||||
## "foo"
|
## "foo"
|
||||||
##
|
##
|
||||||
## Substrings are separated from the right by the set of chars `seps`
|
## Substrings are separated from the right by the set of chars `seps`
|
||||||
|
|
||||||
rsplitCommon(s, seps, maxsplit, 1)
|
rsplitCommon(s, seps, maxsplit, 1)
|
||||||
|
|
||||||
iterator rsplit*(s: string, sep: char,
|
iterator rsplit*(s: string, sep: char,
|
||||||
|
|
@ -779,14 +617,14 @@ iterator splitLines*(s: string): string =
|
||||||
var first = 0
|
var first = 0
|
||||||
var last = 0
|
var last = 0
|
||||||
while true:
|
while true:
|
||||||
while s[last] notin {'\0', '\c', '\l'}: inc(last)
|
while last < s.len and s[last] notin {'\c', '\l'}: inc(last)
|
||||||
yield substr(s, first, last-1)
|
yield substr(s, first, last-1)
|
||||||
# skip newlines:
|
# skip newlines:
|
||||||
|
if last >= s.len: break
|
||||||
if s[last] == '\l': inc(last)
|
if s[last] == '\l': inc(last)
|
||||||
elif s[last] == '\c':
|
elif s[last] == '\c':
|
||||||
inc(last)
|
inc(last)
|
||||||
if s[last] == '\l': inc(last)
|
if last < s.len and s[last] == '\l': inc(last)
|
||||||
else: break # was '\0'
|
|
||||||
first = last
|
first = last
|
||||||
|
|
||||||
proc splitLines*(s: string): seq[string] {.noSideEffect,
|
proc splitLines*(s: string): seq[string] {.noSideEffect,
|
||||||
|
|
@ -811,7 +649,7 @@ proc countLines*(s: string): int {.noSideEffect,
|
||||||
while i < s.len:
|
while i < s.len:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '\c':
|
of '\c':
|
||||||
if s[i+1] == '\l': inc i
|
if i+1 < s.len and s[i+1] == '\l': inc i
|
||||||
inc result
|
inc result
|
||||||
of '\l': inc result
|
of '\l': inc result
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -1025,9 +863,9 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar,
|
||||||
## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores
|
## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores
|
||||||
## within `s` are ignored.
|
## within `s` are ignored.
|
||||||
var i = 0
|
var i = 0
|
||||||
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||||
elif s[i] == '#': inc(i)
|
elif i < s.len and s[i] == '#': inc(i)
|
||||||
while true:
|
while i < s.len:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '_': inc(i)
|
of '_': inc(i)
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
|
|
@ -1039,7 +877,6 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar,
|
||||||
of 'A'..'F':
|
of 'A'..'F':
|
||||||
result = result shl 4 or (ord(s[i]) - ord('A') + 10)
|
result = result shl 4 or (ord(s[i]) - ord('A') + 10)
|
||||||
inc(i)
|
inc(i)
|
||||||
of '\0': break
|
|
||||||
else: raise newException(ValueError, "invalid integer: " & s)
|
else: raise newException(ValueError, "invalid integer: " & s)
|
||||||
|
|
||||||
proc generateHexCharToValueMap(): string =
|
proc generateHexCharToValueMap(): string =
|
||||||
|
|
@ -1148,14 +985,6 @@ template spaces*(n: Natural): string = repeat(' ', n)
|
||||||
## echo text1 & spaces(max(0, width - text1.len)) & "|"
|
## echo text1 & spaces(max(0, width - text1.len)) & "|"
|
||||||
## echo text2 & spaces(max(0, width - text2.len)) & "|"
|
## echo text2 & spaces(max(0, width - text2.len)) & "|"
|
||||||
|
|
||||||
proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} =
|
|
||||||
## deprecated: use repeat() or spaces()
|
|
||||||
repeat(c, count)
|
|
||||||
|
|
||||||
proc repeatStr*(count: Natural, s: string): string {.deprecated.} =
|
|
||||||
## deprecated: use repeat(string, count) or string.repeat(count)
|
|
||||||
repeat(s, count)
|
|
||||||
|
|
||||||
proc align*(s: string, count: Natural, padding = ' '): string {.
|
proc align*(s: string, count: Natural, padding = ' '): string {.
|
||||||
noSideEffect, rtl, extern: "nsuAlignString".} =
|
noSideEffect, rtl, extern: "nsuAlignString".} =
|
||||||
## Aligns a string `s` with `padding`, so that it is of length `count`.
|
## Aligns a string `s` with `padding`, so that it is of length `count`.
|
||||||
|
|
@ -1226,7 +1055,7 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
var j = i
|
var j = i
|
||||||
var isSep = s[j] in seps
|
var isSep = j < s.len and s[j] in seps
|
||||||
while j < s.len and (s[j] in seps) == isSep: inc(j)
|
while j < s.len and (s[j] in seps) == isSep: inc(j)
|
||||||
if j > i:
|
if j > i:
|
||||||
yield (substr(s, i, j-1), isSep)
|
yield (substr(s, i, j-1), isSep)
|
||||||
|
|
@ -1297,7 +1126,7 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string
|
||||||
var indentCount = 0
|
var indentCount = 0
|
||||||
for j in 0..<count.int:
|
for j in 0..<count.int:
|
||||||
indentCount.inc
|
indentCount.inc
|
||||||
if line[j .. j + padding.len-1] != padding:
|
if j + padding.len-1 >= line.len or line[j .. j + padding.len-1] != padding:
|
||||||
indentCount = j
|
indentCount = j
|
||||||
break
|
break
|
||||||
result.add(line[indentCount*padding.len .. ^1])
|
result.add(line[indentCount*padding.len .. ^1])
|
||||||
|
|
@ -1325,13 +1154,13 @@ proc startsWith*(s, prefix: string): bool {.noSideEffect,
|
||||||
## If ``prefix == ""`` true is returned.
|
## If ``prefix == ""`` true is returned.
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
if prefix[i] == '\0': return true
|
if i >= prefix.len: return true
|
||||||
if s[i] != prefix[i]: return false
|
if i >= s.len or s[i] != prefix[i]: return false
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} =
|
proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} =
|
||||||
## Returns true iff ``s`` starts with ``prefix``.
|
## Returns true iff ``s`` starts with ``prefix``.
|
||||||
result = s[0] == prefix
|
result = s.len > 0 and s[0] == prefix
|
||||||
|
|
||||||
proc endsWith*(s, suffix: string): bool {.noSideEffect,
|
proc endsWith*(s, suffix: string): bool {.noSideEffect,
|
||||||
rtl, extern: "nsuEndsWith".} =
|
rtl, extern: "nsuEndsWith".} =
|
||||||
|
|
@ -1343,11 +1172,11 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
|
||||||
while i+j <% s.len:
|
while i+j <% s.len:
|
||||||
if s[i+j] != suffix[i]: return false
|
if s[i+j] != suffix[i]: return false
|
||||||
inc(i)
|
inc(i)
|
||||||
if suffix[i] == '\0': return true
|
if i >= suffix.len: return true
|
||||||
|
|
||||||
proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} =
|
proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} =
|
||||||
## Returns true iff ``s`` ends with ``suffix``.
|
## Returns true iff ``s`` ends with ``suffix``.
|
||||||
result = s[s.high] == suffix
|
result = s.len > 0 and s[s.high] == suffix
|
||||||
|
|
||||||
proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
|
proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
|
||||||
rtl, extern: "nsuContinuesWith".} =
|
rtl, extern: "nsuContinuesWith".} =
|
||||||
|
|
@ -1356,8 +1185,8 @@ proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
|
||||||
## If ``substr == ""`` true is returned.
|
## If ``substr == ""`` true is returned.
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
if substr[i] == '\0': return true
|
if i >= substr.len: return true
|
||||||
if s[i+start] != substr[i]: return false
|
if i+start >= s.len or s[i+start] != substr[i]: return false
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
|
proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
|
||||||
|
|
@ -1502,12 +1331,8 @@ proc find*(s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideE
|
||||||
## If `last` is unspecified, it defaults to `s.high`.
|
## If `last` is unspecified, it defaults to `s.high`.
|
||||||
##
|
##
|
||||||
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||||
if sub.len > s.len:
|
if sub.len > s.len: return -1
|
||||||
return -1
|
if sub.len == 1: return find(s, sub[0], start, last)
|
||||||
|
|
||||||
if sub.len == 1:
|
|
||||||
return find(s, sub[0], start, last)
|
|
||||||
|
|
||||||
var a {.noinit.}: SkipTable
|
var a {.noinit.}: SkipTable
|
||||||
initSkipTable(a, sub)
|
initSkipTable(a, sub)
|
||||||
result = find(a, s, sub, start, last)
|
result = find(a, s, sub, start, last)
|
||||||
|
|
@ -1564,18 +1389,14 @@ proc center*(s: string, width: int, fillChar: char = ' '): string {.
|
||||||
##
|
##
|
||||||
## The original string is returned if `width` is less than or equal
|
## The original string is returned if `width` is less than or equal
|
||||||
## to `s.len`.
|
## to `s.len`.
|
||||||
if width <= s.len:
|
if width <= s.len: return s
|
||||||
return s
|
|
||||||
|
|
||||||
result = newString(width)
|
result = newString(width)
|
||||||
|
|
||||||
# Left padding will be one fillChar
|
# Left padding will be one fillChar
|
||||||
# smaller if there are an odd number
|
# smaller if there are an odd number
|
||||||
# of characters
|
# of characters
|
||||||
let
|
let
|
||||||
charsLeft = (width - s.len)
|
charsLeft = (width - s.len)
|
||||||
leftPadding = charsLeft div 2
|
leftPadding = charsLeft div 2
|
||||||
|
|
||||||
for i in 0 ..< width:
|
for i in 0 ..< width:
|
||||||
if i >= leftPadding and i < leftPadding + s.len:
|
if i >= leftPadding and i < leftPadding + s.len:
|
||||||
# we are where the string should be located
|
# we are where the string should be located
|
||||||
|
|
@ -1593,27 +1414,22 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
i = s.find(sub, i)
|
i = s.find(sub, i)
|
||||||
if i < 0:
|
if i < 0: break
|
||||||
break
|
if overlapping: inc i
|
||||||
if overlapping:
|
else: i += sub.len
|
||||||
inc i
|
|
||||||
else:
|
|
||||||
i += sub.len
|
|
||||||
inc result
|
inc result
|
||||||
|
|
||||||
proc count*(s: string, sub: char): int {.noSideEffect,
|
proc count*(s: string, sub: char): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCountChar".} =
|
rtl, extern: "nsuCountChar".} =
|
||||||
## Count the occurrences of the character `sub` in the string `s`.
|
## Count the occurrences of the character `sub` in the string `s`.
|
||||||
for c in s:
|
for c in s:
|
||||||
if c == sub:
|
if c == sub: inc result
|
||||||
inc result
|
|
||||||
|
|
||||||
proc count*(s: string, subs: set[char]): int {.noSideEffect,
|
proc count*(s: string, subs: set[char]): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCountCharSet".} =
|
rtl, extern: "nsuCountCharSet".} =
|
||||||
## Count the occurrences of the group of character `subs` in the string `s`.
|
## Count the occurrences of the group of character `subs` in the string `s`.
|
||||||
for c in s:
|
for c in s:
|
||||||
if c in subs:
|
if c in subs: inc result
|
||||||
inc result
|
|
||||||
|
|
||||||
proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
|
proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
|
||||||
## Returns ``'"' & s & '"'`` if `s` contains a space and does not
|
## Returns ``'"' & s & '"'`` if `s` contains a space and does not
|
||||||
|
|
@ -1621,10 +1437,8 @@ proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
|
||||||
##
|
##
|
||||||
## **DEPRECATED** as it was confused for shell quoting function. For this
|
## **DEPRECATED** as it was confused for shell quoting function. For this
|
||||||
## application use `osproc.quoteShell <osproc.html#quoteShell>`_.
|
## application use `osproc.quoteShell <osproc.html#quoteShell>`_.
|
||||||
if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
|
if find(s, {' ', '\t'}) >= 0 and s[0] != '"': result = '"' & s & '"'
|
||||||
result = '"' & s & '"'
|
else: result = s
|
||||||
else:
|
|
||||||
result = s
|
|
||||||
|
|
||||||
proc contains*(s: string, c: char): bool {.noSideEffect.} =
|
proc contains*(s: string, c: char): bool {.noSideEffect.} =
|
||||||
## Same as ``find(s, c) >= 0``.
|
## Same as ``find(s, c) >= 0``.
|
||||||
|
|
@ -1704,9 +1518,8 @@ proc multiReplace*(s: string, replacements: varargs[(string, string)]): string {
|
||||||
## Same as replace, but specialized for doing multiple replacements in a single
|
## Same as replace, but specialized for doing multiple replacements in a single
|
||||||
## pass through the input string.
|
## pass through the input string.
|
||||||
##
|
##
|
||||||
## Calling replace multiple times after each other is inefficient and result in too many allocations
|
## multiReplace performs all replacements in a single pass, this means it can be used
|
||||||
## follwed by immediate deallocations as portions of the string gets replaced.
|
## to swap the occurences of "a" and "b", for instance.
|
||||||
## multiReplace performs all replacements in a single pass.
|
|
||||||
##
|
##
|
||||||
## If the resulting string is not longer than the original input string, only a single
|
## If the resulting string is not longer than the original input string, only a single
|
||||||
## memory allocation is required.
|
## memory allocation is required.
|
||||||
|
|
@ -1753,14 +1566,13 @@ proc parseOctInt*(s: string): int {.noSideEffect,
|
||||||
## of the following optional prefixes: ``0o``, ``0O``. Underscores within
|
## of the following optional prefixes: ``0o``, ``0O``. Underscores within
|
||||||
## `s` are ignored.
|
## `s` are ignored.
|
||||||
var i = 0
|
var i = 0
|
||||||
if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
||||||
while true:
|
while i < s.len:
|
||||||
case s[i]
|
case s[i]
|
||||||
of '_': inc(i)
|
of '_': inc(i)
|
||||||
of '0'..'7':
|
of '0'..'7':
|
||||||
result = result shl 3 or (ord(s[i]) - ord('0'))
|
result = result shl 3 or (ord(s[i]) - ord('0'))
|
||||||
inc(i)
|
inc(i)
|
||||||
of '\0': break
|
|
||||||
else: raise newException(ValueError, "invalid integer: " & s)
|
else: raise newException(ValueError, "invalid integer: " & s)
|
||||||
|
|
||||||
proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
||||||
|
|
@ -1854,11 +1666,13 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
||||||
var i = prefix.len
|
var i = prefix.len
|
||||||
if not s.startsWith(prefix):
|
if not s.startsWith(prefix):
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"String does not start with a prefix of: " & prefix)
|
"String does not start with: " & prefix)
|
||||||
while true:
|
while true:
|
||||||
if i == s.len-suffix.len: break
|
if i >= s.len-suffix.len: break
|
||||||
case s[i]
|
if s[i] == '\\':
|
||||||
of '\\':
|
if i+1 >= s.len:
|
||||||
|
result.add('\\')
|
||||||
|
break
|
||||||
case s[i+1]:
|
case s[i+1]:
|
||||||
of 'x':
|
of 'x':
|
||||||
inc i, 2
|
inc i, 2
|
||||||
|
|
@ -1872,15 +1686,15 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
||||||
result.add('\'')
|
result.add('\'')
|
||||||
of '\"':
|
of '\"':
|
||||||
result.add('\"')
|
result.add('\"')
|
||||||
else: result.add("\\" & s[i+1])
|
else:
|
||||||
inc(i)
|
result.add("\\" & s[i+1])
|
||||||
of '\0': break
|
inc(i, 2)
|
||||||
else:
|
else:
|
||||||
result.add(s[i])
|
result.add(s[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
if not s.endsWith(suffix):
|
if not s.endsWith(suffix):
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"String does not end with a suffix of: " & suffix)
|
"String does not end in: " & suffix)
|
||||||
|
|
||||||
proc validIdentifier*(s: string): bool {.noSideEffect,
|
proc validIdentifier*(s: string): bool {.noSideEffect,
|
||||||
rtl, extern: "nsuValidIdentifier".} =
|
rtl, extern: "nsuValidIdentifier".} =
|
||||||
|
|
@ -1890,7 +1704,7 @@ proc validIdentifier*(s: string): bool {.noSideEffect,
|
||||||
## and is followed by any number of characters of the set `IdentChars`.
|
## and is followed by any number of characters of the set `IdentChars`.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert "abc_def08".validIdentifier
|
doAssert "abc_def08".validIdentifier
|
||||||
if s[0] in IdentStartChars:
|
if s.len > 0 and s[0] in IdentStartChars:
|
||||||
for i in 1..s.len-1:
|
for i in 1..s.len-1:
|
||||||
if s[i] notin IdentChars: return false
|
if s[i] notin IdentChars: return false
|
||||||
return true
|
return true
|
||||||
|
|
@ -1909,7 +1723,7 @@ proc editDistance*(a, b: string): int {.noSideEffect,
|
||||||
|
|
||||||
# strip common prefix:
|
# strip common prefix:
|
||||||
var s = 0
|
var s = 0
|
||||||
while a[s] == b[s] and a[s] != '\0':
|
while s < len1 and a[s] == b[s]:
|
||||||
inc(s)
|
inc(s)
|
||||||
dec(len1)
|
dec(len1)
|
||||||
dec(len2)
|
dec(len2)
|
||||||
|
|
@ -1982,8 +1796,6 @@ proc editDistance*(a, b: string): int {.noSideEffect,
|
||||||
if x > c3: x = c3
|
if x > c3: x = c3
|
||||||
row[p] = x
|
row[p] = x
|
||||||
result = row[e]
|
result = row[e]
|
||||||
#dealloc(row)
|
|
||||||
|
|
||||||
|
|
||||||
# floating point formating:
|
# floating point formating:
|
||||||
when not defined(js):
|
when not defined(js):
|
||||||
|
|
@ -2310,9 +2122,8 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||||
var i = 0
|
var i = 0
|
||||||
var num = 0
|
var num = 0
|
||||||
while i < len(formatstr):
|
while i < len(formatstr):
|
||||||
if formatstr[i] == '$':
|
if formatstr[i] == '$' and i+1 < len(formatstr):
|
||||||
case formatstr[i+1] # again we use the fact that strings
|
case formatstr[i+1]
|
||||||
# are zero-terminated here
|
|
||||||
of '#':
|
of '#':
|
||||||
if num > a.high: invalidFormatString()
|
if num > a.high: invalidFormatString()
|
||||||
add s, a[num]
|
add s, a[num]
|
||||||
|
|
@ -2326,7 +2137,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||||
inc(i) # skip $
|
inc(i) # skip $
|
||||||
var negative = formatstr[i] == '-'
|
var negative = formatstr[i] == '-'
|
||||||
if negative: inc i
|
if negative: inc i
|
||||||
while formatstr[i] in Digits:
|
while i < formatstr.len and formatstr[i] in Digits:
|
||||||
j = j * 10 + ord(formatstr[i]) - ord('0')
|
j = j * 10 + ord(formatstr[i]) - ord('0')
|
||||||
inc(i)
|
inc(i)
|
||||||
let idx = if not negative: j-1 else: a.len-j
|
let idx = if not negative: j-1 else: a.len-j
|
||||||
|
|
@ -2338,7 +2149,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||||
var negative = formatstr[j] == '-'
|
var negative = formatstr[j] == '-'
|
||||||
if negative: inc j
|
if negative: inc j
|
||||||
var isNumber = 0
|
var isNumber = 0
|
||||||
while formatstr[j] notin {'\0', '}'}:
|
while j < formatstr.len and formatstr[j] notin {'\0', '}'}:
|
||||||
if formatstr[j] in Digits:
|
if formatstr[j] in Digits:
|
||||||
k = k * 10 + ord(formatstr[j]) - ord('0')
|
k = k * 10 + ord(formatstr[j]) - ord('0')
|
||||||
if isNumber == 0: isNumber = 1
|
if isNumber == 0: isNumber = 1
|
||||||
|
|
@ -2356,7 +2167,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||||
i = j+1
|
i = j+1
|
||||||
of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
|
of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
|
||||||
var j = i+1
|
var j = i+1
|
||||||
while formatstr[j] in PatternChars: inc(j)
|
while j < formatstr.len and formatstr[j] in PatternChars: inc(j)
|
||||||
var x = findNormalized(substr(formatstr, i+1, j-1), a)
|
var x = findNormalized(substr(formatstr, i+1, j-1), a)
|
||||||
if x >= 0 and x < high(a): add s, a[x+1]
|
if x >= 0 and x < high(a): add s, a[x+1]
|
||||||
else: invalidFormatString()
|
else: invalidFormatString()
|
||||||
|
|
@ -2628,13 +2439,7 @@ when isMainModule:
|
||||||
doAssert isSpaceAscii(" ")
|
doAssert isSpaceAscii(" ")
|
||||||
doAssert(not isSpaceAscii("ABc \td"))
|
doAssert(not isSpaceAscii("ABc \td"))
|
||||||
|
|
||||||
doAssert(isNilOrEmpty(""))
|
|
||||||
doAssert(isNilOrEmpty(nil))
|
|
||||||
doAssert(not isNilOrEmpty("test"))
|
|
||||||
doAssert(not isNilOrEmpty(" "))
|
|
||||||
|
|
||||||
doAssert(isNilOrWhitespace(""))
|
doAssert(isNilOrWhitespace(""))
|
||||||
doAssert(isNilOrWhitespace(nil))
|
|
||||||
doAssert(isNilOrWhitespace(" "))
|
doAssert(isNilOrWhitespace(" "))
|
||||||
doAssert(isNilOrWhitespace("\t\l \v\r\f"))
|
doAssert(isNilOrWhitespace("\t\l \v\r\f"))
|
||||||
doAssert(not isNilOrWhitespace("ABc \td"))
|
doAssert(not isNilOrWhitespace("ABc \td"))
|
||||||
|
|
|
||||||
|
|
@ -1318,24 +1318,23 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
|
||||||
result = ""
|
result = ""
|
||||||
var i = 0
|
var i = 0
|
||||||
var currentF = ""
|
var currentF = ""
|
||||||
while true:
|
while i < f.len:
|
||||||
case f[i]
|
case f[i]
|
||||||
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
|
of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',':
|
||||||
formatToken(dt, currentF, result)
|
formatToken(dt, currentF, result)
|
||||||
|
|
||||||
currentF = ""
|
currentF = ""
|
||||||
if f[i] == '\0': break
|
|
||||||
|
|
||||||
if f[i] == '\'':
|
if f[i] == '\'':
|
||||||
inc(i) # Skip '
|
inc(i) # Skip '
|
||||||
while f[i] != '\'' and f.len-1 > i:
|
while i < f.len-1 and f[i] != '\'':
|
||||||
result.add(f[i])
|
result.add(f[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
else: result.add(f[i])
|
else: result.add(f[i])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Check if the letter being added matches previous accumulated buffer.
|
# Check if the letter being added matches previous accumulated buffer.
|
||||||
if currentF.len < 1 or currentF[high(currentF)] == f[i]:
|
if currentF.len == 0 or currentF[high(currentF)] == f[i]:
|
||||||
currentF.add(f[i])
|
currentF.add(f[i])
|
||||||
else:
|
else:
|
||||||
formatToken(dt, currentF, result)
|
formatToken(dt, currentF, result)
|
||||||
|
|
@ -1343,6 +1342,7 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
|
||||||
currentF = ""
|
currentF = ""
|
||||||
|
|
||||||
inc(i)
|
inc(i)
|
||||||
|
formatToken(dt, currentF, result)
|
||||||
|
|
||||||
proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
|
proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
|
||||||
## Converts a `DateTime` object to a string representation.
|
## Converts a `DateTime` object to a string representation.
|
||||||
|
|
@ -1521,44 +1521,47 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
||||||
j += 4
|
j += 4
|
||||||
of "z":
|
of "z":
|
||||||
dt.isDst = false
|
dt.isDst = false
|
||||||
if value[j] == '+':
|
let ch = if j < value.len: value[j] else: '\0'
|
||||||
|
if ch == '+':
|
||||||
dt.utcOffset = 0 - parseInt($value[j+1]) * secondsInHour
|
dt.utcOffset = 0 - parseInt($value[j+1]) * secondsInHour
|
||||||
elif value[j] == '-':
|
elif ch == '-':
|
||||||
dt.utcOffset = parseInt($value[j+1]) * secondsInHour
|
dt.utcOffset = parseInt($value[j+1]) * secondsInHour
|
||||||
elif value[j] == 'Z':
|
elif ch == 'Z':
|
||||||
dt.utcOffset = 0
|
dt.utcOffset = 0
|
||||||
j += 1
|
j += 1
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Couldn't parse timezone offset (z), got: " & value[j])
|
"Couldn't parse timezone offset (z), got: " & ch)
|
||||||
j += 2
|
j += 2
|
||||||
of "zz":
|
of "zz":
|
||||||
dt.isDst = false
|
dt.isDst = false
|
||||||
if value[j] == '+':
|
let ch = if j < value.len: value[j] else: '\0'
|
||||||
|
if ch == '+':
|
||||||
dt.utcOffset = 0 - value[j+1..j+2].parseInt() * secondsInHour
|
dt.utcOffset = 0 - value[j+1..j+2].parseInt() * secondsInHour
|
||||||
elif value[j] == '-':
|
elif ch == '-':
|
||||||
dt.utcOffset = value[j+1..j+2].parseInt() * secondsInHour
|
dt.utcOffset = value[j+1..j+2].parseInt() * secondsInHour
|
||||||
elif value[j] == 'Z':
|
elif ch == 'Z':
|
||||||
dt.utcOffset = 0
|
dt.utcOffset = 0
|
||||||
j += 1
|
j += 1
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Couldn't parse timezone offset (zz), got: " & value[j])
|
"Couldn't parse timezone offset (zz), got: " & ch)
|
||||||
j += 3
|
j += 3
|
||||||
of "zzz":
|
of "zzz":
|
||||||
dt.isDst = false
|
dt.isDst = false
|
||||||
var factor = 0
|
var factor = 0
|
||||||
if value[j] == '+': factor = -1
|
let ch = if j < value.len: value[j] else: '\0'
|
||||||
elif value[j] == '-': factor = 1
|
if ch == '+': factor = -1
|
||||||
elif value[j] == 'Z':
|
elif ch == '-': factor = 1
|
||||||
|
elif ch == 'Z':
|
||||||
dt.utcOffset = 0
|
dt.utcOffset = 0
|
||||||
j += 1
|
j += 1
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Couldn't parse timezone offset (zzz), got: " & value[j])
|
"Couldn't parse timezone offset (zzz), got: " & ch)
|
||||||
dt.utcOffset = factor * value[j+1..j+2].parseInt() * secondsInHour
|
dt.utcOffset = factor * value[j+1..j+2].parseInt() * secondsInHour
|
||||||
j += 4
|
j += 4
|
||||||
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
|
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
|
||||||
|
|
@ -1620,20 +1623,18 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
|
||||||
dt.nanosecond = 0
|
dt.nanosecond = 0
|
||||||
dt.isDst = true # using this is flag for checking whether a timezone has \
|
dt.isDst = true # using this is flag for checking whether a timezone has \
|
||||||
# been read (because DST is always false when a tz is parsed)
|
# been read (because DST is always false when a tz is parsed)
|
||||||
while true:
|
while i < layout.len:
|
||||||
case layout[i]
|
case layout[i]
|
||||||
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
|
of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',':
|
||||||
if token.len > 0:
|
if token.len > 0:
|
||||||
parseToken(dt, token, value, j)
|
parseToken(dt, token, value, j)
|
||||||
# Reset token
|
# Reset token
|
||||||
token = ""
|
token = ""
|
||||||
# Break if at end of line
|
|
||||||
if layout[i] == '\0': break
|
|
||||||
# Skip separator and everything between single quotes
|
# Skip separator and everything between single quotes
|
||||||
# These are literals in both the layout and the value string
|
# These are literals in both the layout and the value string
|
||||||
if layout[i] == '\'':
|
if layout[i] == '\'':
|
||||||
inc(i)
|
inc(i)
|
||||||
while layout[i] != '\'' and layout.len-1 > i:
|
while i < layout.len-1 and layout[i] != '\'':
|
||||||
inc(i)
|
inc(i)
|
||||||
inc(j)
|
inc(j)
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
@ -1642,13 +1643,15 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
|
||||||
inc(j)
|
inc(j)
|
||||||
else:
|
else:
|
||||||
# Check if the letter being added matches previous accumulated buffer.
|
# Check if the letter being added matches previous accumulated buffer.
|
||||||
if token.len < 1 or token[high(token)] == layout[i]:
|
if token.len == 0 or token[high(token)] == layout[i]:
|
||||||
token.add(layout[i])
|
token.add(layout[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
else:
|
else:
|
||||||
parseToken(dt, token, value, j)
|
parseToken(dt, token, value, j)
|
||||||
token = ""
|
token = ""
|
||||||
|
|
||||||
|
if i >= layout.len and token.len > 0:
|
||||||
|
parseToken(dt, token, value, j)
|
||||||
if dt.isDst:
|
if dt.isDst:
|
||||||
# No timezone parsed - assume timezone is `zone`
|
# No timezone parsed - assume timezone is `zone`
|
||||||
result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone)
|
result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone)
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ proc parseAuthority(authority: string, result: var Uri) =
|
||||||
var i = 0
|
var i = 0
|
||||||
var inPort = false
|
var inPort = false
|
||||||
var inIPv6 = false
|
var inIPv6 = false
|
||||||
while true:
|
while i < authority.len:
|
||||||
case authority[i]
|
case authority[i]
|
||||||
of '@':
|
of '@':
|
||||||
swap result.password, result.port
|
swap result.password, result.port
|
||||||
|
|
@ -111,7 +111,6 @@ proc parseAuthority(authority: string, result: var Uri) =
|
||||||
inIPv6 = true
|
inIPv6 = true
|
||||||
of ']':
|
of ']':
|
||||||
inIPv6 = false
|
inIPv6 = false
|
||||||
of '\0': break
|
|
||||||
else:
|
else:
|
||||||
if inPort:
|
if inPort:
|
||||||
result.port.add(authority[i])
|
result.port.add(authority[i])
|
||||||
|
|
@ -128,11 +127,11 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
|
||||||
parseAuthority(result.path, result)
|
parseAuthority(result.path, result)
|
||||||
result.path.setLen(0)
|
result.path.setLen(0)
|
||||||
|
|
||||||
if uri[i] == '?':
|
if i < uri.len and uri[i] == '?':
|
||||||
i.inc # Skip '?'
|
i.inc # Skip '?'
|
||||||
i.inc parseUntil(uri, result.query, {'#'}, i)
|
i.inc parseUntil(uri, result.query, {'#'}, i)
|
||||||
|
|
||||||
if uri[i] == '#':
|
if i < uri.len and uri[i] == '#':
|
||||||
i.inc # Skip '#'
|
i.inc # Skip '#'
|
||||||
i.inc parseUntil(uri, result.anchor, {}, i)
|
i.inc parseUntil(uri, result.anchor, {}, i)
|
||||||
|
|
||||||
|
|
@ -156,7 +155,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||||
|
|
||||||
# Check if this is a reference URI (relative URI)
|
# Check if this is a reference URI (relative URI)
|
||||||
let doubleSlash = uri.len > 1 and uri[1] == '/'
|
let doubleSlash = uri.len > 1 and uri[1] == '/'
|
||||||
if uri[i] == '/':
|
if i < uri.len and uri[i] == '/':
|
||||||
# Make sure ``uri`` doesn't begin with '//'.
|
# Make sure ``uri`` doesn't begin with '//'.
|
||||||
if not doubleSlash:
|
if not doubleSlash:
|
||||||
parsePath(uri, i, result)
|
parsePath(uri, i, result)
|
||||||
|
|
@ -164,7 +163,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||||
|
|
||||||
# Scheme
|
# Scheme
|
||||||
i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i)
|
i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i)
|
||||||
if uri[i] != ':' and not doubleSlash:
|
if (i >= uri.len or uri[i] != ':') and not doubleSlash:
|
||||||
# Assume this is a reference URI (relative URI)
|
# Assume this is a reference URI (relative URI)
|
||||||
i = 0
|
i = 0
|
||||||
result.scheme.setLen(0)
|
result.scheme.setLen(0)
|
||||||
|
|
@ -174,7 +173,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||||
i.inc # Skip ':'
|
i.inc # Skip ':'
|
||||||
|
|
||||||
# Authority
|
# Authority
|
||||||
if uri[i] == '/' and uri[i+1] == '/':
|
if i+1 < uri.len and uri[i] == '/' and uri[i+1] == '/':
|
||||||
i.inc(2) # Skip //
|
i.inc(2) # Skip //
|
||||||
var authority = ""
|
var authority = ""
|
||||||
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
||||||
|
|
@ -197,13 +196,13 @@ proc removeDotSegments(path: string): string =
|
||||||
let endsWithSlash = path[path.len-1] == '/'
|
let endsWithSlash = path[path.len-1] == '/'
|
||||||
var i = 0
|
var i = 0
|
||||||
var currentSegment = ""
|
var currentSegment = ""
|
||||||
while true:
|
while i < path.len:
|
||||||
case path[i]
|
case path[i]
|
||||||
of '/':
|
of '/':
|
||||||
collection.add(currentSegment)
|
collection.add(currentSegment)
|
||||||
currentSegment = ""
|
currentSegment = ""
|
||||||
of '.':
|
of '.':
|
||||||
if path[i+1] == '.' and path[i+2] == '/':
|
if i+2 < path.len and path[i+1] == '.' and path[i+2] == '/':
|
||||||
if collection.len > 0:
|
if collection.len > 0:
|
||||||
discard collection.pop()
|
discard collection.pop()
|
||||||
i.inc 3
|
i.inc 3
|
||||||
|
|
@ -212,13 +211,11 @@ proc removeDotSegments(path: string): string =
|
||||||
i.inc 2
|
i.inc 2
|
||||||
continue
|
continue
|
||||||
currentSegment.add path[i]
|
currentSegment.add path[i]
|
||||||
of '\0':
|
|
||||||
if currentSegment != "":
|
|
||||||
collection.add currentSegment
|
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
currentSegment.add path[i]
|
currentSegment.add path[i]
|
||||||
i.inc
|
i.inc
|
||||||
|
if currentSegment != "":
|
||||||
|
collection.add currentSegment
|
||||||
|
|
||||||
result = collection.join("/")
|
result = collection.join("/")
|
||||||
if endsWithSlash: result.add '/'
|
if endsWithSlash: result.add '/'
|
||||||
|
|
@ -320,18 +317,18 @@ proc `/`*(x: Uri, path: string): Uri =
|
||||||
result = x
|
result = x
|
||||||
|
|
||||||
if result.path.len == 0:
|
if result.path.len == 0:
|
||||||
if path[0] != '/':
|
if path.len == 0 or path[0] != '/':
|
||||||
result.path = "/"
|
result.path = "/"
|
||||||
result.path.add(path)
|
result.path.add(path)
|
||||||
return
|
return
|
||||||
|
|
||||||
if result.path[result.path.len-1] == '/':
|
if result.path.len > 0 and result.path[result.path.len-1] == '/':
|
||||||
if path[0] == '/':
|
if path.len > 0 and path[0] == '/':
|
||||||
result.path.add(path[1 .. path.len-1])
|
result.path.add(path[1 .. path.len-1])
|
||||||
else:
|
else:
|
||||||
result.path.add(path)
|
result.path.add(path)
|
||||||
else:
|
else:
|
||||||
if path[0] != '/':
|
if path.len == 0 or path[0] != '/':
|
||||||
result.path.add '/'
|
result.path.add '/'
|
||||||
result.path.add(path)
|
result.path.add(path)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
|
||||||
raise newException(EInvalidCharacterErr, "Invalid character")
|
raise newException(EInvalidCharacterErr, "Invalid character")
|
||||||
# Exceptions
|
# Exceptions
|
||||||
if qualifiedName.contains(':'):
|
if qualifiedName.contains(':'):
|
||||||
let qfnamespaces = qualifiedName.toLower().split(':')
|
let qfnamespaces = qualifiedName.toLowerAscii().split(':')
|
||||||
if isNil(namespaceURI):
|
if isNil(namespaceURI):
|
||||||
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
|
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
|
||||||
elif qfnamespaces[0] == "xml" and
|
elif qfnamespaces[0] == "xml" and
|
||||||
|
|
@ -311,7 +311,7 @@ proc createElement*(doc: PDocument, tagName: string): PElement =
|
||||||
proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement =
|
proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement =
|
||||||
## Creates an element of the given qualified name and namespace URI.
|
## Creates an element of the given qualified name and namespace URI.
|
||||||
if qualifiedName.contains(':'):
|
if qualifiedName.contains(':'):
|
||||||
let qfnamespaces = qualifiedName.toLower().split(':')
|
let qfnamespaces = qualifiedName.toLowerAscii().split(':')
|
||||||
if isNil(namespaceURI):
|
if isNil(namespaceURI):
|
||||||
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
|
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
|
||||||
elif qfnamespaces[0] == "xml" and
|
elif qfnamespaces[0] == "xml" and
|
||||||
|
|
@ -533,13 +533,13 @@ proc `prefix=`*(n: PNode, value: string) =
|
||||||
|
|
||||||
if isNil(n.fNamespaceURI):
|
if isNil(n.fNamespaceURI):
|
||||||
raise newException(ENamespaceErr, "namespaceURI cannot be nil")
|
raise newException(ENamespaceErr, "namespaceURI cannot be nil")
|
||||||
elif value.toLower() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
|
elif value.toLowerAscii() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
|
||||||
raise newException(ENamespaceErr,
|
raise newException(ENamespaceErr,
|
||||||
"When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
|
"When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
|
||||||
elif value.toLower() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/":
|
elif value.toLowerAscii() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/":
|
||||||
raise newException(ENamespaceErr,
|
raise newException(ENamespaceErr,
|
||||||
"When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
|
"When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
|
||||||
elif value.toLower() == "xmlns" and n.fNodeType == AttributeNode:
|
elif value.toLowerAscii() == "xmlns" and n.fNodeType == AttributeNode:
|
||||||
raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"")
|
raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"")
|
||||||
|
|
||||||
n.fNodeName = value & ":" & n.fLocalName
|
n.fNodeName = value & ":" & n.fLocalName
|
||||||
|
|
|
||||||
|
|
@ -1280,15 +1280,13 @@ proc setLen*[T](s: var seq[T], newlen: Natural) {.
|
||||||
## sets the length of `s` to `newlen`.
|
## sets the length of `s` to `newlen`.
|
||||||
## ``T`` may be any sequence type.
|
## ``T`` may be any sequence type.
|
||||||
## If the current length is greater than the new length,
|
## If the current length is greater than the new length,
|
||||||
## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
|
## ``s`` will be truncated.
|
||||||
## a size, use ``newSeq`` instead.
|
|
||||||
|
|
||||||
proc setLen*(s: var string, newlen: Natural) {.
|
proc setLen*(s: var string, newlen: Natural) {.
|
||||||
magic: "SetLengthStr", noSideEffect.}
|
magic: "SetLengthStr", noSideEffect.}
|
||||||
## sets the length of `s` to `newlen`.
|
## sets the length of `s` to `newlen`.
|
||||||
## If the current length is greater than the new length,
|
## If the current length is greater than the new length,
|
||||||
## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
|
## ``s`` will be truncated.
|
||||||
## a size, use ``newString`` instead.
|
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## var myS = "Nim is great!!"
|
## var myS = "Nim is great!!"
|
||||||
|
|
@ -2414,6 +2412,7 @@ proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
|
||||||
if seqToPtr(x) == seqToPtr(y):
|
if seqToPtr(x) == seqToPtr(y):
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
when not defined(nimNoNil):
|
||||||
if x.isNil or y.isNil:
|
if x.isNil or y.isNil:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
@ -3224,7 +3223,7 @@ when not defined(JS): #and not defined(nimscript):
|
||||||
when declared(initGC): initGC()
|
when declared(initGC): initGC()
|
||||||
|
|
||||||
when not defined(nimscript):
|
when not defined(nimscript):
|
||||||
proc setControlCHook*(hook: proc () {.noconv.} not nil)
|
proc setControlCHook*(hook: proc () {.noconv.})
|
||||||
## allows you to override the behaviour of your application when CTRL+C
|
## allows you to override the behaviour of your application when CTRL+C
|
||||||
## is pressed. Only one such hook is supported.
|
## is pressed. Only one such hook is supported.
|
||||||
|
|
||||||
|
|
@ -4012,18 +4011,18 @@ proc addQuoted*[T](s: var string, x: T) =
|
||||||
|
|
||||||
when hasAlloc:
|
when hasAlloc:
|
||||||
# XXX: make these the default (or implement the NilObject optimization)
|
# XXX: make these the default (or implement the NilObject optimization)
|
||||||
proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} =
|
proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} =
|
||||||
## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case,
|
## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case,
|
||||||
## ``x`` becomes ``@[y]``
|
## ``x`` becomes ``@[y]``
|
||||||
if x == nil: x = @[y]
|
if x == nil: x = @[y]
|
||||||
else: x.add(y)
|
else: x.add(y)
|
||||||
|
|
||||||
proc safeAdd*(x: var string, y: char) =
|
proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} =
|
||||||
## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""``
|
## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""``
|
||||||
if x == nil: x = ""
|
if x == nil: x = ""
|
||||||
x.add(y)
|
x.add(y)
|
||||||
|
|
||||||
proc safeAdd*(x: var string, y: string) =
|
proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} =
|
||||||
## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that
|
## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that
|
||||||
## case, ``x`` becomes ``y``
|
## case, ``x`` becomes ``y``
|
||||||
if x == nil: x = y
|
if x == nil: x = y
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,4 @@ proc reraiseException() {.compilerRtl.} =
|
||||||
|
|
||||||
proc writeStackTrace() = discard
|
proc writeStackTrace() = discard
|
||||||
|
|
||||||
proc setControlCHook(hook: proc () {.noconv.} not nil) = discard
|
proc setControlCHook(hook: proc () {.noconv.}) = discard
|
||||||
|
|
|
||||||
|
|
@ -503,7 +503,7 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
|
||||||
|
|
||||||
registerSignalHandler() # call it in initialization section
|
registerSignalHandler() # call it in initialization section
|
||||||
|
|
||||||
proc setControlCHook(hook: proc () {.noconv.} not nil) =
|
proc setControlCHook(hook: proc () {.noconv.}) =
|
||||||
# ugly cast, but should work on all architectures:
|
# ugly cast, but should work on all architectures:
|
||||||
type SignalHandler = proc (sign: cint) {.noconv, benign.}
|
type SignalHandler = proc (sign: cint) {.noconv, benign.}
|
||||||
c_signal(SIGINT, cast[SignalHandler](hook))
|
c_signal(SIGINT, cast[SignalHandler](hook))
|
||||||
|
|
|
||||||
|
|
@ -22,21 +22,34 @@ proc resize(old: int): int {.inline.} =
|
||||||
|
|
||||||
proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
|
proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
|
||||||
if a == b: return 0
|
if a == b: return 0
|
||||||
|
when defined(nimNoNil):
|
||||||
|
let alen = if a == nil: 0 else: a.len
|
||||||
|
let blen = if b == nil: 0 else: b.len
|
||||||
|
else:
|
||||||
if a == nil: return -1
|
if a == nil: return -1
|
||||||
if b == nil: return 1
|
if b == nil: return 1
|
||||||
let minlen = min(a.len, b.len)
|
let alen = a.len
|
||||||
|
let blen = b.len
|
||||||
|
let minlen = min(alen, blen)
|
||||||
if minlen > 0:
|
if minlen > 0:
|
||||||
result = c_memcmp(addr a.data, addr b.data, minlen.csize)
|
result = c_memcmp(addr a.data, addr b.data, minlen.csize)
|
||||||
if result == 0:
|
if result == 0:
|
||||||
result = a.len - b.len
|
result = alen - blen
|
||||||
else:
|
else:
|
||||||
result = a.len - b.len
|
result = alen - blen
|
||||||
|
|
||||||
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
||||||
if a == b: return true
|
if a == b: return true
|
||||||
|
when defined(nimNoNil):
|
||||||
|
let alen = if a == nil: 0 else: a.len
|
||||||
|
let blen = if b == nil: 0 else: b.len
|
||||||
|
else:
|
||||||
if a == nil or b == nil: return false
|
if a == nil or b == nil: return false
|
||||||
return a.len == b.len and
|
let alen = a.len
|
||||||
equalMem(addr(a.data), addr(b.data), a.len)
|
let blen = b.len
|
||||||
|
if alen == blen:
|
||||||
|
if alen == 0: return true
|
||||||
|
return equalMem(addr(a.data), addr(b.data), alen)
|
||||||
|
|
||||||
when declared(allocAtomic):
|
when declared(allocAtomic):
|
||||||
template allocStr(size: untyped): untyped =
|
template allocStr(size: untyped): untyped =
|
||||||
|
|
@ -101,9 +114,6 @@ proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
||||||
if str == nil: NimString(nil)
|
if str == nil: NimString(nil)
|
||||||
else: toNimStr(str, str.len)
|
else: toNimStr(str, str.len)
|
||||||
|
|
||||||
template wasMoved(x: NimString): bool = false
|
|
||||||
# (x.reserved and seqShallowFlag) != 0
|
|
||||||
|
|
||||||
proc copyString(src: NimString): NimString {.compilerRtl.} =
|
proc copyString(src: NimString): NimString {.compilerRtl.} =
|
||||||
if src != nil:
|
if src != nil:
|
||||||
if (src.reserved and seqShallowFlag) != 0:
|
if (src.reserved and seqShallowFlag) != 0:
|
||||||
|
|
@ -161,14 +171,16 @@ proc hashString(s: string): int {.compilerproc.} =
|
||||||
|
|
||||||
proc addChar(s: NimString, c: char): NimString =
|
proc addChar(s: NimString, c: char): NimString =
|
||||||
# is compilerproc!
|
# is compilerproc!
|
||||||
|
if s == nil:
|
||||||
|
result = rawNewStringNoInit(1)
|
||||||
|
result.len = 0
|
||||||
|
else:
|
||||||
result = s
|
result = s
|
||||||
if result.len >= result.space:
|
if result.len >= result.space:
|
||||||
let r = resize(result.space)
|
let r = resize(result.space)
|
||||||
result = cast[NimString](growObj(result,
|
result = cast[NimString](growObj(result,
|
||||||
sizeof(TGenericSeq) + r + 1))
|
sizeof(TGenericSeq) + r + 1))
|
||||||
result.reserved = r
|
result.reserved = r
|
||||||
elif wasMoved(s):
|
|
||||||
result = newOwnedString(s, s.len)
|
|
||||||
result.data[result.len] = c
|
result.data[result.len] = c
|
||||||
result.data[result.len+1] = '\0'
|
result.data[result.len+1] = '\0'
|
||||||
inc(result.len)
|
inc(result.len)
|
||||||
|
|
@ -205,7 +217,9 @@ proc addChar(s: NimString, c: char): NimString =
|
||||||
# s = rawNewString(0);
|
# s = rawNewString(0);
|
||||||
|
|
||||||
proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
|
proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
|
||||||
if dest.len + addlen <= dest.space and not wasMoved(dest):
|
if dest == nil:
|
||||||
|
result = rawNewStringNoInit(addlen)
|
||||||
|
elif dest.len + addlen <= dest.space:
|
||||||
result = dest
|
result = dest
|
||||||
else: # slow path:
|
else: # slow path:
|
||||||
var sp = max(resize(dest.space), dest.len + addlen)
|
var sp = max(resize(dest.space), dest.len + addlen)
|
||||||
|
|
@ -216,6 +230,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
|
||||||
# DO NOT UPDATE LEN YET: dest.len = newLen
|
# DO NOT UPDATE LEN YET: dest.len = newLen
|
||||||
|
|
||||||
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
||||||
|
if src != nil:
|
||||||
copyMem(addr(dest.data[dest.len]), addr(src.data), src.len + 1)
|
copyMem(addr(dest.data[dest.len]), addr(src.data), src.len + 1)
|
||||||
inc(dest.len, src.len)
|
inc(dest.len, src.len)
|
||||||
|
|
||||||
|
|
@ -226,8 +241,8 @@ proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} =
|
||||||
|
|
||||||
proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
||||||
var n = max(newLen, 0)
|
var n = max(newLen, 0)
|
||||||
if wasMoved(s):
|
if s == nil:
|
||||||
result = newOwnedString(s, n)
|
result = mnewString(newLen)
|
||||||
elif n <= s.space:
|
elif n <= s.space:
|
||||||
result = s
|
result = s
|
||||||
else:
|
else:
|
||||||
|
|
@ -261,6 +276,18 @@ proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
|
||||||
GenericSeqSize))
|
GenericSeqSize))
|
||||||
result.reserved = r
|
result.reserved = r
|
||||||
|
|
||||||
|
proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} =
|
||||||
|
if s == nil:
|
||||||
|
result = cast[PGenericSeq](newSeq(typ, 1))
|
||||||
|
result.len = 0
|
||||||
|
else:
|
||||||
|
result = s
|
||||||
|
if result.len >= result.space:
|
||||||
|
let r = resize(result.space)
|
||||||
|
result = cast[PGenericSeq](growObj(result, typ.base.size * r +
|
||||||
|
GenericSeqSize))
|
||||||
|
result.reserved = r
|
||||||
|
|
||||||
proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||||
compilerRtl, inl.} =
|
compilerRtl, inl.} =
|
||||||
result = seq
|
result = seq
|
||||||
|
|
@ -301,6 +328,13 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||||
(newLen*%elemSize)), (result.len-%newLen) *% elemSize)
|
(newLen*%elemSize)), (result.len-%newLen) *% elemSize)
|
||||||
result.len = newLen
|
result.len = newLen
|
||||||
|
|
||||||
|
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||||
|
compilerRtl.} =
|
||||||
|
if s == nil:
|
||||||
|
result = cast[PGenericSeq](newSeq(typ, newLen))
|
||||||
|
else:
|
||||||
|
result = setLengthSeq(s, typ.base.size, newLen)
|
||||||
|
|
||||||
# --------------- other string routines ----------------------------------
|
# --------------- other string routines ----------------------------------
|
||||||
proc add*(result: var string; x: int64) =
|
proc add*(result: var string; x: int64) =
|
||||||
let base = result.len
|
let base = result.len
|
||||||
|
|
|
||||||
51
tests/array/tarraycons_ptr_generic.nim
Normal file
51
tests/array/tarraycons_ptr_generic.nim
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
discard """
|
||||||
|
output: '''apple
|
||||||
|
banana
|
||||||
|
Fruit
|
||||||
|
2
|
||||||
|
4
|
||||||
|
3
|
||||||
|
none
|
||||||
|
skin
|
||||||
|
paper
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
type
|
||||||
|
Fruit = object of RootObj
|
||||||
|
name: string
|
||||||
|
Apple = object of Fruit
|
||||||
|
Banana = object of Fruit
|
||||||
|
|
||||||
|
var
|
||||||
|
ir = Fruit(name: "Fruit")
|
||||||
|
ia = Apple(name: "apple")
|
||||||
|
ib = Banana(name: "banana")
|
||||||
|
|
||||||
|
let x = [ia.addr, ib.addr, ir.addr]
|
||||||
|
for c in x: echo c.name
|
||||||
|
|
||||||
|
type
|
||||||
|
Vehicle[T] = object of RootObj
|
||||||
|
tire: T
|
||||||
|
Car[T] = object of Vehicle[T]
|
||||||
|
Bike[T] = object of Vehicle[T]
|
||||||
|
|
||||||
|
var v = Vehicle[int](tire: 3)
|
||||||
|
var c = Car[int](tire: 4)
|
||||||
|
var b = Bike[int](tire: 2)
|
||||||
|
|
||||||
|
let y = [b.addr, c.addr, v.addr]
|
||||||
|
for c in y: echo c.tire
|
||||||
|
|
||||||
|
type
|
||||||
|
Book[T] = ref object of RootObj
|
||||||
|
cover: T
|
||||||
|
Hard[T] = ref object of Book[T]
|
||||||
|
Soft[T] = ref object of Book[T]
|
||||||
|
|
||||||
|
var bn = Book[string](cover: "none")
|
||||||
|
var hs = Hard[string](cover: "skin")
|
||||||
|
var bp = Soft[string](cover: "paper")
|
||||||
|
|
||||||
|
let z = [bn, hs, bp]
|
||||||
|
for c in z: echo c.cover
|
||||||
17
tests/array/tarraycons_ptr_generic2.nim
Normal file
17
tests/array/tarraycons_ptr_generic2.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
file: "tarraycons_ptr_generic2.nim"
|
||||||
|
line: 17
|
||||||
|
errormsg: "type mismatch: got <ptr Hard[system.string]> but expected 'Book[system.string]'"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
Book[T] = ref object of RootObj
|
||||||
|
cover: T
|
||||||
|
Hard[T] = ref object of Book[T]
|
||||||
|
Soft[T] = ref object of Book[T]
|
||||||
|
|
||||||
|
var bn = Book[string](cover: "none")
|
||||||
|
var hs = Hard[string](cover: "skin")
|
||||||
|
var bp = Soft[string](cover: "paper")
|
||||||
|
|
||||||
|
let z = [bn, hs.addr, bp]
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
# bug 2007
|
# bug 2007
|
||||||
|
|
||||||
import asyncdispatch, asyncnet, logging, json, uri, strutils, future
|
import asyncdispatch, asyncnet, logging, json, uri, strutils, sugar
|
||||||
|
|
||||||
type
|
type
|
||||||
Builder = ref object
|
Builder = ref object
|
||||||
|
|
@ -27,7 +27,7 @@ proc newBuild*(onProgress: ProgressCB): Build =
|
||||||
result.onProgress = onProgress
|
result.onProgress = onProgress
|
||||||
|
|
||||||
proc start(build: Build, repo, hash: string) {.async.} =
|
proc start(build: Build, repo, hash: string) {.async.} =
|
||||||
let path = repo.parseUri().path.toLower()
|
let path = repo.parseUri().path.toLowerAscii()
|
||||||
|
|
||||||
proc onProgress(builder: Builder, message: string) {.async.} =
|
proc onProgress(builder: Builder, message: string) {.async.} =
|
||||||
debug($message)
|
debug($message)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# bug #3313
|
# bug #3313
|
||||||
import unittest, future
|
import unittest, sugar
|
||||||
|
{.experimental: "notnil".}
|
||||||
type
|
type
|
||||||
ListNodeKind = enum
|
ListNodeKind = enum
|
||||||
lnkNil, lnkCons
|
lnkNil, lnkCons
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ type
|
||||||
s.pop() is T
|
s.pop() is T
|
||||||
|
|
||||||
type ValueType = T
|
type ValueType = T
|
||||||
const ValueTypeName = T.name.toUpper
|
const ValueTypeName = T.name.toUpperAscii
|
||||||
|
|
||||||
proc genericAlgorithm[T](s: var Stack[T], y: T) =
|
proc genericAlgorithm[T](s: var Stack[T], y: T) =
|
||||||
static:
|
static:
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ template accept(x) =
|
||||||
|
|
||||||
template reject(x) =
|
template reject(x) =
|
||||||
static: assert(not compiles(x))
|
static: assert(not compiles(x))
|
||||||
|
{.experimental: "notnil".}
|
||||||
type
|
type
|
||||||
TRefObj = ref object
|
TRefObj = ref object
|
||||||
x: int
|
x: int
|
||||||
|
|
||||||
THasNotNils = object of TObject
|
THasNotNils = object of RootObj
|
||||||
a: TRefObj not nil
|
a: TRefObj not nil
|
||||||
b: TRefObj not nil
|
b: TRefObj not nil
|
||||||
c: TRefObj
|
c: TRefObj
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,6 @@ type TFoo = object
|
||||||
converter toPtr*(some: var TFoo): ptr TFoo = (addr some)
|
converter toPtr*(some: var TFoo): ptr TFoo = (addr some)
|
||||||
|
|
||||||
|
|
||||||
proc zoot(x: ptr TFoo) = nil
|
proc zoot(x: ptr TFoo) = discard
|
||||||
var x: Tfoo
|
var x: Tfoo
|
||||||
zoot(x)
|
zoot(x)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tnil.nim"
|
file: "tnil.nim"
|
||||||
output: '''0x1
|
output: '''1
|
||||||
|
0
|
||||||
nil
|
0
|
||||||
|
|
||||||
nil
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
disabled: "windows"
|
|
||||||
"""
|
"""
|
||||||
|
{.experimental: "notnil".}
|
||||||
type
|
type
|
||||||
MyPointer = distinct pointer
|
MyPointer = distinct pointer
|
||||||
MyString = distinct string
|
MyString = distinct string
|
||||||
|
|
@ -17,7 +13,8 @@ type
|
||||||
MyInt = distinct int
|
MyInt = distinct int
|
||||||
|
|
||||||
proc foo(a: MyPointer) =
|
proc foo(a: MyPointer) =
|
||||||
echo a.repr
|
# workaround a Windows 'repr' difference:
|
||||||
|
echo cast[int](a)
|
||||||
|
|
||||||
foo(cast[MyPointer](1))
|
foo(cast[MyPointer](1))
|
||||||
foo(cast[MyPointer](nil))
|
foo(cast[MyPointer](nil))
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ type
|
||||||
EIO2 = ref object of EIO
|
EIO2 = ref object of EIO
|
||||||
|
|
||||||
proc q() {.tags: [FIO].} =
|
proc q() {.tags: [FIO].} =
|
||||||
nil
|
discard
|
||||||
|
|
||||||
proc raiser(): int =
|
proc raiser(): int =
|
||||||
writeLine stdout, "arg"
|
writeLine stdout, "arg"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ discard """
|
||||||
exitcode: 1
|
exitcode: 1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc returnsNil(): string = return nil
|
proc returnsNil(): ref int = return nil
|
||||||
|
|
||||||
iterator fields*(a, b: int): int =
|
iterator fields*(a, b: int): int =
|
||||||
if a == b:
|
if a == b:
|
||||||
|
|
@ -17,6 +17,6 @@ proc main(): string =
|
||||||
result = ""
|
result = ""
|
||||||
for i in fields(0, 1):
|
for i in fields(0, 1):
|
||||||
let x = returnsNil()
|
let x = returnsNil()
|
||||||
result &= "string literal " & $x
|
result &= "string literal " & $x[]
|
||||||
|
|
||||||
echo main()
|
echo main()
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ proc `$`*(data: Tcommandline_results): string =
|
||||||
|
|
||||||
# - Parse code
|
# - Parse code
|
||||||
|
|
||||||
template raise_or_quit(exception, message: expr): stmt {.immediate.} =
|
template raise_or_quit(exception, message: untyped) =
|
||||||
## Avoids repeating if check based on the default quit_on_failure variable.
|
## Avoids repeating if check based on the default quit_on_failure variable.
|
||||||
##
|
##
|
||||||
## As a special case, if message has a zero length the call to quit won't
|
## As a special case, if message has a zero length the call to quit won't
|
||||||
|
|
@ -230,15 +230,15 @@ template run_custom_proc(parsed_parameter: Tparsed_parameter,
|
||||||
##
|
##
|
||||||
## Pass in the string of the parameter triggering the call. If the
|
## Pass in the string of the parameter triggering the call. If the
|
||||||
if not custom_validator.isNil:
|
if not custom_validator.isNil:
|
||||||
except:
|
try:
|
||||||
raise_or_quit(ValueError, ("Couldn't run custom proc for " &
|
|
||||||
"parameter $1:\n$2" % [escape(parameter),
|
|
||||||
getCurrentExceptionMsg()]))
|
|
||||||
let message = custom_validator(parameter, parsed_parameter)
|
let message = custom_validator(parameter, parsed_parameter)
|
||||||
if not message.isNil and message.len > 0:
|
if not message.isNil and message.len > 0:
|
||||||
raise_or_quit(ValueError, ("Failed to validate value for " &
|
raise_or_quit(ValueError, ("Failed to validate value for " &
|
||||||
"parameter $1:\n$2" % [escape(parameter), message]))
|
"parameter $1:\n$2" % [escape(parameter), message]))
|
||||||
|
except:
|
||||||
|
raise_or_quit(ValueError, ("Couldn't run custom proc for " &
|
||||||
|
"parameter $1:\n$2" % [escape(parameter),
|
||||||
|
getCurrentExceptionMsg()]))
|
||||||
|
|
||||||
proc parse_parameter(quit_on_failure: bool, param, value: string,
|
proc parse_parameter(quit_on_failure: bool, param, value: string,
|
||||||
param_kind: Tparam_kind): Tparsed_parameter =
|
param_kind: Tparam_kind): Tparsed_parameter =
|
||||||
|
|
|
||||||
|
|
@ -388,13 +388,13 @@ type
|
||||||
cdecl.}
|
cdecl.}
|
||||||
|
|
||||||
##cp property emulators
|
##cp property emulators
|
||||||
template defGetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
|
template defGetter(otype: typedesc, memberType: typedesc, memberName, procName: untyped) =
|
||||||
proc `get procName`*(obj: otype): memberType {.cdecl.} =
|
proc `get procName`*(obj: otype): memberType {.cdecl.} =
|
||||||
return obj.memberName
|
return obj.memberName
|
||||||
template defSetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
|
template defSetter(otype: typedesc, memberType: typedesc, memberName, procName: untyped) =
|
||||||
proc `set procName`*(obj: otype, value: memberType) {.cdecl.} =
|
proc `set procName`*(obj: otype, value: memberType) {.cdecl.} =
|
||||||
obj.memberName = value
|
obj.memberName = value
|
||||||
template defProp(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
|
template defProp(otype: typedesc, memberType: typedesc, memberName, procName: untyped) =
|
||||||
defGetter(otype, memberType, memberName, procName)
|
defGetter(otype, memberType, memberName, procName)
|
||||||
defSetter(otype, memberType, memberName, procName)
|
defSetter(otype, memberType, memberName, procName)
|
||||||
|
|
||||||
|
|
@ -908,7 +908,7 @@ proc getShapes*(arb: PArbiter, a, b: var PShape) {.inline.} =
|
||||||
|
|
||||||
#/ A macro shortcut for defining and retrieving the shapes from an arbiter.
|
#/ A macro shortcut for defining and retrieving the shapes from an arbiter.
|
||||||
#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
|
#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
|
||||||
template getShapes*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} =
|
template getShapes*(arb: PArbiter, name1, name2: untyped) =
|
||||||
var name1, name2: PShape
|
var name1, name2: PShape
|
||||||
getShapes(arb, name1, name2)
|
getShapes(arb, name1, name2)
|
||||||
|
|
||||||
|
|
@ -923,7 +923,7 @@ template getShapes*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} =
|
||||||
|
|
||||||
#/ A macro shortcut for defining and retrieving the bodies from an arbiter.
|
#/ A macro shortcut for defining and retrieving the bodies from an arbiter.
|
||||||
#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
|
#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
|
||||||
template getBodies*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} =
|
template getBodies*(arb: PArbiter, name1, name2: untyped) =
|
||||||
var name1, name2: PBOdy
|
var name1, name2: PBOdy
|
||||||
getBodies(arb, name1, name2)
|
getBodies(arb, name1, name2)
|
||||||
|
|
||||||
|
|
@ -947,11 +947,11 @@ proc getDepth*(arb: PArbiter; i: cint): CpFloat {.
|
||||||
cdecl, importc: "cpArbiterGetDepth", dynlib: Lib.}
|
cdecl, importc: "cpArbiterGetDepth", dynlib: Lib.}
|
||||||
|
|
||||||
##Shapes
|
##Shapes
|
||||||
template defShapeSetter(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} =
|
template defShapeSetter(memberType: typedesc, memberName: untyped, procName: untyped, activates: bool) =
|
||||||
proc `set procName`*(obj: PShape, value: memberType) {.cdecl.} =
|
proc `set procName`*(obj: PShape, value: memberType) {.cdecl.} =
|
||||||
if activates and obj.body != nil: obj.body.activate()
|
if activates and obj.body != nil: obj.body.activate()
|
||||||
obj.memberName = value
|
obj.memberName = value
|
||||||
template defShapeProp(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} =
|
template defShapeProp(memberType: typedesc, memberName: untyped, procName: untyped, activates: bool) =
|
||||||
defGetter(PShape, memberType, memberName, procName)
|
defGetter(PShape, memberType, memberName, procName)
|
||||||
defShapeSetter(memberType, memberName, procName, activates)
|
defShapeSetter(memberType, memberName, procName, activates)
|
||||||
|
|
||||||
|
|
@ -1272,11 +1272,11 @@ proc activateBodies(constraint: PConstraint) {.inline.} =
|
||||||
# cpConstraintActivateBodies(constraint); \
|
# cpConstraintActivateBodies(constraint); \
|
||||||
# constraint->member = value; \
|
# constraint->member = value; \
|
||||||
# }
|
# }
|
||||||
template defConstraintSetter(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
|
template defConstraintSetter(memberType: typedesc, member, name: untyped) =
|
||||||
proc `set name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
|
proc `set name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
|
||||||
activateBodies(constraint)
|
activateBodies(constraint)
|
||||||
constraint.member = value
|
constraint.member = value
|
||||||
template defConstraintProp(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
|
template defConstraintProp(memberType: typedesc, member, name: untyped) =
|
||||||
defGetter(PConstraint, memberType, member, name)
|
defGetter(PConstraint, memberType, member, name)
|
||||||
defConstraintSetter(memberType, member, name)
|
defConstraintSetter(memberType, member, name)
|
||||||
# CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space)
|
# CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space)
|
||||||
|
|
@ -1306,18 +1306,18 @@ proc getImpulse*(constraint: PConstraint): CpFloat {.inline.} =
|
||||||
# cpConstraintActivateBodies(constraint); \
|
# cpConstraintActivateBodies(constraint); \
|
||||||
# ((struct *)constraint)->member = value; \
|
# ((struct *)constraint)->member = value; \
|
||||||
# }
|
# }
|
||||||
template constraintCheckCast(constraint: PConstraint, ctype: expr): stmt {.immediate.} =
|
template constraintCheckCast(constraint: PConstraint, ctype: untyped) =
|
||||||
assert(constraint.klass == `ctype getClass`(), "Constraint is the wrong class")
|
assert(constraint.klass == `ctype getClass`(), "Constraint is the wrong class")
|
||||||
template defCGetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
|
template defCGetter(ctype: untyped, memberType: typedesc, member, name: untyped) =
|
||||||
proc `get ctype name`*(constraint: PConstraint): memberType {.cdecl.} =
|
proc `get ctype name`*(constraint: PConstraint): memberType {.cdecl.} =
|
||||||
constraintCheckCast(constraint, ctype)
|
constraintCheckCast(constraint, ctype)
|
||||||
result = cast[`P ctype`](constraint).member
|
result = cast[`P ctype`](constraint).member
|
||||||
template defCSetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
|
template defCSetter(ctype: untyped, memberType: typedesc, member, name: untyped) =
|
||||||
proc `set ctype name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
|
proc `set ctype name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
|
||||||
constraintCheckCast(constraint, ctype)
|
constraintCheckCast(constraint, ctype)
|
||||||
activateBodies(constraint)
|
activateBodies(constraint)
|
||||||
cast[`P ctype`](constraint).member = value
|
cast[`P ctype`](constraint).member = value
|
||||||
template defCProp(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
|
template defCProp(ctype: untyped, memberType: typedesc, member, name: untyped) =
|
||||||
defCGetter(ctype, memberType, member, name)
|
defCGetter(ctype, memberType, member, name)
|
||||||
defCSetter(ctype, memberType, member, name)
|
defCSetter(ctype, memberType, member, name)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ const
|
||||||
ENET_VERSION_MAJOR* = 1
|
ENET_VERSION_MAJOR* = 1
|
||||||
ENET_VERSION_MINOR* = 3
|
ENET_VERSION_MINOR* = 3
|
||||||
ENET_VERSION_PATCH* = 3
|
ENET_VERSION_PATCH* = 3
|
||||||
template ENET_VERSION_CREATE(major, minor, patch: expr): expr =
|
template ENET_VERSION_CREATE(major, minor, patch: untyped): untyped =
|
||||||
(((major) shl 16) or ((minor) shl 8) or (patch))
|
(((major) shl 16) or ((minor) shl 8) or (patch))
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -277,22 +277,22 @@ when defined(Linux) or true:
|
||||||
dataLength*: csize
|
dataLength*: csize
|
||||||
TENetSocketSet* = Tfd_set
|
TENetSocketSet* = Tfd_set
|
||||||
## see if these are different on win32, if not then get rid of these
|
## see if these are different on win32, if not then get rid of these
|
||||||
template ENET_HOST_TO_NET_16*(value: expr): expr =
|
template ENET_HOST_TO_NET_16*(value: untyped): untyped =
|
||||||
(htons(value))
|
(htons(value))
|
||||||
template ENET_HOST_TO_NET_32*(value: expr): expr =
|
template ENET_HOST_TO_NET_32*(value: untyped): untyped =
|
||||||
(htonl(value))
|
(htonl(value))
|
||||||
template ENET_NET_TO_HOST_16*(value: expr): expr =
|
template ENET_NET_TO_HOST_16*(value: untyped): untyped =
|
||||||
(ntohs(value))
|
(ntohs(value))
|
||||||
template ENET_NET_TO_HOST_32*(value: expr): expr =
|
template ENET_NET_TO_HOST_32*(value: untyped): untyped =
|
||||||
(ntohl(value))
|
(ntohl(value))
|
||||||
|
|
||||||
template ENET_SOCKETSET_EMPTY*(sockset: expr): expr =
|
template ENET_SOCKETSET_EMPTY*(sockset: untyped): untyped =
|
||||||
FD_ZERO(addr((sockset)))
|
FD_ZERO(addr((sockset)))
|
||||||
template ENET_SOCKETSET_ADD*(sockset, socket: expr): expr =
|
template ENET_SOCKETSET_ADD*(sockset, socket: untyped): untyped =
|
||||||
FD_SET(socket, addr((sockset)))
|
FD_SET(socket, addr((sockset)))
|
||||||
template ENET_SOCKETSET_REMOVE*(sockset, socket: expr): expr =
|
template ENET_SOCKETSET_REMOVE*(sockset, socket: untyped): untyped =
|
||||||
FD_CLEAR(socket, addr((sockset)))
|
FD_CLEAR(socket, addr((sockset)))
|
||||||
template ENET_SOCKETSET_CHECK*(sockset, socket: expr): expr =
|
template ENET_SOCKETSET_CHECK*(sockset, socket: untyped): untyped =
|
||||||
FD_ISSET(socket, addr((sockset)))
|
FD_ISSET(socket, addr((sockset)))
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
|
|
@ -606,7 +606,7 @@ proc protocolCommandSize*(commandNumber: cuchar): csize{.
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
from hashes import `!$`, `!&`, THash, hash
|
from hashes import `!$`, `!&`, Hash, hash
|
||||||
proc hash*(x: TAddress): THash {.nimcall, noSideEffect.} =
|
proc hash*(x: TAddress): Hash {.nimcall, noSideEffect.} =
|
||||||
result = !$(hash(x.host.int32) !& hash(x.port.int16))
|
result = !$(hash(x.host.int32) !& hash(x.port.int16))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import macros, macro_dsl, estreams
|
import macros, macro_dsl, estreams
|
||||||
from strutils import format
|
from strutils import format
|
||||||
|
|
||||||
template newLenName(): stmt {.immediate.} =
|
template newLenName() =
|
||||||
let lenName {.inject.} = ^("len"& $lenNames)
|
let lenName {.inject.} = ^("len"& $lenNames)
|
||||||
inc(lenNames)
|
inc(lenNames)
|
||||||
|
|
||||||
template defPacketImports*(): stmt {.immediate, dirty.} =
|
template defPacketImports*() {.dirty.} =
|
||||||
import macros, macro_dsl, estreams
|
import macros, macro_dsl, estreams
|
||||||
from strutils import format
|
from strutils import format
|
||||||
|
|
||||||
macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
|
macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
let
|
let
|
||||||
typeName = quoted2ident(typeNameN)
|
typeName = quoted2ident(typeNameN)
|
||||||
|
|
@ -60,7 +60,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
|
||||||
let
|
let
|
||||||
name = typeFields[i][0]
|
name = typeFields[i][0]
|
||||||
dotName = packetID.dot(name)
|
dotName = packetID.dot(name)
|
||||||
resName = newIdentNode(!"result").dot(name)
|
resName = newIdentNode("result").dot(name)
|
||||||
case typeFields[i][1].kind
|
case typeFields[i][1].kind
|
||||||
of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
|
of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
|
||||||
case $typeFields[i][1][0].ident
|
case $typeFields[i][1][0].ident
|
||||||
|
|
@ -200,7 +200,7 @@ proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} =
|
||||||
proc varTy*(a: NimNode): NimNode {.compileTime.} =
|
proc varTy*(a: NimNode): NimNode {.compileTime.} =
|
||||||
result = newNimNode(nnkVarTy).und(a)
|
result = newNimNode(nnkVarTy).und(a)
|
||||||
|
|
||||||
macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
|
macro forwardPacket*(typeName: untyped, underlyingType: untyped): untyped =
|
||||||
var
|
var
|
||||||
packetID = ^"p"
|
packetID = ^"p"
|
||||||
streamID = ^"s"
|
streamID = ^"s"
|
||||||
|
|
@ -234,7 +234,7 @@ macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
|
||||||
echo "unknown type:", repr(underlyingtype)
|
echo "unknown type:", repr(underlyingtype)
|
||||||
echo(repr(result))
|
echo(repr(result))
|
||||||
|
|
||||||
template forwardPacketT*(typeName: expr; underlyingType: expr): stmt {.dirty, immediate.} =
|
template forwardPacketT*(typeName: untyped; underlyingType: untyped) {.dirty.} =
|
||||||
proc `read typeName`*(buffer: PBuffer): typeName =
|
proc `read typeName`*(buffer: PBuffer): typeName =
|
||||||
#discard readData(s, addr result, sizeof(result))
|
#discard readData(s, addr result, sizeof(result))
|
||||||
var res: underlyingType
|
var res: underlyingType
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ proc und*(a: NimNode; b: varargs[NimNode]): NimNode {.compileTime.} =
|
||||||
|
|
||||||
proc `^`*(a: string): NimNode {.compileTime.} =
|
proc `^`*(a: string): NimNode {.compileTime.} =
|
||||||
## new ident node
|
## new ident node
|
||||||
result = newIdentNode(!a)
|
result = newIdentNode(a)
|
||||||
proc `[]`*(a, b: NimNode): NimNode {.compileTime.} =
|
proc `[]`*(a, b: NimNode): NimNode {.compileTime.} =
|
||||||
## new bracket expression: node[node] not to be confused with node[indx]
|
## new bracket expression: node[node] not to be confused with node[indx]
|
||||||
result = newNimNode(nnkBracketExpr).und(a, b)
|
result = newNimNode(nnkBracketExpr).und(a, b)
|
||||||
|
|
@ -34,7 +34,7 @@ proc emptyNode*(): NimNode {.compileTime.} =
|
||||||
proc dot*(left, right: NimNode): NimNode {.compileTime.} =
|
proc dot*(left, right: NimNode): NimNode {.compileTime.} =
|
||||||
result = newNimNode(nnkDotExpr).und(left, right)
|
result = newNimNode(nnkDotExpr).und(left, right)
|
||||||
proc prefix*(a: string, b: NimNode): NimNode {.compileTime.} =
|
proc prefix*(a: string, b: NimNode): NimNode {.compileTime.} =
|
||||||
result = newNimNode(nnkPrefix).und(newIdentNode(!a), b)
|
result = newNimNode(nnkPrefix).und(newIdentNode(a), b)
|
||||||
|
|
||||||
proc quoted2ident*(a: NimNode): NimNode {.compileTime.} =
|
proc quoted2ident*(a: NimNode): NimNode {.compileTime.} =
|
||||||
if a.kind != nnkAccQuoted:
|
if a.kind != nnkAccQuoted:
|
||||||
|
|
@ -45,13 +45,13 @@ proc quoted2ident*(a: NimNode): NimNode {.compileTime.} =
|
||||||
result = ^pname
|
result = ^pname
|
||||||
|
|
||||||
|
|
||||||
macro `?`(a: expr): expr =
|
macro `?`(a: untyped): untyped =
|
||||||
## Character literal ?A #=> 'A'
|
## Character literal ?A #=> 'A'
|
||||||
result = ($a[1].ident)[0].lit
|
result = ($a[1].ident)[0].lit
|
||||||
## echo(?F,?a,?t,?t,?y)
|
## echo(?F,?a,?t,?t,?y)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
macro foo(x: stmt): stmt =
|
macro foo(x: untyped) =
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit))
|
result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit))
|
||||||
result.add(newCall("echo", lit("3 * 45 = "), (3.lit.infix("*", 45.lit))))
|
result.add(newCall("echo", lit("3 * 45 = "), (3.lit.infix("*", 45.lit))))
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ task "install", "compile and install nake binary":
|
||||||
for index, dir in pairs(path):
|
for index, dir in pairs(path):
|
||||||
echo " ", index, ". ", dir
|
echo " ", index, ". ", dir
|
||||||
echo "Where to install nake binary? (quit with ^C or quit or exit)"
|
echo "Where to install nake binary? (quit with ^C or quit or exit)"
|
||||||
let ans = stdin.readLine().toLower
|
let ans = stdin.readLine().toLowerAscii
|
||||||
var index = 0
|
var index = 0
|
||||||
case ans
|
case ans
|
||||||
of "q", "quit", "x", "exit":
|
of "q", "quit", "x", "exit":
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ proc write*(buffer: PBuffer; val: var string) =
|
||||||
setLen buffer.data, buffer.pos + length.int
|
setLen buffer.data, buffer.pos + length.int
|
||||||
copyMem(addr buffer.data[buffer.pos], addr val[0], length.int)
|
copyMem(addr buffer.data[buffer.pos], addr val[0], length.int)
|
||||||
inc buffer.pos, length.int
|
inc buffer.pos, length.int
|
||||||
proc write*[T: TNumber|bool|char|byte](buffer: PBuffer; val: T) =
|
proc write*[T: SomeNumber|bool|char|byte](buffer: PBuffer; val: T) =
|
||||||
var v: T
|
var v: T
|
||||||
shallowCopy v, val
|
shallowCopy v, val
|
||||||
writeBE buffer, v
|
writeBE buffer, v
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ type
|
||||||
TInputFinishedProc* = proc()
|
TInputFinishedProc* = proc()
|
||||||
TKeyCallback = proc()
|
TKeyCallback = proc()
|
||||||
PKeyClient* = ref object
|
PKeyClient* = ref object
|
||||||
onKeyDown: TTable[int32, TKeyCallback]
|
onKeyDown: Table[int32, TKeyCallback]
|
||||||
onKeyUp: TTable[int32, TKeyCallback]
|
onKeyUp: Table[int32, TKeyCallback]
|
||||||
name: string
|
name: string
|
||||||
PTextInput* = ref object
|
PTextInput* = ref object
|
||||||
text*: string
|
text*: string
|
||||||
|
|
@ -134,5 +134,5 @@ iterator pollEvents*(window: PRenderWindow): PEvent =
|
||||||
of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
|
of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
|
||||||
of EvtTextEntered: recordText(activeInput, event.text)
|
of EvtTextEntered: recordText(activeInput, event.text)
|
||||||
of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
|
of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
|
||||||
else: nil
|
else: discard
|
||||||
yield(addr event)
|
yield(addr event)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ type
|
||||||
of Projectile:
|
of Projectile:
|
||||||
bullet*: PBulletRecord
|
bullet*: PBulletRecord
|
||||||
else:
|
else:
|
||||||
nil
|
discard
|
||||||
PBulletRecord* = ref TBulletRecord
|
PBulletRecord* = ref TBulletRecord
|
||||||
TBulletRecord* = object
|
TBulletRecord* = object
|
||||||
id*: int16
|
id*: int16
|
||||||
|
|
@ -115,10 +115,10 @@ var
|
||||||
cfg: PZoneSettings
|
cfg: PZoneSettings
|
||||||
SpriteSheets* = initTable[string, PSpriteSheet](64)
|
SpriteSheets* = initTable[string, PSpriteSheet](64)
|
||||||
SoundCache * = initTable[string, PSoundRecord](64)
|
SoundCache * = initTable[string, PSoundRecord](64)
|
||||||
nameToVehID*: TTable[string, int]
|
nameToVehID*: Table[string, int]
|
||||||
nameToItemID*: TTable[string, int]
|
nameToItemID*: Table[string, int]
|
||||||
nameToObjID*: TTable[string, int]
|
nameToObjID*: Table[string, int]
|
||||||
nameToBulletID*: TTable[string, int]
|
nameToBulletID*: Table[string, int]
|
||||||
activeState = Lobby
|
activeState = Lobby
|
||||||
|
|
||||||
proc newSprite*(filename: string; errors: var seq[string]): PSpriteSheet
|
proc newSprite*(filename: string; errors: var seq[string]): PSpriteSheet
|
||||||
|
|
@ -126,7 +126,7 @@ proc load*(ss: PSpriteSheet): bool {.discardable.}
|
||||||
proc newSound*(filename: string; errors: var seq[string]): PSoundRecord
|
proc newSound*(filename: string; errors: var seq[string]): PSoundRecord
|
||||||
proc load*(s: PSoundRecord): bool {.discardable.}
|
proc load*(s: PSoundRecord): bool {.discardable.}
|
||||||
|
|
||||||
proc validateSettings*(settings: PJsonNode; errors: var seq[string]): bool
|
proc validateSettings*(settings: JsonNode; errors: var seq[string]): bool
|
||||||
proc loadSettings*(rawJson: string, errors: var seq[string]): bool
|
proc loadSettings*(rawJson: string, errors: var seq[string]): bool
|
||||||
proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool
|
proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool
|
||||||
|
|
||||||
|
|
@ -135,17 +135,17 @@ proc fetchItm*(itm: string): PItemRecord
|
||||||
proc fetchObj*(name: string): PObjectRecord
|
proc fetchObj*(name: string): PObjectRecord
|
||||||
proc fetchBullet(name: string): PBulletRecord
|
proc fetchBullet(name: string): PBulletRecord
|
||||||
|
|
||||||
proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings
|
proc importLevel(data: JsonNode; errors: var seq[string]): PLevelSettings
|
||||||
proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord
|
proc importVeh(data: JsonNode; errors: var seq[string]): PVehicleRecord
|
||||||
proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord
|
proc importObject(data: JsonNode; errors: var seq[string]): PObjectRecord
|
||||||
proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord
|
proc importItem(data: JsonNode; errors: var seq[string]): PItemRecord
|
||||||
proc importPhys(data: PJsonNode): TPhysicsRecord
|
proc importPhys(data: JsonNode): TPhysicsRecord
|
||||||
proc importAnim(data: PJsonNode; errors: var seq[string]): PAnimationRecord
|
proc importAnim(data: JsonNode; errors: var seq[string]): PAnimationRecord
|
||||||
proc importHandling(data: PJsonNode): THandlingRecord
|
proc importHandling(data: JsonNode): THandlingRecord
|
||||||
proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord
|
proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord
|
||||||
proc importSoul(data: PJsonNode): TSoulRecord
|
proc importSoul(data: JsonNode): TSoulRecord
|
||||||
proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord
|
proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord
|
||||||
proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord
|
proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord
|
||||||
|
|
||||||
## this is the only pipe between lobby and main.nim
|
## this is the only pipe between lobby and main.nim
|
||||||
proc getActiveState*(): TGameState =
|
proc getActiveState*(): TGameState =
|
||||||
|
|
@ -203,7 +203,7 @@ iterator playableVehicles*(): PVehicleRecord =
|
||||||
if v.playable:
|
if v.playable:
|
||||||
yield v
|
yield v
|
||||||
|
|
||||||
template allAssets*(body: stmt) {.dirty.}=
|
template allAssets*(body: untyped) {.dirty.}=
|
||||||
block:
|
block:
|
||||||
var assetType = FGraphics
|
var assetType = FGraphics
|
||||||
for file, asset in pairs(SpriteSheets):
|
for file, asset in pairs(SpriteSheets):
|
||||||
|
|
@ -212,7 +212,7 @@ template allAssets*(body: stmt) {.dirty.}=
|
||||||
for file, asset in pairs(SoundCache):
|
for file, asset in pairs(SoundCache):
|
||||||
body
|
body
|
||||||
|
|
||||||
template cacheImpl(procName, cacheName, resultType: expr; body: stmt) {.dirty, immediate.} =
|
template cacheImpl(procName, cacheName, resultType, body: untyped) {.dirty.} =
|
||||||
proc procName*(filename: string; errors: var seq[string]): resulttype =
|
proc procName*(filename: string; errors: var seq[string]): resulttype =
|
||||||
if hasKey(cacheName, filename):
|
if hasKey(cacheName, filename):
|
||||||
return cacheName[filename]
|
return cacheName[filename]
|
||||||
|
|
@ -220,7 +220,7 @@ template cacheImpl(procName, cacheName, resultType: expr; body: stmt) {.dirty, i
|
||||||
body
|
body
|
||||||
cacheName[filename] = result
|
cacheName[filename] = result
|
||||||
|
|
||||||
template checkFile(path: expr): stmt {.dirty, immediate.} =
|
template checkFile(path: untyped) {.dirty.} =
|
||||||
if not existsFile(path):
|
if not existsFile(path):
|
||||||
errors.add("File missing: "& path)
|
errors.add("File missing: "& path)
|
||||||
|
|
||||||
|
|
@ -243,7 +243,7 @@ proc expandPath*(assetType: TAssetType; fileName: string): string =
|
||||||
case assetType
|
case assetType
|
||||||
of FGraphics: result.add "gfx/"
|
of FGraphics: result.add "gfx/"
|
||||||
of FSound: result.add "sfx/"
|
of FSound: result.add "sfx/"
|
||||||
else: nil
|
else: discard
|
||||||
result.add fileName
|
result.add fileName
|
||||||
proc expandPath*(fc: ScFileChallenge): string {.inline.} =
|
proc expandPath*(fc: ScFileChallenge): string {.inline.} =
|
||||||
result = expandPath(fc.assetType, fc.file)
|
result = expandPath(fc.assetType, fc.file)
|
||||||
|
|
@ -280,10 +280,10 @@ else:
|
||||||
if not s.soundBuf.isNil:
|
if not s.soundBuf.isNil:
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
template addError(e: expr): stmt {.immediate.} =
|
template addError(e: untyped) =
|
||||||
errors.add(e)
|
errors.add(e)
|
||||||
result = false
|
result = false
|
||||||
proc validateSettings*(settings: PJsonNode, errors: var seq[string]): bool =
|
proc validateSettings*(settings: JsonNode, errors: var seq[string]): bool =
|
||||||
result = true
|
result = true
|
||||||
if settings.kind != JObject:
|
if settings.kind != JObject:
|
||||||
addError("Settings root must be an object")
|
addError("Settings root must be an object")
|
||||||
|
|
@ -328,10 +328,10 @@ proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool =
|
||||||
result = loadSettings(readFile(filename), errors)
|
result = loadSettings(readFile(filename), errors)
|
||||||
|
|
||||||
proc loadSettings*(rawJson: string, errors: var seq[string]): bool =
|
proc loadSettings*(rawJson: string, errors: var seq[string]): bool =
|
||||||
var settings: PJsonNode
|
var settings: JsonNode
|
||||||
try:
|
try:
|
||||||
settings = parseJson(rawJson)
|
settings = parseJson(rawJson)
|
||||||
except EJsonParsingError:
|
except JsonParsingError:
|
||||||
errors.add("JSON parsing error: "& getCurrentExceptionMsg())
|
errors.add("JSON parsing error: "& getCurrentExceptionMsg())
|
||||||
return
|
return
|
||||||
except:
|
except:
|
||||||
|
|
@ -407,21 +407,21 @@ proc fetchObj*(name: string): PObjectRecord =
|
||||||
proc fetchBullet(name: string): PBulletRecord =
|
proc fetchBullet(name: string): PBulletRecord =
|
||||||
return cfg.bullets[nameToBulletID[name]]
|
return cfg.bullets[nameToBulletID[name]]
|
||||||
|
|
||||||
proc getField(node: PJsonNode, field: string, target: var float) =
|
proc getField(node: JsonNode, field: string, target: var float) =
|
||||||
if not node.hasKey(field):
|
if not node.hasKey(field):
|
||||||
return
|
return
|
||||||
if node[field].kind == JFloat:
|
if node[field].kind == JFloat:
|
||||||
target = node[field].fnum
|
target = node[field].fnum
|
||||||
elif node[field].kind == JInt:
|
elif node[field].kind == JInt:
|
||||||
target = node[field].num.float
|
target = node[field].num.float
|
||||||
proc getField(node: PJsonNode, field: string, target: var int) =
|
proc getField(node: JsonNode, field: string, target: var int) =
|
||||||
if not node.hasKey(field):
|
if not node.hasKey(field):
|
||||||
return
|
return
|
||||||
if node[field].kind == JInt:
|
if node[field].kind == JInt:
|
||||||
target = node[field].num.int
|
target = node[field].num.int
|
||||||
elif node[field].kind == JFloat:
|
elif node[field].kind == JFloat:
|
||||||
target = node[field].fnum.int
|
target = node[field].fnum.int
|
||||||
proc getField(node: PJsonNode; field: string; target: var bool) =
|
proc getField(node: JsonNode; field: string; target: var bool) =
|
||||||
if not node.hasKey(field):
|
if not node.hasKey(field):
|
||||||
return
|
return
|
||||||
case node[field].kind
|
case node[field].kind
|
||||||
|
|
@ -431,19 +431,19 @@ proc getField(node: PJsonNode; field: string; target: var bool) =
|
||||||
target = (node[field].num != 0)
|
target = (node[field].num != 0)
|
||||||
of JFloat:
|
of JFloat:
|
||||||
target = (node[field].fnum != 0.0)
|
target = (node[field].fnum != 0.0)
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
template checkKey(node: expr; key: string): stmt =
|
template checkKey(node: untyped; key: string) =
|
||||||
if not hasKey(node, key):
|
if not hasKey(node, key):
|
||||||
return
|
return
|
||||||
|
|
||||||
proc importTrail(data: PJsonNode; errors: var seq[string]): TTrailRecord =
|
proc importTrail(data: JsonNode; errors: var seq[string]): TTrailRecord =
|
||||||
checkKey(data, "trail")
|
checkKey(data, "trail")
|
||||||
result.anim = importAnim(data["trail"], errors)
|
result.anim = importAnim(data["trail"], errors)
|
||||||
result.timer = 1000.0
|
result.timer = 1000.0
|
||||||
getField(data["trail"], "timer", result.timer)
|
getField(data["trail"], "timer", result.timer)
|
||||||
result.timer /= 1000.0
|
result.timer /= 1000.0
|
||||||
proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings =
|
proc importLevel(data: JsonNode; errors: var seq[string]): PLevelSettings =
|
||||||
new(result)
|
new(result)
|
||||||
result.size = vec2i(5000, 5000)
|
result.size = vec2i(5000, 5000)
|
||||||
result.starfield = @[]
|
result.starfield = @[]
|
||||||
|
|
@ -456,7 +456,7 @@ proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings =
|
||||||
if level.hasKey("starfield"):
|
if level.hasKey("starfield"):
|
||||||
for star in level["starfield"].items:
|
for star in level["starfield"].items:
|
||||||
result.starfield.add(newSprite(star.str, errors))
|
result.starfield.add(newSprite(star.str, errors))
|
||||||
proc importPhys(data: PJsonNode): TPhysicsRecord =
|
proc importPhys(data: JsonNode): TPhysicsRecord =
|
||||||
result.radius = 20.0
|
result.radius = 20.0
|
||||||
result.mass = 10.0
|
result.mass = 10.0
|
||||||
|
|
||||||
|
|
@ -466,7 +466,7 @@ proc importPhys(data: PJsonNode): TPhysicsRecord =
|
||||||
phys.getField("mass", result.mass)
|
phys.getField("mass", result.mass)
|
||||||
when not defined(NoChipmunk):
|
when not defined(NoChipmunk):
|
||||||
result.moment = momentForCircle(result.mass, 0.0, result.radius, VectorZero) * MomentMult
|
result.moment = momentForCircle(result.mass, 0.0, result.radius, VectorZero) * MomentMult
|
||||||
proc importHandling(data: PJsonNode): THandlingRecord =
|
proc importHandling(data: JsonNode): THandlingRecord =
|
||||||
result.thrust = 45.0
|
result.thrust = 45.0
|
||||||
result.topSpeed = 100.0 #unused
|
result.topSpeed = 100.0 #unused
|
||||||
result.reverse = 30.0
|
result.reverse = 30.0
|
||||||
|
|
@ -483,7 +483,7 @@ proc importHandling(data: PJsonNode): THandlingRecord =
|
||||||
hand.getField("reverse", result.reverse)
|
hand.getField("reverse", result.reverse)
|
||||||
hand.getField("strafe", result.strafe)
|
hand.getField("strafe", result.strafe)
|
||||||
hand.getField("rotation", result.rotation)
|
hand.getField("rotation", result.rotation)
|
||||||
proc importAnim(data: PJsonNode, errors: var seq[string]): PAnimationRecord =
|
proc importAnim(data: JsonNode, errors: var seq[string]): PAnimationRecord =
|
||||||
new(result)
|
new(result)
|
||||||
result.angle = 0.0
|
result.angle = 0.0
|
||||||
result.delay = 1000.0
|
result.delay = 1000.0
|
||||||
|
|
@ -502,26 +502,26 @@ proc importAnim(data: PJsonNode, errors: var seq[string]): PAnimationRecord =
|
||||||
|
|
||||||
result.angle = radians(result.angle) ## comes in as degrees
|
result.angle = radians(result.angle) ## comes in as degrees
|
||||||
result.delay /= 1000 ## delay comes in as milliseconds
|
result.delay /= 1000 ## delay comes in as milliseconds
|
||||||
proc importSoul(data: PJsonNode): TSoulRecord =
|
proc importSoul(data: JsonNode): TSoulRecord =
|
||||||
result.energy = 10000
|
result.energy = 10000
|
||||||
result.health = 1
|
result.health = 1
|
||||||
checkKey(data, "soul")
|
checkKey(data, "soul")
|
||||||
let soul = data["soul"]
|
let soul = data["soul"]
|
||||||
soul.getField("energy", result.energy)
|
soul.getField("energy", result.energy)
|
||||||
soul.getField("health", result.health)
|
soul.getField("health", result.health)
|
||||||
proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord =
|
proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord =
|
||||||
checkKey(data, "explode")
|
checkKey(data, "explode")
|
||||||
let expl = data["explode"]
|
let expl = data["explode"]
|
||||||
result.anim = importAnim(expl, errors)
|
result.anim = importAnim(expl, errors)
|
||||||
result.sound = importSound(expl, errors, "sound")
|
result.sound = importSound(expl, errors, "sound")
|
||||||
proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord =
|
proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord =
|
||||||
if data.kind == JObject:
|
if data.kind == JObject:
|
||||||
checkKey(data, fieldName)
|
checkKey(data, fieldName)
|
||||||
result = newSound(data[fieldName].str, errors)
|
result = newSound(data[fieldName].str, errors)
|
||||||
elif data.kind == JString:
|
elif data.kind == JString:
|
||||||
result = newSound(data.str, errors)
|
result = newSound(data.str, errors)
|
||||||
|
|
||||||
proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord =
|
proc importVeh(data: JsonNode; errors: var seq[string]): PVehicleRecord =
|
||||||
new(result)
|
new(result)
|
||||||
result.playable = false
|
result.playable = false
|
||||||
if data.kind != JArray or data.len != 2 or
|
if data.kind != JArray or data.len != 2 or
|
||||||
|
|
@ -538,7 +538,7 @@ proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord =
|
||||||
vehdata.getField("playable", result.playable)
|
vehdata.getField("playable", result.playable)
|
||||||
if result.anim.spriteSheet.isNil and result.playable:
|
if result.anim.spriteSheet.isNil and result.playable:
|
||||||
result.playable = false
|
result.playable = false
|
||||||
proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord =
|
proc importObject(data: JsonNode; errors: var seq[string]): PObjectRecord =
|
||||||
new(result)
|
new(result)
|
||||||
if data.kind != JArray or data.len != 2:
|
if data.kind != JArray or data.len != 2:
|
||||||
result.name = "(broken)"
|
result.name = "(broken)"
|
||||||
|
|
@ -546,7 +546,7 @@ proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord =
|
||||||
result.name = data[0].str
|
result.name = data[0].str
|
||||||
result.anim = importAnim(data[1], errors)
|
result.anim = importAnim(data[1], errors)
|
||||||
result.physics = importPhys(data[1])
|
result.physics = importPhys(data[1])
|
||||||
proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord =
|
proc importItem(data: JsonNode; errors: var seq[string]): PItemRecord =
|
||||||
new(result)
|
new(result)
|
||||||
if data.kind != JArray or data.len != 3:
|
if data.kind != JArray or data.len != 3:
|
||||||
result.name = "(broken)"
|
result.name = "(broken)"
|
||||||
|
|
@ -562,7 +562,7 @@ proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord =
|
||||||
|
|
||||||
result.useSound = importSound(data[2], errors, "useSound")
|
result.useSound = importSound(data[2], errors, "useSound")
|
||||||
|
|
||||||
case data[1].str.toLower
|
case data[1].str.toLowerAscii
|
||||||
of "projectile":
|
of "projectile":
|
||||||
result.kind = Projectile
|
result.kind = Projectile
|
||||||
if data[2]["bullet"].kind == JString:
|
if data[2]["bullet"].kind == JString:
|
||||||
|
|
@ -576,15 +576,15 @@ proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord =
|
||||||
of "ammo":
|
of "ammo":
|
||||||
result.kind = Ammo
|
result.kind = Ammo
|
||||||
of "utility":
|
of "utility":
|
||||||
nil
|
discard
|
||||||
else:
|
else:
|
||||||
errors.add "Invalid item type \""&data[1].str&"\" for item "&result.name
|
errors.add "Invalid item type \""&data[1].str&"\" for item "&result.name
|
||||||
|
|
||||||
proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord =
|
proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord =
|
||||||
new(result)
|
new(result)
|
||||||
result.id = -1
|
result.id = -1
|
||||||
|
|
||||||
var bdata: PJsonNode
|
var bdata: JsonNode
|
||||||
if data.kind == JArray:
|
if data.kind == JArray:
|
||||||
result.name = data[0].str
|
result.name = data[0].str
|
||||||
bdata = data[1]
|
bdata = data[1]
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ defPacketImports()
|
||||||
type
|
type
|
||||||
PacketID* = char
|
PacketID* = char
|
||||||
|
|
||||||
template idpacket(pktName, id, s2c, c2s: expr): stmt {.immediate, dirty.} =
|
template idpacket(pktName, id, s2c, c2s: untyped) {.dirty.} =
|
||||||
let `H pktName`* {.inject.} = id
|
let `H pktName`* {.inject.} = id
|
||||||
defPacket(`Sc pktName`, s2c)
|
defPacket(`Sc pktName`, s2c)
|
||||||
defPacket(`Cs pktName`, c2s)
|
defPacket(`Cs pktName`, c2s)
|
||||||
|
|
||||||
forwardPacketT(uint8, int8)
|
forwardPacketT(uint8, int8)
|
||||||
forwardPacketT(uint16, int16)
|
forwardPacketT(uint16, int16)
|
||||||
forwardPacketT(TPort, int16)
|
forwardPacketT(Port, int16)
|
||||||
|
|
||||||
idPacket(Login, 'a',
|
idPacket(Login, 'a',
|
||||||
tuple[id: int32; alias: string; sessionKey: string],
|
tuple[id: int32; alias: string; sessionKey: string],
|
||||||
|
|
@ -22,7 +22,7 @@ defPacket(CsZoneJoinReq, tuple[session: ScLogin])
|
||||||
|
|
||||||
defPacket(ScZoneRecord, tuple[
|
defPacket(ScZoneRecord, tuple[
|
||||||
name: string = "", desc: string = "",
|
name: string = "", desc: string = "",
|
||||||
ip: string = "", port: TPort = 0.Tport])
|
ip: string = "", port: Port = 0.Port])
|
||||||
idPacket(ZoneList, 'z',
|
idPacket(ZoneList, 'z',
|
||||||
tuple[network: string = "", zones: seq[ScZoneRecord]],
|
tuple[network: string = "", zones: seq[ScZoneRecord]],
|
||||||
tuple[time: string])
|
tuple[time: string])
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ else:
|
||||||
for kind, key, val in getOpt():
|
for kind, key, val in getOpt():
|
||||||
case kind
|
case kind
|
||||||
of cmdLongOption, cmdShortOption:
|
of cmdLongOption, cmdShortOption:
|
||||||
case key.tolower
|
case key.tolowerAscii
|
||||||
of "tasks", "t":
|
of "tasks", "t":
|
||||||
printTaskList = true
|
printTaskList = true
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ task "download", "download game assets":
|
||||||
if existsFile(path):
|
if existsFile(path):
|
||||||
echo "The file already exists\n",
|
echo "The file already exists\n",
|
||||||
"[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets
|
"[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets
|
||||||
case stdin.readLine.toLower
|
case stdin.readLine.toLowerAscii
|
||||||
of "r":
|
of "r":
|
||||||
removeFile path
|
removeFile path
|
||||||
of "m":
|
of "m":
|
||||||
|
|
@ -120,7 +120,7 @@ task "download", "download game assets":
|
||||||
|
|
||||||
echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n",
|
echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n",
|
||||||
"[Y]es [N]o Source: ", BinLibs
|
"[Y]es [N]o Source: ", BinLibs
|
||||||
case stdin.readline.toLower
|
case stdin.readline.toLowerAscii
|
||||||
of "y", "yes":
|
of "y", "yes":
|
||||||
discard ## o_O
|
discard ## o_O
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ type
|
||||||
type1 = typedesc
|
type1 = typedesc
|
||||||
type2 = typedesc
|
type2 = typedesc
|
||||||
|
|
||||||
proc typePairs(A, B: type1; C, D: type2) = nil
|
proc typePairs(A, B: type1; C, D: type2) = discard
|
||||||
|
|
||||||
accept typePairs(int, int, TFoo, TFOO)
|
accept typePairs(int, int, TFoo, TFOO)
|
||||||
accept typePairs(TBAR, TBar, TBAR, TBAR)
|
accept typePairs(TBAR, TBar, TBAR, TBAR)
|
||||||
|
|
@ -55,7 +55,7 @@ accept typePairs(int, int, string, string)
|
||||||
reject typePairs(TBAR, TBar, TBar, TFoo)
|
reject typePairs(TBAR, TBar, TBar, TFoo)
|
||||||
reject typePairs(string, int, TBAR, TBAR)
|
reject typePairs(string, int, TBAR, TBAR)
|
||||||
|
|
||||||
proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = nil
|
proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = discard
|
||||||
|
|
||||||
accept typePairs2(int, int, TFoo, TFOO)
|
accept typePairs2(int, int, TFoo, TFOO)
|
||||||
accept typePairs2(TBAR, TBar, TBAR, TBAR)
|
accept typePairs2(TBAR, TBar, TBAR, TBAR)
|
||||||
|
|
@ -71,12 +71,12 @@ proc dontBind(a: typedesc, b: typedesc) =
|
||||||
accept dontBind(int, float)
|
accept dontBind(int, float)
|
||||||
accept dontBind(TFoo, TFoo)
|
accept dontBind(TFoo, TFoo)
|
||||||
|
|
||||||
proc dontBind2(a, b: typedesc) = nil
|
proc dontBind2(a, b: typedesc) = discard
|
||||||
|
|
||||||
accept dontBind2(int, float)
|
accept dontBind2(int, float)
|
||||||
accept dontBind2(TBar, int)
|
accept dontBind2(TBar, int)
|
||||||
|
|
||||||
proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = nil
|
proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = discard
|
||||||
|
|
||||||
accept bindArg(int, string, 10, 20, "test", "nest")
|
accept bindArg(int, string, 10, 20, "test", "nest")
|
||||||
accept bindArg(int, int, 10, 20, 30, 40)
|
accept bindArg(int, int, 10, 20, 30, 40)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ discard """
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
|
|
||||||
var x = "hello world!".toLower.toUpper
|
var x = "hello world!".toLowerAscii.toUpperAscii
|
||||||
x.echo()
|
x.echo()
|
||||||
#OUT HELLO WORLD!
|
#OUT HELLO WORLD!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import strutils
|
||||||
proc foo(s: static[string]): string =
|
proc foo(s: static[string]): string =
|
||||||
static: echo s
|
static: echo s
|
||||||
|
|
||||||
const R = s.toUpper
|
const R = s.toUpperAscii
|
||||||
return R
|
return R
|
||||||
|
|
||||||
echo foo("test 1")
|
echo foo("test 1")
|
||||||
|
|
|
||||||
23
tests/misc/tsemfold.nim
Normal file
23
tests/misc/tsemfold.nim
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
discard """
|
||||||
|
action: run
|
||||||
|
"""
|
||||||
|
|
||||||
|
doAssertRaises(OverflowError): discard low(int8) - 1'i8
|
||||||
|
doAssertRaises(OverflowError): discard high(int8) + 1'i8
|
||||||
|
doAssertRaises(OverflowError): discard abs(low(int8))
|
||||||
|
doAssertRaises(DivByZeroError): discard 1 mod 0
|
||||||
|
doAssertRaises(DivByZeroError): discard 1 div 0
|
||||||
|
doAssertRaises(OverflowError): discard low(int8) div -1'i8
|
||||||
|
|
||||||
|
doAssertRaises(OverflowError): discard low(int64) - 1'i64
|
||||||
|
doAssertRaises(OverflowError): discard high(int64) + 1'i64
|
||||||
|
|
||||||
|
type E = enum eA, eB
|
||||||
|
doAssertRaises(OverflowError): discard eA.pred
|
||||||
|
doAssertRaises(OverflowError): discard eB.succ
|
||||||
|
|
||||||
|
doAssertRaises(OverflowError): discard low(int8) * -1
|
||||||
|
doAssertRaises(OverflowError): discard low(int64) * -1
|
||||||
|
doAssertRaises(OverflowError): discard high(int8) * 2
|
||||||
|
doAssertRaises(OverflowError): discard high(int64) * 2
|
||||||
|
|
||||||
|
|
@ -3,6 +3,7 @@ discard """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #6682
|
# bug #6682
|
||||||
|
{.experimental: "notnil".}
|
||||||
|
|
||||||
type
|
type
|
||||||
Fields = enum
|
Fields = enum
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ discard """
|
||||||
line: 22
|
line: 22
|
||||||
errormsg: "type mismatch"
|
errormsg: "type mismatch"
|
||||||
"""
|
"""
|
||||||
|
{.experimental: "notnil".}
|
||||||
type
|
type
|
||||||
PObj = ref TObj not nil
|
PObj = ref TObj not nil
|
||||||
TObj = object
|
TObj = object
|
||||||
|
|
@ -15,8 +15,8 @@ type
|
||||||
proc p(x: string not nil): int =
|
proc p(x: string not nil): int =
|
||||||
result = 45
|
result = 45
|
||||||
|
|
||||||
proc q(x: MyString) = nil
|
proc q(x: MyString) = discard
|
||||||
proc q2(x: string) = nil
|
proc q2(x: string) = discard
|
||||||
|
|
||||||
q2(nil)
|
q2(nil)
|
||||||
q(nil)
|
q(nil)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ discard """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
|
{.experimental: "notnil".}
|
||||||
|
|
||||||
type
|
type
|
||||||
TObj = object
|
TObj = object
|
||||||
|
|
@ -24,7 +24,7 @@ proc p2() =
|
||||||
p2()
|
p2()
|
||||||
|
|
||||||
proc q(x: pointer not nil) =
|
proc q(x: pointer not nil) =
|
||||||
nil
|
discard
|
||||||
|
|
||||||
proc p() =
|
proc p() =
|
||||||
var x: pointer
|
var x: pointer
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ discard """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
|
{.experimental: "notnil".}
|
||||||
|
|
||||||
type
|
type
|
||||||
TObj = object
|
TObj = object
|
||||||
x, y: int
|
x, y: int
|
||||||
|
|
||||||
proc q(x: pointer not nil) =
|
proc q(x: pointer not nil) =
|
||||||
nil
|
discard
|
||||||
|
|
||||||
proc p() =
|
proc p() =
|
||||||
var x: pointer
|
var x: pointer
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ discard """
|
||||||
|
|
||||||
# bug #584
|
# bug #584
|
||||||
# Testprogram for 'not nil' check
|
# Testprogram for 'not nil' check
|
||||||
|
{.experimental: "notnil".}
|
||||||
const testWithResult = true
|
const testWithResult = true
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ discard ""
|
||||||
type
|
type
|
||||||
TObj = ref object
|
TObj = ref object
|
||||||
|
|
||||||
|
{.experimental: "notnil".}
|
||||||
|
|
||||||
proc check(a: TObj not nil) =
|
proc check(a: TObj not nil) =
|
||||||
echo repr(a)
|
echo repr(a)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ discard """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #2216
|
# bug #2216
|
||||||
|
{.experimental: "notnil".}
|
||||||
|
|
||||||
type
|
type
|
||||||
A[T] = ref object
|
A[T] = ref object
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ discard """
|
||||||
errormsg: "fields not initialized: bar"
|
errormsg: "fields not initialized: bar"
|
||||||
line: "13"
|
line: "13"
|
||||||
"""
|
"""
|
||||||
|
{.experimental: "notnil".}
|
||||||
# bug #2355
|
# bug #2355
|
||||||
type
|
type
|
||||||
Foo = object
|
Foo = object
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ discard """
|
||||||
import strutils
|
import strutils
|
||||||
|
|
||||||
{.warning[ProveField]: on.}
|
{.warning[ProveField]: on.}
|
||||||
|
{.experimental: "notnil".}
|
||||||
type
|
type
|
||||||
TNodeKind = enum
|
TNodeKind = enum
|
||||||
nkBinary, nkTernary, nkStr
|
nkBinary, nkTernary, nkStr
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ discard """
|
||||||
type
|
type
|
||||||
PTest = ref object
|
PTest = ref object
|
||||||
|
|
||||||
proc test(x: PTest, y: int) = nil
|
proc test(x: PTest, y: int) = discard
|
||||||
|
|
||||||
var buf: PTest
|
var buf: PTest
|
||||||
buf.test()
|
buf.test()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@ discard """
|
||||||
errormsg: "redefinition of \'foo\'"
|
errormsg: "redefinition of \'foo\'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc foo(a: int, b: string) = nil
|
proc foo(a: int, b: string) = discard
|
||||||
proc foo(a: int, b: string) = nil
|
proc foo(a: int, b: string) = discard
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ type
|
||||||
TRange = range[0..40]
|
TRange = range[0..40]
|
||||||
|
|
||||||
proc p(r: TRange) =
|
proc p(r: TRange) =
|
||||||
nil
|
discard
|
||||||
|
|
||||||
var
|
var
|
||||||
r: TRange
|
r: TRange
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -30,7 +30,6 @@ else:
|
||||||
result = newString(size)
|
result = newString(size)
|
||||||
let res = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
|
let res = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
|
||||||
cstring(result), size, cstring(nil), LPBOOL(nil))
|
cstring(result), size, cstring(nil), LPBOOL(nil))
|
||||||
result[size] = chr(0)
|
|
||||||
doAssert size == res
|
doAssert size == res
|
||||||
|
|
||||||
proc testCP(wc: WideCString, lo, hi: int) =
|
proc testCP(wc: WideCString, lo, hi: int) =
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue