Merge branch 'araq-misc' into devel
This commit is contained in:
commit
2870ca5d71
122 changed files with 772 additions and 882 deletions
|
|
@ -51,5 +51,3 @@ script:
|
|||
- ./koch csource
|
||||
- ./koch nimsuggest
|
||||
# - nim c -r nimsuggest/tester
|
||||
- ( ! grep -F '.. code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html )
|
||||
- ( ! grep -F '..code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html )
|
||||
|
|
|
|||
33
changelog.md
33
changelog.md
|
|
@ -63,6 +63,10 @@
|
|||
- ``lineInfoObj`` now returns absolute path instead of project path.
|
||||
It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc.
|
||||
|
||||
- `threadpool`'s `await` and derivatives have been renamed to `blockUntil`
|
||||
to avoid confusions with `await` from the `async` macro.
|
||||
|
||||
|
||||
#### Breaking changes in the compiler
|
||||
|
||||
- The undocumented ``#? braces`` parsing mode was removed.
|
||||
|
|
@ -91,7 +95,7 @@
|
|||
- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals.
|
||||
- Added the proc ``math.prod`` for product of elements in openArray.
|
||||
- Added the proc ``parseBinInt`` to parse a binary integer from a string, which returns the value.
|
||||
- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``
|
||||
- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``.
|
||||
- Added the proc ``flush`` for memory mapped files.
|
||||
- Added the ``MemMapFileStream``.
|
||||
- Added ``macros.copyLineInfo`` to copy lineInfo from other node.
|
||||
|
|
@ -134,7 +138,13 @@
|
|||
- ``func`` is now an alias for ``proc {.noSideEffect.}``.
|
||||
- In order to make ``for`` loops and iterators more flexible to use Nim now
|
||||
supports so called "for-loop macros". See
|
||||
the `manual <manual.html#macros-for-loop-macros>`_ for more details.
|
||||
the [manual](manual.html#macros-for-loop-macros) for more details.
|
||||
This feature enables a Python-like generic ``enumerate`` implementation.
|
||||
|
||||
- Case statements can now be rewritten via macros. See the [manual](manual.html#macros-case-statement-macros) for more information.
|
||||
This feature enables custom pattern matchers.
|
||||
|
||||
|
||||
- the `typedesc` special type has been renamed to just `type`.
|
||||
- `static` and `type` are now also modifiers similar to `ref` and `ptr`.
|
||||
They denote the special types `static[T]` and `type[T]`.
|
||||
|
|
@ -155,7 +165,7 @@
|
|||
More details in language manual.
|
||||
|
||||
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
||||
these is ``"" / @[]``.
|
||||
these is ``"" / @[]``. Use ``--nilseqs:on`` for a transition period.
|
||||
|
||||
- Accessing the binary zero terminator in Nim's native strings
|
||||
is now invalid. Internally a Nim string still has the trailing zero for
|
||||
|
|
@ -167,9 +177,20 @@
|
|||
- Thread-local variables can now be declared inside procs. This implies all
|
||||
the effects of the ``global`` pragma.
|
||||
|
||||
- Nim now supports ``except`` clause in the export statement.
|
||||
- Nim now supports the ``except`` clause in the export statement.
|
||||
|
||||
- Range float types, example ``range[0.0 .. Inf]``. More details in language manual.
|
||||
- The ``{.this.}`` pragma has been deprecated. It never worked within generics and
|
||||
we found the resulting code harder to read than the more explicit ``obj.field``
|
||||
syntax.
|
||||
- "Memory regions" for pointer types have been deprecated, they were hardly used
|
||||
anywhere. Note that this has **nothing** to do with the ``--gc:regions`` switch
|
||||
of managing memory.
|
||||
|
||||
- The exception hierarchy was slightly reworked, ``SystemError`` was renamed to
|
||||
``CatchableError`` and is the new base class for any exception that is guaranteed to
|
||||
be catchable. This change should have minimal impact on most existing Nim code.
|
||||
|
||||
|
||||
### Tool changes
|
||||
|
||||
|
|
@ -178,7 +199,7 @@
|
|||
|
||||
### Compiler changes
|
||||
|
||||
- The VM's instruction count limit was raised to 1 billion instructions in
|
||||
- The VM's instruction count limit was raised to 3 million instructions in
|
||||
order to support more complex computations at compile-time.
|
||||
|
||||
- Support for hot code reloading has been implemented for the JavaScript
|
||||
|
|
@ -204,6 +225,6 @@
|
|||
- macros.bindSym now capable to accepts not only literal string or string constant expression.
|
||||
bindSym enhancement make it also can accepts computed string or ident node inside macros /
|
||||
compile time functions / static blocks. Only in templates / regular code it retains it's old behavior.
|
||||
This new feature can be accessed via {.experimental: "dynamicBindSym".} pragma/switch
|
||||
This new feature can be accessed via {.experimental: "dynamicBindSym".} pragma/switch.
|
||||
|
||||
### Bugfixes
|
||||
|
|
|
|||
|
|
@ -971,8 +971,8 @@ const
|
|||
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
||||
ConstantDataTypes*: TTypeKinds = {tyArray, tySet,
|
||||
tyTuple, tySequence}
|
||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
|
||||
tyProc, tyString, tyError}
|
||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr,
|
||||
tyProc, tyError}
|
||||
ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
|
||||
skIterator,
|
||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||
|
|
@ -1150,7 +1150,10 @@ proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
|||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc discardSons*(father: PNode) =
|
||||
father.sons = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
father.sons = @[]
|
||||
else:
|
||||
father.sons = nil
|
||||
|
||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||
n.info = info
|
||||
|
|
@ -1367,7 +1370,7 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo;
|
|||
result.loc = s.loc
|
||||
result.annex = s.annex
|
||||
# XXX once usedGenerics is used, ensure module aliases keep working!
|
||||
assert s.usedGenerics == nil
|
||||
assert s.usedGenerics.len == 0
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
|
|
@ -1592,7 +1595,10 @@ proc getStr*(a: PNode): string =
|
|||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
of nkNilLit:
|
||||
# let's hope this fixes more problems than it creates:
|
||||
result = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
result = ""
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
doAssert false, "getStr"
|
||||
#internalError(a.info, "getStr")
|
||||
|
|
|
|||
|
|
@ -431,7 +431,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
# don't call '$' here for efficiency:
|
||||
let pat = ri.sons[0].sym.loc.r.data
|
||||
internalAssert p.config, pat != nil
|
||||
internalAssert p.config, pat.len > 0
|
||||
if pat.contains({'#', '(', '@', '\''}):
|
||||
var pl = genPatternCall(p, ri, pat, typ)
|
||||
# simpler version of 'fixupCall' that works with the pl+params combination:
|
||||
|
|
@ -480,7 +480,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
|||
|
||||
# don't call '$' here for efficiency:
|
||||
let pat = ri.sons[0].sym.loc.r.data
|
||||
internalAssert p.config, pat != nil
|
||||
internalAssert p.config, pat.len > 0
|
||||
var start = 3
|
||||
if ' ' in pat:
|
||||
start = 1
|
||||
|
|
|
|||
|
|
@ -65,9 +65,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
|||
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)
|
||||
if n.strVal.len == 0 and optNilSeqs notin p.options:
|
||||
result = genNilStringLiteral(p.module, n.info)
|
||||
else:
|
||||
result = genStringLiteral(p.module, n)
|
||||
else:
|
||||
if n.strVal.isNil: result = rope("NIM_NIL")
|
||||
else: result = makeCString(n.strVal)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
|
|||
|
||||
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
|
||||
if compilationCachePresent(conf):
|
||||
result = rope(nil)
|
||||
result = rope("")
|
||||
add(result, "\n/*\t")
|
||||
add(result, CProcSectionNames[ps])
|
||||
add(result, ":*/\n")
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
|||
of "implicitstatic": result = contains(conf.options, optImplicitStatic)
|
||||
of "patterns": result = contains(conf.options, optPatterns)
|
||||
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
|
||||
of "nilseqs": result = contains(conf.options, optNilSeqs)
|
||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
|
||||
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
|
||||
|
|
@ -496,6 +497,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
|||
else:
|
||||
localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
||||
of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
|
||||
of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info)
|
||||
of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
|
||||
of "floatchecks":
|
||||
processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
|
||||
|
|
|
|||
|
|
@ -74,3 +74,5 @@ proc initDefines*(symbols: StringTableRef) =
|
|||
defineSymbol("nimVmExportFixed")
|
||||
defineSymbol("nimIncrSeqV3")
|
||||
defineSymbol("nimAshr")
|
||||
defineSymbol("nimNoNilSeqs")
|
||||
defineSymbol("nimNoNilSeqs2")
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
|
|||
proc genComment(d: PDoc, n: PNode): string =
|
||||
result = ""
|
||||
var dummyHasToc: bool
|
||||
if n.comment != nil:
|
||||
if n.comment.len > 0:
|
||||
renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
|
||||
toLinenumber(n.info), toColumn(n.info),
|
||||
dummyHasToc, d.options, d.conf), result)
|
||||
|
|
@ -205,7 +205,8 @@ proc genRecComment(d: PDoc, n: PNode): Rope =
|
|||
result = genRecComment(d, n.sons[i])
|
||||
if result != nil: return
|
||||
else:
|
||||
n.comment = nil
|
||||
when defined(nimNoNilSeqs): n.comment = ""
|
||||
else: n.comment = nil
|
||||
|
||||
proc getPlainDocstring(n: PNode): string =
|
||||
## Gets the plain text docstring of a node non destructively.
|
||||
|
|
@ -215,7 +216,7 @@ proc getPlainDocstring(n: PNode): string =
|
|||
## the concatenated ``##`` comments of the node.
|
||||
result = ""
|
||||
if n == nil: return
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
if startsWith(n.comment, "##"):
|
||||
result = n.comment
|
||||
if result.len < 1:
|
||||
for i in countup(0, safeLen(n)-1):
|
||||
|
|
@ -564,9 +565,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
|||
|
||||
result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||
"col": %n.info.col}
|
||||
if comm != nil and comm != "":
|
||||
if comm.len > 0:
|
||||
result["description"] = %comm
|
||||
if r.buf != nil:
|
||||
if r.buf.len > 0:
|
||||
result["code"] = %r.buf
|
||||
|
||||
proc checkForFalse(n: PNode): bool =
|
||||
|
|
@ -634,7 +635,7 @@ proc add(d: PDoc; j: JsonNode) =
|
|||
proc generateJson*(d: PDoc, n: PNode) =
|
||||
case n.kind
|
||||
of nkCommentStmt:
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
if startsWith(n.comment, "##"):
|
||||
let stripped = n.comment.substr(2).strip
|
||||
d.add %{ "comment": %stripped, "line": %n.info.line.int,
|
||||
"col": %n.info.col }
|
||||
|
|
@ -678,7 +679,7 @@ proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
|
|||
proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
|
||||
case n.kind
|
||||
of nkCommentStmt:
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
if startsWith(n.comment, "##"):
|
||||
let stripped = n.comment.substr(2).strip
|
||||
r.add stripped
|
||||
of nkProcDef:
|
||||
|
|
|
|||
|
|
@ -30,14 +30,7 @@ type
|
|||
wordCounter: int
|
||||
idAnon*, idDelegator*, emptyIdent*: PIdent
|
||||
|
||||
when false:
|
||||
var
|
||||
legacy: IdentCache
|
||||
|
||||
proc resetIdentCache*() =
|
||||
when false:
|
||||
for i in low(legacy.buckets)..high(legacy.buckets):
|
||||
legacy.buckets[i] = nil
|
||||
proc resetIdentCache*() = discard
|
||||
|
||||
proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
|
||||
if a[0] != b[0]: return 1
|
||||
|
|
@ -73,11 +66,9 @@ proc cmpExact(a, b: cstring, blen: int): int =
|
|||
if result == 0:
|
||||
if a[i] != '\0': result = 1
|
||||
|
||||
{.this: self.}
|
||||
|
||||
proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
|
||||
var idx = h and high(buckets)
|
||||
result = buckets[idx]
|
||||
proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
|
||||
var idx = h and high(ic.buckets)
|
||||
result = ic.buckets[idx]
|
||||
var last: PIdent = nil
|
||||
var id = 0
|
||||
while result != nil:
|
||||
|
|
@ -85,8 +76,8 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId
|
|||
if last != nil:
|
||||
# make access to last looked up identifier faster:
|
||||
last.next = result.next
|
||||
result.next = buckets[idx]
|
||||
buckets[idx] = result
|
||||
result.next = ic.buckets[idx]
|
||||
ic.buckets[idx] = result
|
||||
return
|
||||
elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
|
||||
assert((id == 0) or (id == result.id))
|
||||
|
|
@ -97,20 +88,20 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId
|
|||
result.h = h
|
||||
result.s = newString(length)
|
||||
for i in countup(0, length - 1): result.s[i] = identifier[i]
|
||||
result.next = buckets[idx]
|
||||
buckets[idx] = result
|
||||
result.next = ic.buckets[idx]
|
||||
ic.buckets[idx] = result
|
||||
if id == 0:
|
||||
inc(wordCounter)
|
||||
result.id = -wordCounter
|
||||
inc(ic.wordCounter)
|
||||
result.id = -ic.wordCounter
|
||||
else:
|
||||
result.id = id
|
||||
|
||||
proc getIdent*(self: IdentCache; identifier: string): PIdent =
|
||||
result = getIdent(cstring(identifier), len(identifier),
|
||||
proc getIdent*(ic: IdentCache; identifier: string): PIdent =
|
||||
result = getIdent(ic, cstring(identifier), len(identifier),
|
||||
hashIgnoreStyle(identifier))
|
||||
|
||||
proc getIdent*(self: IdentCache; identifier: string, h: Hash): PIdent =
|
||||
result = getIdent(cstring(identifier), len(identifier), h)
|
||||
proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent =
|
||||
result = getIdent(ic, cstring(identifier), len(identifier), h)
|
||||
|
||||
proc newIdentCache*(): IdentCache =
|
||||
result = IdentCache()
|
||||
|
|
|
|||
|
|
@ -1267,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
|
||||
if sfInfixCall in f.flags:
|
||||
let pat = n.sons[0].sym.loc.r.data
|
||||
internalAssert p.config, pat != nil
|
||||
internalAssert p.config, pat.len > 0
|
||||
if pat.contains({'#', '(', '@'}):
|
||||
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
|
|
@ -1350,7 +1350,7 @@ proc arrayTypeForElemType(typ: PType): string =
|
|||
of tyUint8: "Uint8Array"
|
||||
of tyFloat32: "Float32Array"
|
||||
of tyFloat64, tyFloat: "Float64Array"
|
||||
else: nil
|
||||
else: ""
|
||||
|
||||
proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
var t = skipTypes(typ, abstractInst)
|
||||
|
|
|
|||
|
|
@ -164,13 +164,13 @@ type
|
|||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {}
|
||||
result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
|
||||
result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintGlobalVar, hintGCStats}
|
||||
result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
|
||||
hintProcessing, hintPattern, hintExecuting, hintLinking}
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {}
|
||||
result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
|
||||
result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintGlobalVar, hintGCStats}
|
||||
result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
|
||||
hintProcessing, hintPattern, hintExecuting, hintLinking}
|
||||
|
||||
const
|
||||
NotesVerbosity* = computeNotesVerbosity()
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
|
|||
err.add "\nThis might be caused by a recursive module dependency: "
|
||||
err.add c.recursiveDep
|
||||
# prevent excessive errors for 'nim check'
|
||||
c.recursiveDep = nil
|
||||
c.recursiveDep = ""
|
||||
localError(c.config, info, errGenerated, err)
|
||||
|
||||
proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
|
|
|
|||
|
|
@ -65,10 +65,8 @@ type
|
|||
|
||||
proc hash*(x: FileIndex): Hash {.borrow.}
|
||||
|
||||
{.this: g.}
|
||||
|
||||
proc stopCompile*(g: ModuleGraph): bool {.inline.} =
|
||||
result = doStopCompile != nil and doStopCompile()
|
||||
result = g.doStopCompile != nil and g.doStopCompile()
|
||||
|
||||
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo(), {})
|
||||
|
|
@ -98,44 +96,44 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
|||
result.cacheTables = initTable[string, BTree[string, PNode]]()
|
||||
|
||||
proc resetAllModules*(g: ModuleGraph) =
|
||||
initStrTable(packageSyms)
|
||||
deps = initIntSet()
|
||||
modules = @[]
|
||||
importStack = @[]
|
||||
inclToMod = initTable[FileIndex, FileIndex]()
|
||||
usageSym = nil
|
||||
owners = @[]
|
||||
methods = @[]
|
||||
initStrTable(compilerprocs)
|
||||
initStrTable(exposed)
|
||||
initStrTable(g.packageSyms)
|
||||
g.deps = initIntSet()
|
||||
g.modules = @[]
|
||||
g.importStack = @[]
|
||||
g.inclToMod = initTable[FileIndex, FileIndex]()
|
||||
g.usageSym = nil
|
||||
g.owners = @[]
|
||||
g.methods = @[]
|
||||
initStrTable(g.compilerprocs)
|
||||
initStrTable(g.exposed)
|
||||
|
||||
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:
|
||||
result = modules[fileIdx.int32]
|
||||
if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len:
|
||||
result = g.modules[fileIdx.int32]
|
||||
|
||||
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
|
||||
|
||||
proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
|
||||
assert m.position == m.info.fileIndex.int32
|
||||
addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false)
|
||||
if suggestMode:
|
||||
deps.incl m.position.dependsOn(dep.int)
|
||||
if g.suggestMode:
|
||||
g.deps.incl m.position.dependsOn(dep.int)
|
||||
# we compute the transitive closure later when quering the graph lazily.
|
||||
# this improves efficiency quite a lot:
|
||||
#invalidTransitiveClosure = true
|
||||
|
||||
proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
|
||||
addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true)
|
||||
discard hasKeyOrPut(inclToMod, includeFile, module)
|
||||
discard hasKeyOrPut(g.inclToMod, includeFile, module)
|
||||
|
||||
proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =
|
||||
## returns 'fileIdx' if the file belonging to this index is
|
||||
## directly used as a module or else the module that first
|
||||
## references this include file.
|
||||
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil:
|
||||
if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len and g.modules[fileIdx.int32] != nil:
|
||||
result = fileIdx
|
||||
else:
|
||||
result = inclToMod.getOrDefault(fileIdx)
|
||||
result = g.inclToMod.getOrDefault(fileIdx)
|
||||
|
||||
proc transitiveClosure(g: var IntSet; n: int) =
|
||||
# warshall's algorithm
|
||||
|
|
@ -147,22 +145,22 @@ proc transitiveClosure(g: var IntSet; n: int) =
|
|||
g.incl i.dependsOn(j)
|
||||
|
||||
proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
let m = getModule fileIdx
|
||||
let m = g.getModule fileIdx
|
||||
if m != nil: incl m.flags, sfDirty
|
||||
|
||||
proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
# we need to mark its dependent modules D as dirty right away because after
|
||||
# nimsuggest is done with this module, the module's dirty flag will be
|
||||
# cleared but D still needs to be remembered as 'dirty'.
|
||||
if invalidTransitiveClosure:
|
||||
invalidTransitiveClosure = false
|
||||
transitiveClosure(deps, modules.len)
|
||||
if g.invalidTransitiveClosure:
|
||||
g.invalidTransitiveClosure = false
|
||||
transitiveClosure(g.deps, g.modules.len)
|
||||
|
||||
# every module that *depends* on this file is also dirty:
|
||||
for i in 0i32..<modules.len.int32:
|
||||
let m = modules[i]
|
||||
if m != nil and deps.contains(i.dependsOn(fileIdx.int)):
|
||||
for i in 0i32..<g.modules.len.int32:
|
||||
let m = g.modules[i]
|
||||
if m != nil and g.deps.contains(i.dependsOn(fileIdx.int)):
|
||||
incl m.flags, sfDirty
|
||||
|
||||
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
||||
result = suggestMode and sfDirty in m.flags
|
||||
result = g.suggestMode and sfDirty in m.flags
|
||||
|
|
|
|||
|
|
@ -391,10 +391,10 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
|
|||
|
||||
if conf.structuredErrorHook != nil:
|
||||
conf.structuredErrorHook(conf, unknownLineInfo(),
|
||||
s & (if kind != nil: KindFormat % kind else: ""), sev)
|
||||
s & (if kind.len > 0: KindFormat % kind else: ""), sev)
|
||||
|
||||
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||
if kind != nil:
|
||||
if kind.len > 0:
|
||||
styledMsgWriteln(color, title, resetStyle, s,
|
||||
KindColor, `%`(KindFormat, kind))
|
||||
else:
|
||||
|
|
@ -483,9 +483,9 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
|||
|
||||
if not ignoreMsg:
|
||||
if conf.structuredErrorHook != nil:
|
||||
conf.structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev)
|
||||
conf.structuredErrorHook(conf, info, s & (if kind.len > 0: KindFormat % kind else: ""), sev)
|
||||
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||
if kind != nil:
|
||||
if kind.len > 0:
|
||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
|
||||
KindColor, `%`(KindFormat, kind))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ type # please make sure we have under 32 options
|
|||
optPatterns, # en/disable pattern matching
|
||||
optMemTracker,
|
||||
optHotCodeReloading,
|
||||
optLaxStrings
|
||||
optLaxStrings,
|
||||
optNilSeqs
|
||||
|
||||
TOptions* = set[TOption]
|
||||
TGlobalOption* = enum # **keep binary compatible**
|
||||
|
|
@ -110,14 +111,16 @@ type
|
|||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg
|
||||
|
||||
Feature* = enum ## experimental features
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
implicitDeref,
|
||||
dotOperators,
|
||||
callOperator,
|
||||
parallel,
|
||||
destructor,
|
||||
notnil,
|
||||
dynamicBindSym
|
||||
dynamicBindSym,
|
||||
forLoopMacros,
|
||||
caseStmtMacros
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||
|
|
@ -482,7 +485,7 @@ include packagehandling
|
|||
|
||||
proc getOsCacheDir(): string =
|
||||
when defined(posix):
|
||||
result = string getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache")
|
||||
result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim"
|
||||
else:
|
||||
result = getHomeDir() / genSubDir
|
||||
|
||||
|
|
@ -600,18 +603,22 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
|
|||
proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
|
||||
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
|
||||
var candidates: seq[string] = @[]
|
||||
for k, f in os.walkDir(pkg, relative=true):
|
||||
if k == pcFile and f != "config.nims":
|
||||
let (_, name, ext) = splitFile(f)
|
||||
if ext in extensions:
|
||||
let x = changeFileExt(pkg / name, ".nim")
|
||||
if fileExists(x):
|
||||
candidates.add x
|
||||
for c in candidates:
|
||||
# nim-foo foo or foo nfoo
|
||||
if (pkg in c) or (c in pkg): return c
|
||||
if candidates.len >= 1:
|
||||
return candidates[0]
|
||||
var dir = pkg
|
||||
while true:
|
||||
for k, f in os.walkDir(dir, relative=true):
|
||||
if k == pcFile and f != "config.nims":
|
||||
let (_, name, ext) = splitFile(f)
|
||||
if ext in extensions:
|
||||
let x = changeFileExt(dir / name, ".nim")
|
||||
if fileExists(x):
|
||||
candidates.add x
|
||||
for c in candidates:
|
||||
# nim-foo foo or foo nfoo
|
||||
if (pkg in c) or (c in pkg): return c
|
||||
if candidates.len >= 1:
|
||||
return candidates[0]
|
||||
dir = parentDir(dir)
|
||||
if dir == "": break
|
||||
return ""
|
||||
|
||||
proc canonDynlibName(s: string): string =
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0
|
|||
proc rawSkipComment(p: var TParser, node: PNode) =
|
||||
if p.tok.tokType == tkComment:
|
||||
if node != nil:
|
||||
if node.comment == nil: node.comment = ""
|
||||
when not defined(nimNoNilSeqs):
|
||||
if node.comment == nil: node.comment = ""
|
||||
when defined(nimpretty):
|
||||
if p.tok.commentOffsetB > p.tok.commentOffsetA:
|
||||
add node.comment, fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)
|
||||
|
|
|
|||
|
|
@ -21,14 +21,17 @@ type
|
|||
formals: int
|
||||
c: PContext
|
||||
subMatch: bool # subnode matches are special
|
||||
mappingIsFull: bool
|
||||
PPatternContext = var TPatternContext
|
||||
|
||||
proc getLazy(c: PPatternContext, sym: PSym): PNode =
|
||||
if not isNil(c.mapping):
|
||||
if c.mappingIsFull:
|
||||
result = c.mapping[sym.position]
|
||||
|
||||
proc putLazy(c: PPatternContext, sym: PSym, n: PNode) =
|
||||
if isNil(c.mapping): newSeq(c.mapping, c.formals)
|
||||
if not c.mappingIsFull:
|
||||
newSeq(c.mapping, c.formals)
|
||||
c.mappingIsFull = true
|
||||
c.mapping[sym.position] = n
|
||||
|
||||
proc matches(c: PPatternContext, p, n: PNode): bool
|
||||
|
|
@ -209,7 +212,11 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
|
|||
for j in 0 ..< p.len:
|
||||
if not matches(c, p.sons[j], n.sons[i+j]):
|
||||
# we need to undo any bindings:
|
||||
if not isNil(c.mapping): c.mapping = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
c.mapping = @[]
|
||||
c.mappingIsFull = false
|
||||
else:
|
||||
if not isNil(c.mapping): c.mapping = nil
|
||||
return false
|
||||
result = true
|
||||
|
||||
|
|
|
|||
|
|
@ -1066,8 +1066,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
|||
of wThis:
|
||||
if it.kind in nkPragmaCallKinds and it.len == 2:
|
||||
c.selfName = considerQuotedIdent(c, it[1])
|
||||
message(c.config, n.info, warnDeprecated, "the '.this' pragma")
|
||||
elif it.kind == nkIdent or it.len == 1:
|
||||
c.selfName = getIdent(c.cache, "self")
|
||||
message(c.config, n.info, warnDeprecated, "the '.this' pragma")
|
||||
else:
|
||||
localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
|
||||
of wNoRewrite:
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ const
|
|||
|
||||
proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
|
||||
result = false
|
||||
if n.comment != nil:
|
||||
if n.comment.len > 0:
|
||||
result = (renderNoComments notin g.flags) or
|
||||
(renderDocComments in g.flags)
|
||||
|
||||
|
|
@ -402,7 +402,7 @@ proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
|||
proc lsub(g: TSrcGen; n: PNode): int =
|
||||
# computes the length of a tree
|
||||
if isNil(n): return 0
|
||||
if n.comment != nil: return MaxLineLen + 1
|
||||
if n.comment.len > 0: return MaxLineLen + 1
|
||||
case n.kind
|
||||
of nkEmpty: result = 0
|
||||
of nkTripleStrLit:
|
||||
|
|
@ -500,7 +500,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
|||
of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_")
|
||||
of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_")
|
||||
of nkPragma: result = lcomma(g, n) + 4
|
||||
of nkCommentStmt: result = if n.comment.isNil: 0 else: len(n.comment)
|
||||
of nkCommentStmt: result = len(n.comment)
|
||||
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
|
||||
of nkImportAs: result = lsub(g, n.sons[0]) + len("_as_") + lsub(g, n.sons[1])
|
||||
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
|
||||
|
|
@ -539,7 +539,7 @@ proc gsub(g: var TSrcGen, n: PNode) =
|
|||
proc hasCom(n: PNode): bool =
|
||||
result = false
|
||||
if n.isNil: return false
|
||||
if n.comment != nil: return true
|
||||
if n.comment.len > 0: return true
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: discard
|
||||
else:
|
||||
|
|
@ -602,7 +602,7 @@ proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
|
|||
dedent(g)
|
||||
|
||||
proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
|
||||
result = n.comment != nil
|
||||
result = n.comment.len > 0
|
||||
if not result:
|
||||
# check further
|
||||
for i in countup(start, sonsLen(n) + theEnd):
|
||||
|
|
@ -637,7 +637,7 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
|
|||
proc gcond(g: var TSrcGen, n: PNode) =
|
||||
if n.kind == nkStmtListExpr:
|
||||
put(g, tkParLe, "(")
|
||||
gsub(g, n)
|
||||
gsub(g, n)
|
||||
if n.kind == nkStmtListExpr:
|
||||
put(g, tkParRi, ")")
|
||||
|
||||
|
|
@ -864,7 +864,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
if isNil(n): return
|
||||
var
|
||||
a: TContext
|
||||
if n.comment != nil: pushCom(g, n)
|
||||
if n.comment.len > 0: pushCom(g, n)
|
||||
case n.kind # atoms:
|
||||
of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
|
||||
of nkEmpty: discard
|
||||
|
|
@ -1079,7 +1079,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
|
||||
else: nil
|
||||
var n_next = n[1]
|
||||
while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref,
|
||||
while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref,
|
||||
nkStringToCString, nkCStringToString} and n_next.len > 0:
|
||||
n_next = n_next[0]
|
||||
if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
||||
|
|
|
|||
|
|
@ -66,29 +66,19 @@ type
|
|||
Rope* = ref RopeObj
|
||||
RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
|
||||
# by nil to safe space
|
||||
left*, right*: Rope
|
||||
length*: int
|
||||
data*: string # != nil if a leaf
|
||||
left, right: Rope
|
||||
L: int # <= 0 if a leaf
|
||||
data*: string
|
||||
|
||||
proc len*(a: Rope): int =
|
||||
## the rope's length
|
||||
if a == nil: result = 0
|
||||
else: result = a.length
|
||||
else: result = abs a.L
|
||||
|
||||
proc newRope(data: string = nil): Rope =
|
||||
proc newRope(data: string = ""): Rope =
|
||||
new(result)
|
||||
if data != nil:
|
||||
result.length = len(data)
|
||||
result.data = data
|
||||
|
||||
proc newMutableRope*(capacity = 30): Rope =
|
||||
## creates a new rope that supports direct modifications of the rope's
|
||||
## 'data' and 'length' fields.
|
||||
new(result)
|
||||
result.data = newStringOfCap(capacity)
|
||||
|
||||
proc freezeMutableRope*(r: Rope) {.inline.} =
|
||||
r.length = r.data.len
|
||||
result.L = -len(data)
|
||||
result.data = data
|
||||
|
||||
var
|
||||
cache: array[0..2048*2 - 1, Rope] # XXX Global here!
|
||||
|
|
@ -147,7 +137,7 @@ proc `&`*(a, b: Rope): Rope =
|
|||
result = a
|
||||
else:
|
||||
result = newRope()
|
||||
result.length = a.length + b.length
|
||||
result.L = abs(a.L) + abs(b.L)
|
||||
result.left = a
|
||||
result.right = b
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
|||
template cbos(name, body) {.dirty.} =
|
||||
result.registerCallback "stdlib.system." & astToStr(name),
|
||||
proc (a: VmArgs) =
|
||||
errorMsg = nil
|
||||
errorMsg = ""
|
||||
try:
|
||||
body
|
||||
except OSError:
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ proc commonType*(x, y: PType): PType =
|
|||
elif b.kind == tyStmt: result = b
|
||||
elif a.kind == tyTypeDesc:
|
||||
# turn any concrete typedesc into the abstract typedesc type
|
||||
if a.sons == nil: result = a
|
||||
if a.len == 0: result = a
|
||||
else:
|
||||
result = newType(tyTypeDesc, a.owner)
|
||||
rawAddSon(result, newType(tyNone, a.owner))
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
continue
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
|
||||
if c.currentScope.symbols.counter == counterInitial or syms != nil:
|
||||
if c.currentScope.symbols.counter == counterInitial or syms.len != 0:
|
||||
matches(c, n, orig, z)
|
||||
if z.state == csMatch:
|
||||
#if sym.name.s == "==" and (n.info ?? "temp3"):
|
||||
|
|
@ -237,7 +237,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
|||
if symx.kind in routineKinds:
|
||||
errors.add(CandidateError(sym: symx,
|
||||
unmatchedVarParam: 0, firstMismatch: 0,
|
||||
diagnostics: nil,
|
||||
diagnostics: @[],
|
||||
enabled: false))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if errors.len == 0:
|
||||
|
|
@ -455,7 +455,7 @@ proc tryDeref(n: PNode): PNode =
|
|||
|
||||
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds, flags: TExprFlags): PNode =
|
||||
var errors: CandidateErrors = if efExplain in flags: @[] else: nil
|
||||
var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
|
||||
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
|
||||
if r.state == csMatch:
|
||||
# this may be triggered, when the explain pragma is used
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ type
|
|||
# in standalone ``except`` and ``finally``
|
||||
next*: PProcCon # used for stacking procedure contexts
|
||||
wasForwarded*: bool # whether the current proc has a separate header
|
||||
mappingExists*: bool
|
||||
mapping*: TIdTable
|
||||
|
||||
TMatchedConcept* = object
|
||||
|
|
@ -176,12 +177,14 @@ proc lastOptionEntry*(c: PContext): POptionEntry =
|
|||
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
||||
|
||||
proc put*(p: PProcCon; key, val: PSym) =
|
||||
if p.mapping.data == nil: initIdTable(p.mapping)
|
||||
if not p.mappingExists:
|
||||
initIdTable(p.mapping)
|
||||
p.mappingExists = true
|
||||
#echo "put into table ", key.info
|
||||
p.mapping.idTablePut(key, val)
|
||||
|
||||
proc get*(p: PProcCon; key: PSym): PSym =
|
||||
if p.mapping.data == nil: return nil
|
||||
if not p.mappingExists: return nil
|
||||
result = PSym(p.mapping.idTableGet(key))
|
||||
|
||||
proc getGenSym*(c: PContext; s: PSym): PSym =
|
||||
|
|
|
|||
|
|
@ -97,10 +97,9 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
|||
|
||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||
id: CompilesId): PSym =
|
||||
if genericSym.procInstCache != nil:
|
||||
for inst in genericSym.procInstCache:
|
||||
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
||||
return inst.sym
|
||||
for inst in genericSym.procInstCache:
|
||||
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
||||
return inst.sym
|
||||
|
||||
when false:
|
||||
proc `$`(x: PSym): string =
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
|
|||
else:
|
||||
globalError(conf, n.info, "string literal must be of some string type")
|
||||
of nkNilLit:
|
||||
if x.kind in NilableTypes:
|
||||
if x.kind in NilableTypes+{tyString, tySequence}:
|
||||
n.typ = t
|
||||
else:
|
||||
globalError(conf, n.info, "nil literal must be of some pointer type")
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
|
|||
if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}:
|
||||
let assignment = locateFieldInInitExpr(c, r.sym, initExpr)
|
||||
if assignment == nil:
|
||||
if result == nil:
|
||||
if result.len == 0:
|
||||
result = r.sym.name.s
|
||||
else:
|
||||
result.add ", "
|
||||
|
|
@ -129,7 +129,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
|
|||
|
||||
proc checkForMissingFields(c: PContext, recList, initExpr: PNode) =
|
||||
let missing = missingMandatoryFields(c, recList, initExpr)
|
||||
if missing != nil:
|
||||
if missing.len > 0:
|
||||
localError(c.config, initExpr.info, "fields not initialized: $1.", [missing])
|
||||
|
||||
proc semConstructFields(c: PContext, recNode: PNode,
|
||||
|
|
|
|||
|
|
@ -178,71 +178,6 @@ proc semIf(c: PContext, n: PNode): PNode =
|
|||
result.kind = nkIfExpr
|
||||
result.typ = typ
|
||||
|
||||
proc semCase(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkMinSonsLen(n, 2, c.config)
|
||||
openScope(c)
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
var chckCovered = false
|
||||
var covered: BiggestInt = 0
|
||||
var typ = commonTypeBegin
|
||||
var hasElse = false
|
||||
let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc})
|
||||
case caseTyp.kind
|
||||
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
||||
chckCovered = true
|
||||
of tyFloat..tyFloat128, tyString, tyError:
|
||||
discard
|
||||
else:
|
||||
localError(c.config, n.info, errSelectorMustBeOfCertainTypes)
|
||||
return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var x = n.sons[i]
|
||||
when defined(nimsuggest):
|
||||
if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum:
|
||||
suggestEnum(c, x, caseTyp)
|
||||
case x.kind
|
||||
of nkOfBranch:
|
||||
checkMinSonsLen(x, 2, c.config)
|
||||
semCaseBranch(c, n, x, i, covered)
|
||||
var last = sonsLen(x)-1
|
||||
x.sons[last] = semExprBranchScope(c, x.sons[last])
|
||||
typ = commonType(typ, x.sons[last])
|
||||
of nkElifBranch:
|
||||
chckCovered = false
|
||||
checkSonsLen(x, 2, c.config)
|
||||
openScope(c)
|
||||
x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
|
||||
x.sons[1] = semExprBranch(c, x.sons[1])
|
||||
typ = commonType(typ, x.sons[1])
|
||||
closeScope(c)
|
||||
of nkElse:
|
||||
chckCovered = false
|
||||
checkSonsLen(x, 1, c.config)
|
||||
x.sons[0] = semExprBranchScope(c, x.sons[0])
|
||||
typ = commonType(typ, x.sons[0])
|
||||
hasElse = true
|
||||
else:
|
||||
illFormedAst(x, c.config)
|
||||
if chckCovered:
|
||||
if covered == toCover(c, n.sons[0].typ):
|
||||
hasElse = true
|
||||
else:
|
||||
localError(c.config, n.info, "not all cases are covered")
|
||||
closeScope(c)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
||||
# propagate any enforced VoidContext:
|
||||
if typ == c.enforceVoidContext:
|
||||
result.typ = c.enforceVoidContext
|
||||
else:
|
||||
for i in 1..n.len-1:
|
||||
var it = n.sons[i]
|
||||
let j = it.len-1
|
||||
if not endsInNoReturn(it.sons[j]):
|
||||
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
|
||||
result.typ = typ
|
||||
|
||||
proc semTry(c: PContext, n: PNode): PNode =
|
||||
|
||||
var check = initIntSet()
|
||||
|
|
@ -683,29 +618,28 @@ proc isTrivalStmtExpr(n: PNode): bool =
|
|||
return false
|
||||
result = true
|
||||
|
||||
proc handleForLoopMacro(c: PContext; n: PNode): PNode =
|
||||
let iterExpr = n[^2]
|
||||
if iterExpr.kind in nkCallKinds:
|
||||
proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string): PNode =
|
||||
if selector.kind in nkCallKinds:
|
||||
# we transform
|
||||
# n := for a, b, c in m(x, y, z): Y
|
||||
# to
|
||||
# m(n)
|
||||
let forLoopStmt = magicsys.getCompilerProc(c.graph, "ForLoopStmt")
|
||||
if forLoopStmt == nil: return
|
||||
let maType = magicsys.getCompilerProc(c.graph, magicType)
|
||||
if maType == nil: return
|
||||
|
||||
let headSymbol = iterExpr[0]
|
||||
let headSymbol = selector[0]
|
||||
var o: TOverloadIter
|
||||
var match: PSym = nil
|
||||
var symx = initOverloadIter(o, c, headSymbol)
|
||||
while symx != nil:
|
||||
if symx.kind in {skTemplate, skMacro}:
|
||||
if symx.typ.len == 2 and symx.typ[1] == forLoopStmt.typ:
|
||||
if symx.typ.len == 2 and symx.typ[1] == maType.typ:
|
||||
if match == nil:
|
||||
match = symx
|
||||
else:
|
||||
localError(c.config, n.info, errAmbiguousCallXYZ % [
|
||||
getProcHeader(c.config, match),
|
||||
getProcHeader(c.config, symx), $iterExpr])
|
||||
getProcHeader(c.config, symx), $selector])
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
|
||||
if match == nil: return
|
||||
|
|
@ -717,11 +651,44 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode =
|
|||
of skTemplate: result = semTemplateExpr(c, callExpr, match, {})
|
||||
else: result = nil
|
||||
|
||||
proc handleForLoopMacro(c: PContext; n: PNode): PNode =
|
||||
result = handleStmtMacro(c, n, n[^2], "ForLoopStmt")
|
||||
|
||||
proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
|
||||
# n[0] has been sem'checked and has a type. We use this to resolve
|
||||
# 'match(n[0])' but then we pass 'n' to the 'match' macro. This seems to
|
||||
# be the best solution.
|
||||
var toResolve = newNodeI(nkCall, n.info)
|
||||
toResolve.add newIdentNode(getIdent(c.cache, "match"), n.info)
|
||||
toResolve.add n[0]
|
||||
|
||||
var errors: CandidateErrors
|
||||
var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {},
|
||||
errors, false)
|
||||
if r.state == csMatch:
|
||||
var match = r.calleeSym
|
||||
markUsed(c.config, n[0].info, match, c.graph.usageSym)
|
||||
styleCheckUse(n[0].info, match)
|
||||
|
||||
# but pass 'n' to the 'match' macro, not 'n[0]':
|
||||
r.call.sons[1] = n
|
||||
let toExpand = semResolvedCall(c, r, r.call, {})
|
||||
case match.kind
|
||||
of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, {})
|
||||
of skTemplate: result = semTemplateExpr(c, toExpand, match, {})
|
||||
else: result = nil
|
||||
# this would be the perfectly consistent solution with 'for loop macros',
|
||||
# but it kinda sucks for pattern matching as the matcher is not attached to
|
||||
# a type then:
|
||||
when false:
|
||||
result = handleStmtMacro(c, n, n[0], "CaseStmt")
|
||||
|
||||
proc semFor(c: PContext, n: PNode): PNode =
|
||||
checkMinSonsLen(n, 3, c.config)
|
||||
var length = sonsLen(n)
|
||||
result = handleForLoopMacro(c, n)
|
||||
if result != nil: return result
|
||||
if forLoopMacros in c.features:
|
||||
result = handleForLoopMacro(c, n)
|
||||
if result != nil: return result
|
||||
openScope(c)
|
||||
result = n
|
||||
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
||||
|
|
@ -757,6 +724,75 @@ proc semFor(c: PContext, n: PNode): PNode =
|
|||
result.typ = c.enforceVoidContext
|
||||
closeScope(c)
|
||||
|
||||
proc semCase(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkMinSonsLen(n, 2, c.config)
|
||||
openScope(c)
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
var chckCovered = false
|
||||
var covered: BiggestInt = 0
|
||||
var typ = commonTypeBegin
|
||||
var hasElse = false
|
||||
let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc})
|
||||
case caseTyp.kind
|
||||
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
||||
chckCovered = true
|
||||
of tyFloat..tyFloat128, tyString, tyError:
|
||||
discard
|
||||
else:
|
||||
if caseStmtMacros in c.features:
|
||||
result = handleCaseStmtMacro(c, n)
|
||||
if result != nil: return result
|
||||
|
||||
localError(c.config, n.info, errSelectorMustBeOfCertainTypes)
|
||||
return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var x = n.sons[i]
|
||||
when defined(nimsuggest):
|
||||
if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum:
|
||||
suggestEnum(c, x, caseTyp)
|
||||
case x.kind
|
||||
of nkOfBranch:
|
||||
checkMinSonsLen(x, 2, c.config)
|
||||
semCaseBranch(c, n, x, i, covered)
|
||||
var last = sonsLen(x)-1
|
||||
x.sons[last] = semExprBranchScope(c, x.sons[last])
|
||||
typ = commonType(typ, x.sons[last])
|
||||
of nkElifBranch:
|
||||
chckCovered = false
|
||||
checkSonsLen(x, 2, c.config)
|
||||
openScope(c)
|
||||
x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
|
||||
x.sons[1] = semExprBranch(c, x.sons[1])
|
||||
typ = commonType(typ, x.sons[1])
|
||||
closeScope(c)
|
||||
of nkElse:
|
||||
chckCovered = false
|
||||
checkSonsLen(x, 1, c.config)
|
||||
x.sons[0] = semExprBranchScope(c, x.sons[0])
|
||||
typ = commonType(typ, x.sons[0])
|
||||
hasElse = true
|
||||
else:
|
||||
illFormedAst(x, c.config)
|
||||
if chckCovered:
|
||||
if covered == toCover(c, n.sons[0].typ):
|
||||
hasElse = true
|
||||
else:
|
||||
localError(c.config, n.info, "not all cases are covered")
|
||||
closeScope(c)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
||||
# propagate any enforced VoidContext:
|
||||
if typ == c.enforceVoidContext:
|
||||
result.typ = c.enforceVoidContext
|
||||
else:
|
||||
for i in 1..n.len-1:
|
||||
var it = n.sons[i]
|
||||
let j = it.len-1
|
||||
if not endsInNoReturn(it.sons[j]):
|
||||
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
|
||||
result.typ = typ
|
||||
|
||||
proc semRaise(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, 1, c.config)
|
||||
|
|
@ -970,7 +1006,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
|||
var body = s.typ.lastSon
|
||||
if body.kind == tyObject:
|
||||
# erases all declared fields
|
||||
body.n.sons = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
body.n.sons = @[]
|
||||
else:
|
||||
body.n.sons = nil
|
||||
|
||||
popOwner(c)
|
||||
closeScope(c)
|
||||
|
|
|
|||
|
|
@ -193,6 +193,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
|||
if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin {
|
||||
tyError, tyObject}:
|
||||
message c.config, n[i].info, errGenerated, "region needs to be an object type"
|
||||
else:
|
||||
message(c.config, n.info, warnDeprecated, "region for pointer types")
|
||||
addSonSkipIntLit(result, region)
|
||||
addSonSkipIntLit(result, t)
|
||||
if tfPartial in result.flags:
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ proc searchInstTypes*(key: PType): PType =
|
|||
if not (genericTyp.kind == tyGenericBody and
|
||||
key.sons[0] == genericTyp and genericTyp.sym != nil): return
|
||||
|
||||
if genericTyp.sym.typeInstCache == nil:
|
||||
return
|
||||
when not defined(nimNoNilSeqs):
|
||||
if genericTyp.sym.typeInstCache == nil: return
|
||||
|
||||
for inst in genericTyp.sym.typeInstCache:
|
||||
if inst.id == key.id: return inst
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
|||
c.calleeScope = 1
|
||||
else:
|
||||
c.calleeScope = calleeScope
|
||||
c.diagnostics = if diagnosticsEnabled: @[] else: nil
|
||||
c.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil
|
||||
c.diagnosticsEnabled = diagnosticsEnabled
|
||||
c.magic = c.calleeSym.magic
|
||||
initIdTable(c.bindings)
|
||||
|
|
@ -535,6 +535,12 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|||
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
||||
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
||||
|
||||
proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation =
|
||||
if optNilSeqs in c.c.config.options:
|
||||
result = allowsNil(f)
|
||||
else:
|
||||
result = isNone
|
||||
|
||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||
result = f.kind != a.kind and (f.kind in {tyVar, tyLent} or a.kind in {tyVar, tyLent})
|
||||
|
||||
|
|
@ -741,7 +747,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
|
|||
diagnostics = @[]
|
||||
flags = {efExplain}
|
||||
m.c.config.writelnHook = proc (s: string) =
|
||||
if errorPrefix == nil: errorPrefix = typeClass.sym.name.s & ":"
|
||||
if errorPrefix.len == 0: errorPrefix = typeClass.sym.name.s & ":"
|
||||
let msg = s.replace("Error:", errorPrefix)
|
||||
if oldWriteHook != nil: oldWriteHook msg
|
||||
diagnostics.add msg
|
||||
|
|
@ -1253,7 +1259,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
|||
result = isNone
|
||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||
result = isNilConversion
|
||||
of tyNil: result = f.allowsNil
|
||||
of tyNil: result = allowsNilDeprecated(c, f)
|
||||
else: discard
|
||||
of tyOrdinal:
|
||||
if isOrdinalType(a):
|
||||
|
|
@ -1338,7 +1344,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
|||
result = isNilConversion
|
||||
else:
|
||||
result = isEqual
|
||||
of tyNil: result = f.allowsNil
|
||||
of tyNil: result = allowsNilDeprecated(c, f)
|
||||
else: discard
|
||||
of tyCString:
|
||||
# conversion from string to cstring is automatic:
|
||||
|
|
@ -1612,7 +1618,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
|||
if f.sonsLen == 0:
|
||||
result = isGeneric
|
||||
else:
|
||||
internalAssert c.c.graph.config, a.sons != nil and a.sons.len > 0
|
||||
internalAssert c.c.graph.config, a.len > 0
|
||||
c.typedescMatched = true
|
||||
var aa = a
|
||||
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
|
||||
|
|
@ -1809,7 +1815,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
|||
# see tests/tgenericconverter:
|
||||
let srca = typeRel(m, src, a)
|
||||
if srca notin {isEqual, isGeneric, isSubtype}: continue
|
||||
|
||||
|
||||
let constraint = c.converters[i].typ.n[1].sym.constraint
|
||||
if not constraint.isNil and not matchNodeKinds(constraint, arg):
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
|||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
|
||||
result = t.sym.name.s
|
||||
if t.kind == tyGenericParam and t.sons != nil and t.sonsLen > 0:
|
||||
if t.kind == tyGenericParam and t.sonsLen > 0:
|
||||
result.add ": "
|
||||
var first = true
|
||||
for son in t.sons:
|
||||
|
|
@ -1200,7 +1200,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
|||
tyNone, tyForward, tyFromExpr:
|
||||
result = t
|
||||
of tyNil:
|
||||
if kind != skConst: result = t
|
||||
if kind != skConst and kind != skParam: result = t
|
||||
of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
|
||||
result = nil
|
||||
of tyOrdinal:
|
||||
|
|
@ -1528,10 +1528,9 @@ proc isCompileTimeOnly*(t: PType): bool {.inline.} =
|
|||
|
||||
proc containsCompileTimeOnly*(t: PType): bool =
|
||||
if isCompileTimeOnly(t): return true
|
||||
if t.sons != nil:
|
||||
for i in 0 ..< t.sonsLen:
|
||||
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
|
||||
return true
|
||||
for i in 0 ..< t.sonsLen:
|
||||
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
|
||||
return true
|
||||
return false
|
||||
|
||||
type
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const
|
|||
byteExcess* = 128 # we use excess-K for immediates
|
||||
wordExcess* = 32768
|
||||
|
||||
MaxLoopIterations* = 1_000_000_000 # max iterations of all loops
|
||||
MaxLoopIterations* = 3_000_000 # max iterations of all loops
|
||||
|
||||
|
||||
type
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ Advanced options:
|
|||
--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
|
||||
--nilseqs:on|off allow 'nil' for strings/seqs for
|
||||
backwards compatibility
|
||||
--skipCfg do not read the general configuration file
|
||||
--skipUserCfg do not read the user's configuration file
|
||||
--skipParentCfg do not read the parent dirs' configuration files
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
* `Exception <system.html#Exception>`_
|
||||
* `AccessViolationError <system.html#AccessViolationError>`_
|
||||
* `ArithmeticError <system.html#ArithmeticError>`_
|
||||
* `DivByZeroError <system.html#DivByZeroError>`_
|
||||
* `OverflowError <system.html#OverflowError>`_
|
||||
* `AssertionError <system.html#AssertionError>`_
|
||||
* `DeadThreadError <system.html#DeadThreadError>`_
|
||||
* `FloatingPointError <system.html#FloatingPointError>`_
|
||||
* `FloatDivByZeroError <system.html#FloatDivByZeroError>`_
|
||||
* `FloatInexactError <system.html#FloatInexactError>`_
|
||||
* `FloatInvalidOpError <system.html#FloatInvalidOpError>`_
|
||||
* `FloatOverflowError <system.html#FloatOverflowError>`_
|
||||
* `FloatUnderflowError <system.html#FloatUnderflowError>`_
|
||||
* `FieldError <system.html#FieldError>`_
|
||||
* `IndexError <system.html#IndexError>`_
|
||||
* `ObjectAssignmentError <system.html#ObjectAssignmentError>`_
|
||||
* `ObjectConversionError <system.html#ObjectConversionError>`_
|
||||
* `ValueError <system.html#ValueError>`_
|
||||
* `KeyError <system.html#KeyError>`_
|
||||
* `ReraiseError <system.html#ReraiseError>`_
|
||||
* `RangeError <system.html#RangeError>`_
|
||||
* `OutOfMemoryError <system.html#OutOfMemoryError>`_
|
||||
* `ResourceExhaustedError <system.html#ResourceExhaustedError>`_
|
||||
* `StackOverflowError <system.html#StackOverflowError>`_
|
||||
* `SystemError <system.html#SystemError>`_
|
||||
* `IOError <system.html#IOError>`_
|
||||
* `OSError <system.html#OSError>`_
|
||||
* `LibraryError <system.html#LibraryError>`_
|
||||
141
doc/manual.rst
141
doc/manual.rst
|
|
@ -769,8 +769,8 @@ Pre-defined floating point types
|
|||
The following floating point types are pre-defined:
|
||||
|
||||
``float``
|
||||
the generic floating point type; its size is platform dependent
|
||||
(the compiler chooses the processor's fastest floating point type).
|
||||
the generic floating point type; its size used to be platform dependent,
|
||||
but now it is always mapped to ``float64``.
|
||||
This type should be used in general.
|
||||
|
||||
floatXX
|
||||
|
|
@ -1507,68 +1507,6 @@ non nilable pointers. The details of this analysis are still to be specified
|
|||
here.
|
||||
|
||||
|
||||
Memory regions
|
||||
--------------
|
||||
|
||||
The types ``ref`` and ``ptr`` can get an optional ``region`` annotation.
|
||||
A region has to be an object type.
|
||||
|
||||
Regions are very useful to separate user space and kernel memory in the
|
||||
development of OS kernels:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Kernel = object
|
||||
Userspace = object
|
||||
|
||||
var a: Kernel ptr Stat
|
||||
var b: Userspace ptr Stat
|
||||
|
||||
# the following does not compile as the pointer types are incompatible:
|
||||
a = b
|
||||
|
||||
As the example shows ``ptr`` can also be used as a binary
|
||||
operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``.
|
||||
|
||||
In order to make generic code easier to write ``ptr T`` is a subtype
|
||||
of ``ptr[R, T]`` for any ``R``.
|
||||
|
||||
Furthermore the subtype relation of the region object types is lifted to
|
||||
the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be
|
||||
used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is
|
||||
not compatible to ``pointer`` to prevent the following from compiling:
|
||||
|
||||
.. code-block:: nim
|
||||
# from system
|
||||
proc dealloc(p: pointer)
|
||||
|
||||
# wrap some scripting language
|
||||
type
|
||||
PythonsHeap = object
|
||||
PyObjectHeader = object
|
||||
rc: int
|
||||
typ: pointer
|
||||
PyObject = ptr[PythonsHeap, PyObjectHeader]
|
||||
|
||||
proc createPyObject(): PyObject {.importc: "...".}
|
||||
proc destroyPyObject(x: PyObject) {.importc: "...".}
|
||||
|
||||
var foo = createPyObject()
|
||||
# type error here, how convenient:
|
||||
dealloc(foo)
|
||||
|
||||
|
||||
Future directions:
|
||||
|
||||
* Memory regions might become available for ``string`` and ``seq`` too.
|
||||
* Builtin regions like ``private``, ``global`` and ``local`` might be
|
||||
useful for an OpenCL target.
|
||||
* Builtin "regions" can model ``lent`` and ``unique`` pointers.
|
||||
* An assignment operator can be attached to a region so that proper write
|
||||
barriers can be generated. This would imply that the GC can be implemented
|
||||
completely in user-space.
|
||||
|
||||
|
||||
Procedural type
|
||||
---------------
|
||||
A procedural type is internally a pointer to a procedure. ``nil`` is
|
||||
|
|
@ -2337,6 +2275,8 @@ pointer type and overloading resolution is tried with ``a[]`` instead.
|
|||
Automatic self insertions
|
||||
-------------------------
|
||||
|
||||
**Note**: The ``.this`` pragma is deprecated and should not be used anymore.
|
||||
|
||||
Starting with version 0.14 of the language, Nim supports ``field`` as a
|
||||
shortcut for ``self.field`` comparable to the `this`:idx: keyword in Java
|
||||
or C++. This feature has to be explicitly enabled via a ``{.this: self.}``
|
||||
|
|
@ -4029,9 +3969,13 @@ exception.
|
|||
Exception hierarchy
|
||||
-------------------
|
||||
|
||||
The exception tree is defined in the `system <system.html>`_ module:
|
||||
|
||||
.. include:: exception_hierarchy_fragment.txt
|
||||
The exception tree is defined in the `system <system.html>`_ module.
|
||||
Every exception inherits from ``system.Exception``. Exceptions that indicate
|
||||
programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``)
|
||||
and are stricly speaking not catchable as they can also be mapped to an operation
|
||||
that terminates the whole process. Exceptions that indicate any other runtime error
|
||||
that can be caught inherit from ``system.CatchableError``
|
||||
(which is a subtype of ``Exception``).
|
||||
|
||||
|
||||
Imported exceptions
|
||||
|
|
@ -5436,6 +5380,7 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
|
|||
:test: "nim c $1"
|
||||
|
||||
import macros
|
||||
{.experimental: "forLoopMacros".}
|
||||
|
||||
macro enumerate(x: ForLoopStmt): untyped =
|
||||
expectKind x, nnkForStmt
|
||||
|
|
@ -5462,6 +5407,62 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
|
|||
echo a2, " ", b2
|
||||
|
||||
|
||||
Currently for loop macros must be enabled explicitly
|
||||
via ``{.experimental: "forLoopMacros".}``.
|
||||
|
||||
|
||||
Case statement macros
|
||||
---------------------
|
||||
|
||||
A macro that needs to be called `match`:idx: can be used to
|
||||
rewrite ``case`` statements in order to
|
||||
implement `pattern matching`:idx: for certain types. The following
|
||||
example implements a simplistic form of pattern matching for tuples,
|
||||
leveraging the existing equality operator for tuples (as provided in
|
||||
``system.==``):
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
|
||||
{.experimental: "caseStmtMacros".}
|
||||
|
||||
import macros
|
||||
|
||||
macro match(n: tuple): untyped =
|
||||
result = newTree(nnkIfStmt)
|
||||
let selector = n[0]
|
||||
for i in 1 ..< n.len:
|
||||
let it = n[i]
|
||||
case it.kind
|
||||
of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr:
|
||||
result.add it
|
||||
of nnkOfBranch:
|
||||
for j in 0..it.len-2:
|
||||
let cond = newCall("==", selector, it[j])
|
||||
result.add newTree(nnkElifBranch, cond, it[^1])
|
||||
else:
|
||||
error "'match' cannot handle this node", it
|
||||
echo repr result
|
||||
|
||||
case ("foo", 78)
|
||||
of ("foo", 78): echo "yes"
|
||||
of ("bar", 88): echo "no"
|
||||
else: discard
|
||||
|
||||
|
||||
Currently case statement macros must be enabled explicitly
|
||||
via ``{.experimental: "caseStmtMacros".}``.
|
||||
|
||||
``match`` macros are subject to overload resolution. First the
|
||||
``case``'s selector expression is used to determine which ``match``
|
||||
macro to call. To this macro is then the complete ``case`` statement
|
||||
body is passed and the macro is evaluated.
|
||||
|
||||
In other words, the macro needs to transform the full ``case`` statement
|
||||
but only the statement's selector expression is used to determine which
|
||||
``macro`` to call.
|
||||
|
||||
|
||||
Special Types
|
||||
=============
|
||||
|
||||
|
|
@ -7933,7 +7934,7 @@ that ``spawn`` takes is restricted:
|
|||
|
||||
``spawn`` executes the passed expression on the thread pool and returns
|
||||
a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading
|
||||
with the ``^`` operator is **blocking**. However, one can use ``awaitAny`` to
|
||||
with the ``^`` operator is **blocking**. However, one can use ``blockUntilAny`` to
|
||||
wait on multiple flow variables at the same time:
|
||||
|
||||
.. code-block:: nim
|
||||
|
|
@ -7944,10 +7945,10 @@ wait on multiple flow variables at the same time:
|
|||
var responses = newSeq[FlowVarBase](3)
|
||||
for i in 0..2:
|
||||
responses[i] = spawn tellServer(Update, "key", "value")
|
||||
var index = awaitAny(responses)
|
||||
var index = blockUntilAny(responses)
|
||||
assert index >= 0
|
||||
responses.del(index)
|
||||
discard awaitAny(responses)
|
||||
discard blockUntilAny(responses)
|
||||
|
||||
Data flow variables ensure that no data races
|
||||
are possible. Due to technical limitations not every type ``T`` is possible in
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ Generated C code directory
|
|||
The generated files that Nim produces all go into a subdirectory called
|
||||
``nimcache``. Its full path is
|
||||
|
||||
- ``$XDG_CACHE_HOME/$projectname(_r|_d)`` or ``~/.cache/$projectname(_r|_d)``
|
||||
- ``$XDG_CACHE_HOME/nim/$projectname(_r|_d)`` or ``~/.cache/nim/$projectname(_r|_d)``
|
||||
on Posix
|
||||
- ``$HOME/nimcache/$projectname(_r|_d)`` on Windows.
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Spawn statement
|
|||
A standalone ``spawn`` statement is a simple construct. It executes
|
||||
the passed expression on the thread pool and returns a `data flow variable`:idx:
|
||||
``FlowVar[T]`` that can be read from. The reading with the ``^`` operator is
|
||||
**blocking**. However, one can use ``awaitAny`` to wait on multiple flow
|
||||
**blocking**. However, one can use ``blockUntilAny`` to wait on multiple flow
|
||||
variables at the same time:
|
||||
|
||||
.. code-block:: nim
|
||||
|
|
@ -36,10 +36,10 @@ variables at the same time:
|
|||
var responses = newSeq[FlowVarBase](3)
|
||||
for i in 0..2:
|
||||
responses[i] = spawn tellServer(Update, "key", "value")
|
||||
var index = awaitAny(responses)
|
||||
var index = blockUntilAny(responses)
|
||||
assert index >= 0
|
||||
responses.del(index)
|
||||
discard awaitAny(responses)
|
||||
discard blockUntilAny(responses)
|
||||
|
||||
Data flow variables ensure that no data races
|
||||
are possible. Due to technical limitations not every type ``T`` is possible in
|
||||
|
|
|
|||
|
|
@ -42,6 +42,6 @@ test "arithmetic failure":
|
|||
expect(ArithmeticError):
|
||||
err()
|
||||
|
||||
expect(ArithmeticError, SystemError):
|
||||
expect(ArithmeticError, CatchableError):
|
||||
discard foo()
|
||||
|
||||
|
|
|
|||
4
koch.nim
4
koch.nim
|
|
@ -183,7 +183,7 @@ proc bundleNimbleExe() =
|
|||
bundleNimbleSrc()
|
||||
# now compile Nimble and copy it to $nim/bin for the installer.ini
|
||||
# to pick it up:
|
||||
nimexec("c -d:release dist/nimble/src/nimble.nim")
|
||||
nimexec("c -d:release --nilseqs:on dist/nimble/src/nimble.nim")
|
||||
copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe)
|
||||
|
||||
proc buildNimble(latest: bool) =
|
||||
|
|
@ -210,7 +210,7 @@ proc buildNimble(latest: bool) =
|
|||
else:
|
||||
exec("git checkout -f stable")
|
||||
exec("git pull")
|
||||
nimexec("c --noNimblePath -p:compiler -d:release " & installDir / "src/nimble.nim")
|
||||
nimexec("c --noNimblePath -p:compiler --nilseqs:on -d:release " & installDir / "src/nimble.nim")
|
||||
copyExe(installDir / "src/nimble".exe, "bin/nimble".exe)
|
||||
|
||||
proc bundleNimsuggest(buildExe: bool) =
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ type
|
|||
t: Thread[ptr Actor[In, Out]]
|
||||
|
||||
PActor*[In, Out] = ptr Actor[In, Out] ## an actor
|
||||
{.deprecated: [TTask: Task, TActor: Actor].}
|
||||
|
||||
proc spawn*[In, Out](action: proc(
|
||||
self: PActor[In, Out]){.thread.}): PActor[In, Out] =
|
||||
|
|
@ -168,7 +167,7 @@ proc terminate*[In, Out](a: var ActorPool[In, Out]) =
|
|||
for i in 0..<a.actors.len: join(a.actors[i])
|
||||
when Out isnot void:
|
||||
close(a.outputs)
|
||||
a.actors = nil
|
||||
a.actors = @[]
|
||||
|
||||
proc join*[In, Out](a: var ActorPool[In, Out]) =
|
||||
## short-cut for `sync` and then `terminate`.
|
||||
|
|
|
|||
|
|
@ -128,10 +128,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
|
|||
var a = 0
|
||||
for c in items(string(formatstr)):
|
||||
if c == '?':
|
||||
if args[a].isNil:
|
||||
add(result, "NULL")
|
||||
else:
|
||||
add(result, dbQuote(args[a]))
|
||||
add(result, dbQuote(args[a]))
|
||||
inc(a)
|
||||
else:
|
||||
add(result, c)
|
||||
|
|
@ -183,24 +180,8 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
|
|||
row = mysql.fetchRow(sqlres)
|
||||
if row == nil: break
|
||||
for i in 0..L-1:
|
||||
if row[i] == nil:
|
||||
if backup == nil:
|
||||
newSeq(backup, L)
|
||||
if backup[i] == nil and result[i] != nil:
|
||||
shallowCopy(backup[i], result[i])
|
||||
result[i] = nil
|
||||
else:
|
||||
if result[i] == nil:
|
||||
if backup != nil:
|
||||
if backup[i] == nil:
|
||||
backup[i] = ""
|
||||
shallowCopy(result[i], backup[i])
|
||||
setLen(result[i], 0)
|
||||
else:
|
||||
result[i] = ""
|
||||
else:
|
||||
setLen(result[i], 0)
|
||||
add(result[i], row[i])
|
||||
setLen(result[i], 0)
|
||||
result[i].add row[i]
|
||||
yield result
|
||||
properFreeResult(sqlres, row)
|
||||
|
||||
|
|
@ -323,10 +304,7 @@ proc getRow*(db: DbConn, query: SqlQuery,
|
|||
if row != nil:
|
||||
for i in 0..L-1:
|
||||
setLen(result[i], 0)
|
||||
if row[i] == nil:
|
||||
result[i] = nil
|
||||
else:
|
||||
add(result[i], row[i])
|
||||
add(result[i], row[i])
|
||||
properFreeResult(sqlres, row)
|
||||
|
||||
proc getAllRows*(db: DbConn, query: SqlQuery,
|
||||
|
|
@ -345,10 +323,7 @@ proc getAllRows*(db: DbConn, query: SqlQuery,
|
|||
setLen(result, j+1)
|
||||
newSeq(result[j], L)
|
||||
for i in 0..L-1:
|
||||
if row[i] == nil:
|
||||
result[j][i] = nil
|
||||
else:
|
||||
result[j][i] = $row[i]
|
||||
result[j][i] = $row[i]
|
||||
inc(j)
|
||||
mysql.freeResult(sqlres)
|
||||
|
||||
|
|
|
|||
|
|
@ -103,10 +103,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
|
|||
else:
|
||||
for c in items(string(formatstr)):
|
||||
if c == '?':
|
||||
if args[a] == nil:
|
||||
add(result, "NULL")
|
||||
else:
|
||||
add(result, dbQuote(args[a]))
|
||||
add(result, dbQuote(args[a]))
|
||||
inc(a)
|
||||
else:
|
||||
add(result, c)
|
||||
|
|
@ -179,7 +176,7 @@ proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
|
|||
setLen(r[col], 0)
|
||||
let x = pqgetvalue(res, line, col)
|
||||
if x.isNil:
|
||||
r[col] = nil
|
||||
r[col] = ""
|
||||
else:
|
||||
add(r[col], x)
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ proc dbError*(db: DbConn) {.noreturn.} =
|
|||
|
||||
proc dbQuote*(s: string): string =
|
||||
## DB quotes the string.
|
||||
if s.isNil: return "NULL"
|
||||
result = "'"
|
||||
for c in items(s):
|
||||
if c == '\'': add(result, "''")
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ proc `[]`*(pattern: Captures, i: int): string =
|
|||
let bounds = bounds.get
|
||||
return pattern.str.substr(bounds.a, bounds.b)
|
||||
else:
|
||||
return nil
|
||||
return ""
|
||||
|
||||
proc match*(pattern: RegexMatch): string =
|
||||
return pattern.captures[-1]
|
||||
|
|
@ -291,9 +291,9 @@ template toTableImpl(cond: untyped) {.dirty.} =
|
|||
else:
|
||||
result[key] = nextVal
|
||||
|
||||
proc toTable*(pattern: Captures, default: string = nil): Table[string, string] =
|
||||
proc toTable*(pattern: Captures, default: string = ""): Table[string, string] =
|
||||
result = initTable[string, string]()
|
||||
toTableImpl(nextVal == nil)
|
||||
toTableImpl(nextVal.len == 0)
|
||||
|
||||
proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])):
|
||||
Table[string, Option[HSlice[int, int]]] =
|
||||
|
|
@ -312,13 +312,13 @@ template itemsImpl(cond: untyped) {.dirty.} =
|
|||
iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] =
|
||||
itemsImpl(nextVal.isNone)
|
||||
|
||||
iterator items*(pattern: Captures, default: string = nil): string =
|
||||
itemsImpl(nextVal == nil)
|
||||
iterator items*(pattern: Captures, default: string = ""): string =
|
||||
itemsImpl(nextVal.len == 0)
|
||||
|
||||
proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
|
||||
accumulateResult(pattern.items(default))
|
||||
|
||||
proc toSeq*(pattern: Captures, default: string = nil): seq[string] =
|
||||
proc toSeq*(pattern: Captures, default: string = ""): seq[string] =
|
||||
accumulateResult(pattern.items(default))
|
||||
|
||||
proc `$`*(pattern: RegexMatch): string =
|
||||
|
|
|
|||
|
|
@ -10,11 +10,7 @@ proc fget*[K, V](self: Table[K, V], key: K): V =
|
|||
const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
||||
const StartIdent = Ident - {'0'..'9'}
|
||||
|
||||
proc checkNil(arg: string): string =
|
||||
if arg == nil:
|
||||
raise newException(ValueError, "Cannot use nil capture")
|
||||
else:
|
||||
return arg
|
||||
template checkNil(arg: string): string = arg
|
||||
|
||||
template formatStr*(howExpr, namegetter, idgetter): untyped =
|
||||
let how = howExpr
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string],
|
|||
var b = rawMatches[i * 2 + 1]
|
||||
if a >= 0'i32:
|
||||
matches[i-1] = bufSubstr(buf, int(a), int(b))
|
||||
else: matches[i-1] = nil
|
||||
else: matches[i-1] = ""
|
||||
return rawMatches[1] - rawMatches[0]
|
||||
|
||||
proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
||||
|
|
@ -133,7 +133,7 @@ proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
|||
var a = rawMatches[i * 2]
|
||||
var b = rawMatches[i * 2 + 1]
|
||||
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
|
||||
else: matches[i-1] = nil
|
||||
else: matches[i-1] = ""
|
||||
return (rawMatches[0].int, rawMatches[1].int - 1)
|
||||
|
||||
proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
|
||||
|
|
@ -287,7 +287,7 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
|||
var a = rawMatches[i * 2]
|
||||
var b = rawMatches[i * 2 + 1]
|
||||
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
|
||||
else: matches[i-1] = nil
|
||||
else: matches[i-1] = ""
|
||||
return rawMatches[0]
|
||||
|
||||
proc find*(s: string, pattern: Regex, matches: var openArray[string],
|
||||
|
|
@ -456,8 +456,6 @@ proc replacef*(s: string, sub: Regex, by: string): string =
|
|||
while true:
|
||||
var match = findBounds(s, sub, caps, prev)
|
||||
if match.first < 0: break
|
||||
assert result != nil
|
||||
assert s != nil
|
||||
add(result, substr(s, prev, match.first-1))
|
||||
addf(result, by, caps)
|
||||
prev = match.last + 1
|
||||
|
|
@ -615,7 +613,7 @@ when isMainModule:
|
|||
doAssert false
|
||||
|
||||
if "abc" =~ re"(cba)?.*":
|
||||
doAssert matches[0] == nil
|
||||
doAssert matches[0] == ""
|
||||
else: doAssert false
|
||||
|
||||
if "abc" =~ re"().*":
|
||||
|
|
|
|||
|
|
@ -293,9 +293,9 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
|
|||
(key: "kind", val: %($node.kind)),
|
||||
(key: "level", val: %BiggestInt(node.level))
|
||||
]
|
||||
if node.text != nil:
|
||||
if node.text.len > 0:
|
||||
result.add("text", %node.text)
|
||||
if node.sons != nil and len(node.sons) > 0:
|
||||
if len(node.sons) > 0:
|
||||
var accm = newSeq[JsonNode](len(node.sons))
|
||||
for i, son in node.sons:
|
||||
accm[i] = renderRstToJsonNode(son)
|
||||
|
|
|
|||
|
|
@ -312,7 +312,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string,
|
|||
## The index won't be written to disk unless you call `writeIndexFile()
|
||||
## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen
|
||||
## tools guide <docgen.html#index-switch>`_.
|
||||
assert(not d.theIndex.isNil)
|
||||
var
|
||||
entry = term
|
||||
isTitle = false
|
||||
|
|
@ -337,7 +336,7 @@ proc hash(n: PRstNode): int =
|
|||
result = hash(n.text)
|
||||
elif n.len > 0:
|
||||
result = hash(n.sons[0])
|
||||
for i in 1 .. <len(n):
|
||||
for i in 1 ..< len(n):
|
||||
result = result !& hash(n.sons[i])
|
||||
result = !$result
|
||||
|
||||
|
|
@ -398,9 +397,9 @@ proc hash(x: IndexEntry): Hash =
|
|||
proc `<-`(a: var IndexEntry, b: IndexEntry) =
|
||||
shallowCopy a.keyword, b.keyword
|
||||
shallowCopy a.link, b.link
|
||||
if b.linkTitle.isNil: a.linkTitle = nil
|
||||
if b.linkTitle.isNil: a.linkTitle = ""
|
||||
else: shallowCopy a.linkTitle, b.linkTitle
|
||||
if b.linkDesc.isNil: a.linkDesc = nil
|
||||
if b.linkDesc.isNil: a.linkDesc = ""
|
||||
else: shallowCopy a.linkDesc, b.linkDesc
|
||||
|
||||
proc sortIndex(a: var openArray[IndexEntry]) =
|
||||
|
|
@ -452,7 +451,7 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
|
|||
title="$3" data-doc-search-tag="$2" href="$1">$2</a></li>
|
||||
""", [url, text, desc])
|
||||
else:
|
||||
result.addf("""<li><a class="reference external"
|
||||
result.addf("""<li><a class="reference external"
|
||||
data-doc-search-tag="$2" href="$1">$2</a></li>
|
||||
""", [url, text])
|
||||
inc j
|
||||
|
|
@ -524,7 +523,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
|
|||
titleTag = levels[L].text
|
||||
else:
|
||||
result.add(level.indentToLevel(levels[L].level))
|
||||
result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2">
|
||||
result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2">
|
||||
$3</a></li>
|
||||
""", [titleTag & " : " & levels[L].text, link, levels[L].text])
|
||||
inc L
|
||||
|
|
@ -608,8 +607,8 @@ proc readIndexDir(dir: string):
|
|||
fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
|
||||
fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
|
||||
else:
|
||||
fileEntries[F].linkTitle = nil
|
||||
fileEntries[F].linkDesc = nil
|
||||
fileEntries[F].linkTitle = ""
|
||||
fileEntries[F].linkDesc = ""
|
||||
inc F
|
||||
# Depending on type add this to the list of symbols or table of APIs.
|
||||
if title.keyword.isNil:
|
||||
|
|
@ -657,7 +656,6 @@ proc mergeIndexes*(dir: string): string =
|
|||
## Returns the merged and sorted indices into a single HTML block which can
|
||||
## be further embedded into nimdoc templates.
|
||||
var (modules, symbols, docs) = readIndexDir(dir)
|
||||
assert(not symbols.isNil)
|
||||
|
||||
result = ""
|
||||
# Generate a quick jump list of documents.
|
||||
|
|
|
|||
|
|
@ -219,10 +219,10 @@ proc getHint(entry: StackTraceEntry): string =
|
|||
## We try to provide some hints about stack trace entries that the user
|
||||
## may not be familiar with, in particular calls inside the stdlib.
|
||||
result = ""
|
||||
if entry.procname == "processPendingCallbacks":
|
||||
if entry.procname == cstring"processPendingCallbacks":
|
||||
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
||||
return "Executes pending callbacks"
|
||||
elif entry.procname == "poll":
|
||||
elif entry.procname == cstring"poll":
|
||||
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
||||
return "Processes asynchronous completion events"
|
||||
|
||||
|
|
|
|||
|
|
@ -493,8 +493,6 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
|
|||
## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
|
||||
## protocol uses ``\r\L`` to delimit a new line.
|
||||
assert SocketFlag.Peek notin flags ## TODO:
|
||||
assert(not resString.mget.isNil(),
|
||||
"String inside resString future needs to be initialised")
|
||||
result = newFuture[void]("asyncnet.recvLineInto")
|
||||
|
||||
# TODO: Make the async transformation check for FutureVar params and complete
|
||||
|
|
@ -657,7 +655,7 @@ when defineSsl:
|
|||
|
||||
proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket,
|
||||
handshake: SslHandshakeType,
|
||||
hostname: string = nil) =
|
||||
hostname: string = "") =
|
||||
## Wraps a connected socket in an SSL context. This function effectively
|
||||
## turns ``socket`` into an SSL socket.
|
||||
## ``hostname`` should be specified so that the client knows which hostname
|
||||
|
|
@ -672,7 +670,7 @@ when defineSsl:
|
|||
|
||||
case handshake
|
||||
of handshakeAsClient:
|
||||
if not hostname.isNil and not isIpAddress(hostname):
|
||||
if hostname.len > 0 and not isIpAddress(hostname):
|
||||
# Set the SNI address for this connection. This call can fail if
|
||||
# we're not using TLSv1+.
|
||||
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ proc missingOrExcl*(s: var IntSet, key: int) : bool =
|
|||
## `key` is removed from `s` and false is returned.
|
||||
var count = s.elems
|
||||
exclImpl(s, key)
|
||||
result = count == s.elems
|
||||
result = count == s.elems
|
||||
|
||||
proc containsOrIncl*(s: var IntSet, key: int): bool =
|
||||
## returns true if `s` contains `key`, otherwise `key` is included in `s`
|
||||
|
|
@ -212,7 +212,10 @@ proc initIntSet*: IntSet =
|
|||
|
||||
#newSeq(result.data, InitIntSetSize)
|
||||
#result.max = InitIntSetSize-1
|
||||
result.data = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
result.data = @[]
|
||||
else:
|
||||
result.data = nil
|
||||
result.max = 0
|
||||
result.counter = 0
|
||||
result.head = nil
|
||||
|
|
@ -222,7 +225,10 @@ proc clear*(result: var IntSet) =
|
|||
#setLen(result.data, InitIntSetSize)
|
||||
#for i in 0..InitIntSetSize-1: result.data[i] = nil
|
||||
#result.max = InitIntSetSize-1
|
||||
result.data = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
result.data = @[]
|
||||
else:
|
||||
result.data = nil
|
||||
result.max = 0
|
||||
result.counter = 0
|
||||
result.head = nil
|
||||
|
|
@ -234,7 +240,10 @@ proc assign*(dest: var IntSet, src: IntSet) =
|
|||
## copies `src` to `dest`. `dest` does not need to be initialized by
|
||||
## `initIntSet`.
|
||||
if src.elems <= src.a.len:
|
||||
dest.data = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
dest.data = @[]
|
||||
else:
|
||||
dest.data = nil
|
||||
dest.max = 0
|
||||
dest.counter = src.counter
|
||||
dest.head = nil
|
||||
|
|
@ -247,11 +256,9 @@ proc assign*(dest: var IntSet, src: IntSet) =
|
|||
|
||||
var it = src.head
|
||||
while it != nil:
|
||||
|
||||
var h = it.key and dest.max
|
||||
while dest.data[h] != nil: h = nextTry(h, dest.max)
|
||||
assert(dest.data[h] == nil)
|
||||
|
||||
var n: PTrunk
|
||||
new(n)
|
||||
n.next = dest.head
|
||||
|
|
@ -259,7 +266,6 @@ proc assign*(dest: var IntSet, src: IntSet) =
|
|||
n.bits = it.bits
|
||||
dest.head = n
|
||||
dest.data[h] = n
|
||||
|
||||
it = it.next
|
||||
|
||||
proc union*(s1, s2: IntSet): IntSet =
|
||||
|
|
@ -315,7 +321,7 @@ proc len*(s: IntSet): int {.inline.} =
|
|||
for _ in s:
|
||||
inc(result)
|
||||
|
||||
proc card*(s: IntSet): int {.inline.} =
|
||||
proc card*(s: IntSet): int {.inline.} =
|
||||
## alias for `len() <#len>` _.
|
||||
result = s.len()
|
||||
|
||||
|
|
@ -361,7 +367,7 @@ when isMainModule:
|
|||
x.incl(1056)
|
||||
|
||||
x.incl(1044)
|
||||
x.excl(1044)
|
||||
x.excl(1044)
|
||||
|
||||
assert x.containsOrIncl(888) == false
|
||||
assert 888 in x
|
||||
|
|
|
|||
|
|
@ -1329,7 +1329,7 @@ when isMainModule:
|
|||
doAssert clearTable[42] == "asd"
|
||||
clearTable.clear()
|
||||
doAssert(not clearTable.hasKey(123123))
|
||||
doAssert clearTable.getOrDefault(42) == nil
|
||||
doAssert clearTable.getOrDefault(42) == ""
|
||||
|
||||
block: #5482
|
||||
var a = [("wrong?","foo"), ("wrong?", "foo2")].newOrderedTable()
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ proc destroySemaphore(cv: var Semaphore) {.inline.} =
|
|||
deinitCond(cv.c)
|
||||
deinitLock(cv.L)
|
||||
|
||||
proc await(cv: var Semaphore) =
|
||||
proc blockUntil(cv: var Semaphore) =
|
||||
acquire(cv.L)
|
||||
while cv.counter <= 0:
|
||||
wait(cv.c, cv.L)
|
||||
|
|
@ -81,7 +81,7 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
|
|||
fence()
|
||||
b.interest = true
|
||||
fence()
|
||||
while b.left != b.entered: await(b.cv)
|
||||
while b.left != b.entered: blockUntil(b.cv)
|
||||
destroySemaphore(b.cv)
|
||||
|
||||
{.pop.}
|
||||
|
|
@ -89,8 +89,6 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
|
|||
# ----------------------------------------------------------------------------
|
||||
|
||||
type
|
||||
foreign* = object ## a region that indicates the pointer comes from a
|
||||
## foreign thread heap.
|
||||
AwaitInfo = object
|
||||
cv: Semaphore
|
||||
idx: int
|
||||
|
|
@ -99,7 +97,7 @@ type
|
|||
FlowVarBaseObj = object of RootObj
|
||||
ready, usesSemaphore, awaited: bool
|
||||
cv: Semaphore #\
|
||||
# for 'awaitAny' support
|
||||
# for 'blockUntilAny' support
|
||||
ai: ptr AwaitInfo
|
||||
idx: int
|
||||
data: pointer # we incRef and unref it to keep it alive; note this MUST NOT
|
||||
|
|
@ -130,12 +128,12 @@ type
|
|||
q: ToFreeQueue
|
||||
readyForTask: Semaphore
|
||||
|
||||
proc await*(fv: FlowVarBase) =
|
||||
proc blockUntil*(fv: FlowVarBase) =
|
||||
## waits until the value for the flowVar arrives. Usually it is not necessary
|
||||
## to call this explicitly.
|
||||
if fv.usesSemaphore and not fv.awaited:
|
||||
fv.awaited = true
|
||||
await(fv.cv)
|
||||
blockUntil(fv.cv)
|
||||
destroySemaphore(fv.cv)
|
||||
|
||||
proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
|
||||
|
|
@ -143,7 +141,7 @@ proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
|
|||
w.data = data
|
||||
w.f = fn
|
||||
signal(w.taskArrived)
|
||||
await(w.taskStarted)
|
||||
blockUntil(w.taskStarted)
|
||||
result = true
|
||||
|
||||
proc cleanFlowVars(w: ptr Worker) =
|
||||
|
|
@ -178,11 +176,11 @@ proc attach(fv: FlowVarBase; i: int): bool =
|
|||
release(fv.cv.L)
|
||||
|
||||
proc finished(fv: FlowVarBase) =
|
||||
doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'"
|
||||
doAssert fv.ai.isNil, "flowVar is still attached to an 'blockUntilAny'"
|
||||
# we have to protect against the rare cases where the owner of the flowVar
|
||||
# simply disregards the flowVar and yet the "flowVar" has not yet written
|
||||
# anything to it:
|
||||
await(fv)
|
||||
blockUntil(fv)
|
||||
if fv.data.isNil: return
|
||||
let owner = cast[ptr Worker](fv.owner)
|
||||
let q = addr(owner.q)
|
||||
|
|
@ -191,7 +189,7 @@ proc finished(fv: FlowVarBase) =
|
|||
#echo "EXHAUSTED!"
|
||||
release(q.lock)
|
||||
wakeupWorkerToProcessQueue(owner)
|
||||
await(q.empty)
|
||||
blockUntil(q.empty)
|
||||
acquire(q.lock)
|
||||
q.data[q.len] = cast[pointer](fv.data)
|
||||
inc q.len
|
||||
|
|
@ -222,7 +220,7 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
|
|||
## to ``action``. Note that due to Nim's parameter passing semantics this
|
||||
## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can
|
||||
## sometimes be more efficient than ``^``.
|
||||
await(fv)
|
||||
blockUntil(fv)
|
||||
when T is string or T is seq:
|
||||
action(cast[T](fv.data))
|
||||
elif T is ref:
|
||||
|
|
@ -231,31 +229,31 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
|
|||
action(fv.blob)
|
||||
finished(fv)
|
||||
|
||||
proc unsafeRead*[T](fv: FlowVar[ref T]): foreign ptr T =
|
||||
proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T =
|
||||
## blocks until the value is available and then returns this value.
|
||||
await(fv)
|
||||
result = cast[foreign ptr T](fv.data)
|
||||
blockUntil(fv)
|
||||
result = cast[ptr T](fv.data)
|
||||
|
||||
proc `^`*[T](fv: FlowVar[ref T]): ref T =
|
||||
## blocks until the value is available and then returns this value.
|
||||
await(fv)
|
||||
blockUntil(fv)
|
||||
let src = cast[ref T](fv.data)
|
||||
deepCopy result, src
|
||||
|
||||
proc `^`*[T](fv: FlowVar[T]): T =
|
||||
## blocks until the value is available and then returns this value.
|
||||
await(fv)
|
||||
blockUntil(fv)
|
||||
when T is string or T is seq:
|
||||
# XXX closures? deepCopy?
|
||||
result = cast[T](fv.data)
|
||||
else:
|
||||
result = fv.blob
|
||||
|
||||
proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
|
||||
proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int =
|
||||
## awaits any of the given flowVars. Returns the index of one flowVar for
|
||||
## which a value arrived. A flowVar only supports one call to 'awaitAny' at
|
||||
## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second
|
||||
## call will only await 'c'. If there is no flowVar left to be able to wait
|
||||
## which a value arrived. A flowVar only supports one call to 'blockUntilAny' at
|
||||
## the same time. That means if you blockUntilAny([a,b]) and blockUntilAny([b,c]) the second
|
||||
## call will only blockUntil 'c'. If there is no flowVar left to be able to wait
|
||||
## on, -1 is returned.
|
||||
## **Note**: This results in non-deterministic behaviour and should be avoided.
|
||||
var ai: AwaitInfo
|
||||
|
|
@ -271,7 +269,7 @@ proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
|
|||
inc conflicts
|
||||
if conflicts < flowVars.len:
|
||||
if result < 0:
|
||||
await(ai.cv)
|
||||
blockUntil(ai.cv)
|
||||
result = ai.idx
|
||||
for i in 0 .. flowVars.high:
|
||||
discard cas(addr flowVars[i].ai, addr ai, nil)
|
||||
|
|
@ -328,7 +326,7 @@ proc slave(w: ptr Worker) {.thread.} =
|
|||
w.ready = true
|
||||
readyWorker = w
|
||||
signal(gSomeReady)
|
||||
await(w.taskArrived)
|
||||
blockUntil(w.taskArrived)
|
||||
# XXX Somebody needs to look into this (why does this assertion fail
|
||||
# in Visual Studio?)
|
||||
when not defined(vcc) and not defined(tcc): assert(not w.ready)
|
||||
|
|
@ -353,7 +351,7 @@ proc distinguishedSlave(w: ptr Worker) {.thread.} =
|
|||
else:
|
||||
w.ready = true
|
||||
signal(w.readyForTask)
|
||||
await(w.taskArrived)
|
||||
blockUntil(w.taskArrived)
|
||||
assert(not w.ready)
|
||||
w.f(w, w.data)
|
||||
if w.q.len != 0: w.cleanFlowVars
|
||||
|
|
@ -501,7 +499,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
|
|||
# on the current thread instead.
|
||||
var self = addr(workersData[localThreadId-1])
|
||||
fn(self, data)
|
||||
await(self.taskStarted)
|
||||
blockUntil(self.taskStarted)
|
||||
return
|
||||
|
||||
if isSlave:
|
||||
|
|
@ -526,7 +524,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
|
|||
|
||||
inc numSlavesWaiting
|
||||
|
||||
await(gSomeReady)
|
||||
blockUntil(gSomeReady)
|
||||
|
||||
if isSlave:
|
||||
withLock numSlavesLock:
|
||||
|
|
@ -544,7 +542,7 @@ proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerProc.} =
|
|||
release(distinguishedLock)
|
||||
while true:
|
||||
if selectWorker(addr(distinguishedData[id]), fn, data): break
|
||||
await(distinguishedData[id].readyForTask)
|
||||
blockUntil(distinguishedData[id].readyForTask)
|
||||
|
||||
|
||||
proc sync*() =
|
||||
|
|
@ -557,7 +555,7 @@ proc sync*() =
|
|||
if not allReady: break
|
||||
allReady = allReady and workersData[i].ready
|
||||
if allReady: break
|
||||
await(gSomeReady)
|
||||
blockUntil(gSomeReady)
|
||||
inc toRelease
|
||||
|
||||
for i in 0 ..< toRelease:
|
||||
|
|
|
|||
|
|
@ -1869,7 +1869,6 @@ proc entityToUtf8*(entity: string): string =
|
|||
## "" is returned if the entity name is unknown. The HTML parser
|
||||
## already converts entities to UTF-8.
|
||||
runnableExamples:
|
||||
doAssert entityToUtf8(nil) == ""
|
||||
doAssert entityToUtf8("") == ""
|
||||
doAssert entityToUtf8("a") == ""
|
||||
doAssert entityToUtf8("gt") == ">"
|
||||
|
|
|
|||
|
|
@ -378,23 +378,23 @@ proc newMultipartData*: MultipartData =
|
|||
## Constructs a new ``MultipartData`` object.
|
||||
MultipartData(content: @[])
|
||||
|
||||
proc add*(p: var MultipartData, name, content: string, filename: string = nil,
|
||||
contentType: string = nil) =
|
||||
proc add*(p: var MultipartData, name, content: string, filename: string = "",
|
||||
contentType: string = "") =
|
||||
## Add a value to the multipart data. Raises a `ValueError` exception if
|
||||
## `name`, `filename` or `contentType` contain newline characters.
|
||||
|
||||
if {'\c','\L'} in name:
|
||||
raise newException(ValueError, "name contains a newline character")
|
||||
if filename != nil and {'\c','\L'} in filename:
|
||||
if {'\c','\L'} in filename:
|
||||
raise newException(ValueError, "filename contains a newline character")
|
||||
if contentType != nil and {'\c','\L'} in contentType:
|
||||
if {'\c','\L'} in contentType:
|
||||
raise newException(ValueError, "contentType contains a newline character")
|
||||
|
||||
var str = "Content-Disposition: form-data; name=\"" & name & "\""
|
||||
if filename != nil:
|
||||
if filename.len > 0:
|
||||
str.add("; filename=\"" & filename & "\"")
|
||||
str.add("\c\L")
|
||||
if contentType != nil:
|
||||
if contentType.len > 0:
|
||||
str.add("Content-Type: " & contentType & "\c\L")
|
||||
str.add("\c\L" & content & "\c\L")
|
||||
|
||||
|
|
@ -434,7 +434,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
|
|||
var contentType: string
|
||||
let (_, fName, ext) = splitFile(file)
|
||||
if ext.len > 0:
|
||||
contentType = m.getMimetype(ext[1..ext.high], nil)
|
||||
contentType = m.getMimetype(ext[1..ext.high], "")
|
||||
p.add(name, readFile(file), fName & ext, contentType)
|
||||
result = p
|
||||
|
||||
|
|
@ -457,7 +457,7 @@ proc `[]=`*(p: var MultipartData, name: string,
|
|||
p.add(name, file.content, file.name, file.contentType)
|
||||
|
||||
proc format(p: MultipartData): tuple[contentType, body: string] =
|
||||
if p == nil or p.content == nil or p.content.len == 0:
|
||||
if p == nil or p.content.len == 0:
|
||||
return ("", "")
|
||||
|
||||
# Create boundary that is not in the data to be formatted
|
||||
|
|
|
|||
|
|
@ -1144,7 +1144,7 @@ proc processType(typeName: NimNode, obj: NimNode,
|
|||
result = quote do:
|
||||
(
|
||||
verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`));
|
||||
if `jsonNode`.kind == JNull: nil else: `jsonNode`.str
|
||||
if `jsonNode`.kind == JNull: "" else: `jsonNode`.str
|
||||
)
|
||||
of "biggestint":
|
||||
result = quote do:
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
|
|||
raiseOSError(osLastError())
|
||||
result = newSocket(fd, domain, sockType, protocol, buffered)
|
||||
|
||||
proc parseIPv4Address(address_str: string): IpAddress =
|
||||
proc parseIPv4Address(addressStr: string): IpAddress =
|
||||
## Parses IPv4 adresses
|
||||
## Raises EInvalidValue on errors
|
||||
var
|
||||
|
|
@ -241,15 +241,15 @@ proc parseIPv4Address(address_str: string): IpAddress =
|
|||
|
||||
result.family = IpAddressFamily.IPv4
|
||||
|
||||
for i in 0 .. high(address_str):
|
||||
if address_str[i] in strutils.Digits: # Character is a number
|
||||
for i in 0 .. high(addressStr):
|
||||
if addressStr[i] in strutils.Digits: # Character is a number
|
||||
currentByte = currentByte * 10 +
|
||||
cast[uint16](ord(address_str[i]) - ord('0'))
|
||||
cast[uint16](ord(addressStr[i]) - ord('0'))
|
||||
if currentByte > 255'u16:
|
||||
raise newException(ValueError,
|
||||
"Invalid IP Address. Value is out of range")
|
||||
seperatorValid = true
|
||||
elif address_str[i] == '.': # IPv4 address separator
|
||||
elif addressStr[i] == '.': # IPv4 address separator
|
||||
if not seperatorValid or byteCount >= 3:
|
||||
raise newException(ValueError,
|
||||
"Invalid IP Address. The address consists of too many groups")
|
||||
|
|
@ -265,11 +265,11 @@ proc parseIPv4Address(address_str: string): IpAddress =
|
|||
raise newException(ValueError, "Invalid IP Address")
|
||||
result.address_v4[byteCount] = cast[uint8](currentByte)
|
||||
|
||||
proc parseIPv6Address(address_str: string): IpAddress =
|
||||
proc parseIPv6Address(addressStr: string): IpAddress =
|
||||
## Parses IPv6 adresses
|
||||
## Raises EInvalidValue on errors
|
||||
result.family = IpAddressFamily.IPv6
|
||||
if address_str.len < 2:
|
||||
if addressStr.len < 2:
|
||||
raise newException(ValueError, "Invalid IP Address")
|
||||
|
||||
var
|
||||
|
|
@ -282,7 +282,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
|||
v4StartPos = -1
|
||||
byteCount = 0
|
||||
|
||||
for i,c in address_str:
|
||||
for i,c in addressStr:
|
||||
if c == ':':
|
||||
if not seperatorValid:
|
||||
raise newException(ValueError,
|
||||
|
|
@ -293,7 +293,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
|||
"Invalid IP Address. Address contains more than one \"::\" seperator")
|
||||
dualColonGroup = groupCount
|
||||
seperatorValid = false
|
||||
elif i != 0 and i != high(address_str):
|
||||
elif i != 0 and i != high(addressStr):
|
||||
if groupCount >= 8:
|
||||
raise newException(ValueError,
|
||||
"Invalid IP Address. The address consists of too many groups")
|
||||
|
|
@ -303,11 +303,11 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
|||
groupCount.inc()
|
||||
if dualColonGroup != -1: seperatorValid = false
|
||||
elif i == 0: # only valid if address starts with ::
|
||||
if address_str[1] != ':':
|
||||
if addressStr[1] != ':':
|
||||
raise newException(ValueError,
|
||||
"Invalid IP Address. Address may not start with \":\"")
|
||||
else: # i == high(address_str) - only valid if address ends with ::
|
||||
if address_str[high(address_str)-1] != ':':
|
||||
else: # i == high(addressStr) - only valid if address ends with ::
|
||||
if addressStr[high(addressStr)-1] != ':':
|
||||
raise newException(ValueError,
|
||||
"Invalid IP Address. Address may not end with \":\"")
|
||||
lastWasColon = true
|
||||
|
|
@ -345,7 +345,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
|||
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
|
||||
groupCount.inc()
|
||||
else: # Must parse IPv4 address
|
||||
for i,c in address_str[v4StartPos..high(address_str)]:
|
||||
for i,c in addressStr[v4StartPos..high(addressStr)]:
|
||||
if c in strutils.Digits: # Character is a number
|
||||
currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
|
||||
if currentShort > 255'u32:
|
||||
|
|
@ -386,21 +386,21 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
|||
raise newException(ValueError,
|
||||
"Invalid IP Address. The address consists of too many groups")
|
||||
|
||||
proc parseIpAddress*(address_str: string): IpAddress =
|
||||
proc parseIpAddress*(addressStr: string): IpAddress =
|
||||
## Parses an IP address
|
||||
## Raises EInvalidValue on error
|
||||
if address_str == nil:
|
||||
raise newException(ValueError, "IP Address string is nil")
|
||||
if address_str.contains(':'):
|
||||
return parseIPv6Address(address_str)
|
||||
if addressStr.len == 0:
|
||||
raise newException(ValueError, "IP Address string is empty")
|
||||
if addressStr.contains(':'):
|
||||
return parseIPv6Address(addressStr)
|
||||
else:
|
||||
return parseIPv4Address(address_str)
|
||||
return parseIPv4Address(addressStr)
|
||||
|
||||
proc isIpAddress*(address_str: string): bool {.tags: [].} =
|
||||
proc isIpAddress*(addressStr: string): bool {.tags: [].} =
|
||||
## Checks if a string is an IP address
|
||||
## Returns true if it is, false otherwise
|
||||
try:
|
||||
discard parseIpAddress(address_str)
|
||||
discard parseIpAddress(addressStr)
|
||||
except ValueError:
|
||||
return false
|
||||
return true
|
||||
|
|
@ -587,7 +587,7 @@ when defineSsl:
|
|||
proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar;
|
||||
max_psk_len: cuint): cuint {.cdecl.} =
|
||||
let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX)
|
||||
let hintString = if hint == nil: nil else: $hint
|
||||
let hintString = if hint == nil: "" else: $hint
|
||||
let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
|
||||
if psk.len.cuint > max_psk_len:
|
||||
return 0
|
||||
|
|
@ -657,7 +657,7 @@ when defineSsl:
|
|||
|
||||
proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket,
|
||||
handshake: SslHandshakeType,
|
||||
hostname: string = nil) =
|
||||
hostname: string = "") =
|
||||
## Wraps a connected socket in an SSL context. This function effectively
|
||||
## turns ``socket`` into an SSL socket.
|
||||
## ``hostname`` should be specified so that the client knows which hostname
|
||||
|
|
@ -671,7 +671,7 @@ when defineSsl:
|
|||
wrapSocket(ctx, socket)
|
||||
case handshake
|
||||
of handshakeAsClient:
|
||||
if not hostname.isNil and not isIpAddress(hostname):
|
||||
if hostname.len > 0 and not isIpAddress(hostname):
|
||||
# Discard result in case OpenSSL version doesn't support SNI, or we're
|
||||
# not using TLSv1+
|
||||
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ type
|
|||
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
|
||||
## Initalizes option parses with cmdline. cmdline should not contain
|
||||
## argument 0 - program name.
|
||||
## If cmdline == nil default to current command line arguments.
|
||||
## If cmdline.len == 0 default to current command line arguments.
|
||||
result.remainingShortOptions = ""
|
||||
when not defined(createNimRtl):
|
||||
if cmdline == nil:
|
||||
if cmdline.len == 0:
|
||||
result.cmd = commandLineParams()
|
||||
return
|
||||
else:
|
||||
|
|
@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
|
|||
## and calls initOptParser(openarray[string])
|
||||
## Do not use.
|
||||
if cmdline == "": # backward compatibility
|
||||
return initOptParser(seq[string](nil))
|
||||
return initOptParser(@[])
|
||||
else:
|
||||
return initOptParser(cmdline.split)
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ type
|
|||
kind: XmlEventKind
|
||||
err: XmlErrorKind
|
||||
state: ParserState
|
||||
cIsEmpty: bool
|
||||
filename: string
|
||||
options: set[XmlParseOption]
|
||||
|
||||
|
|
@ -125,7 +126,8 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
|
|||
my.kind = xmlError
|
||||
my.a = ""
|
||||
my.b = ""
|
||||
my.c = nil
|
||||
my.c = ""
|
||||
my.cIsEmpty = true
|
||||
my.options = options
|
||||
|
||||
proc close*(my: var XmlParser) {.inline.} =
|
||||
|
|
@ -482,6 +484,7 @@ proc parseTag(my: var XmlParser) =
|
|||
my.kind = xmlElementOpen
|
||||
my.state = stateAttr
|
||||
my.c = my.a # save for later
|
||||
my.cIsEmpty = false
|
||||
else:
|
||||
my.kind = xmlElementStart
|
||||
let slash = my.buf[my.bufpos] == '/'
|
||||
|
|
@ -490,7 +493,8 @@ proc parseTag(my: var XmlParser) =
|
|||
if slash and my.buf[my.bufpos] == '>':
|
||||
inc(my.bufpos)
|
||||
my.state = stateEmptyElementTag
|
||||
my.c = nil
|
||||
my.c = ""
|
||||
my.cIsEmpty = true
|
||||
elif my.buf[my.bufpos] == '>':
|
||||
inc(my.bufpos)
|
||||
else:
|
||||
|
|
@ -678,7 +682,7 @@ proc next*(my: var XmlParser) =
|
|||
of stateEmptyElementTag:
|
||||
my.state = stateNormal
|
||||
my.kind = xmlElementEnd
|
||||
if not my.c.isNil:
|
||||
if not my.cIsEmpty:
|
||||
my.a = my.c
|
||||
of stateError:
|
||||
my.kind = xmlError
|
||||
|
|
|
|||
|
|
@ -765,7 +765,7 @@ template fillMatches(s, caps, c) =
|
|||
if startIdx != -1:
|
||||
caps[k] = substr(s, startIdx, endIdx)
|
||||
else:
|
||||
caps[k] = nil
|
||||
caps[k] = ""
|
||||
|
||||
proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
|
||||
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
|
||||
|
|
@ -1854,7 +1854,7 @@ when isMainModule:
|
|||
assert match("prefix/start", peg"^start$", 7)
|
||||
|
||||
if "foo" =~ peg"{'a'}?.*":
|
||||
assert matches[0] == nil
|
||||
assert matches[0].len == 0
|
||||
else: assert false
|
||||
|
||||
if "foo" =~ peg"{''}.*":
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ type
|
|||
length: int
|
||||
data: string # != nil if a leaf
|
||||
|
||||
proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
|
||||
proc isConc(r: Rope): bool {.inline.} = return r.length > 0
|
||||
|
||||
# Note that the left and right pointers are not needed for leafs.
|
||||
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
||||
|
|
@ -50,12 +50,12 @@ proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
|
|||
proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
|
||||
## the rope's length
|
||||
if a == nil: result = 0
|
||||
else: result = a.length
|
||||
else: result = abs a.length
|
||||
|
||||
proc newRope(): Rope = new(result)
|
||||
proc newRope(data: string): Rope =
|
||||
new(result)
|
||||
result.length = len(data)
|
||||
result.length = -len(data)
|
||||
result.data = data
|
||||
|
||||
var
|
||||
|
|
@ -129,7 +129,7 @@ proc insertInCache(s: string, tree: Rope): Rope =
|
|||
result.left = t
|
||||
t.right = nil
|
||||
|
||||
proc rope*(s: string = nil): Rope {.rtl, extern: "nro$1Str".} =
|
||||
proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} =
|
||||
## Converts a string to a rope.
|
||||
if s.len == 0:
|
||||
result = nil
|
||||
|
|
@ -170,17 +170,7 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
|
|||
result = a
|
||||
else:
|
||||
result = newRope()
|
||||
result.length = a.length + b.length
|
||||
when false:
|
||||
# XXX rebalancing would be nice, but is too expensive.
|
||||
result.left = a.left
|
||||
var x = newRope()
|
||||
x.left = a.right
|
||||
x.right = b
|
||||
result.right = x
|
||||
else:
|
||||
result.left = a
|
||||
result.right = b
|
||||
result.length = abs(a.length) + abs(b.length)
|
||||
|
||||
proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
|
||||
## the concatenation operator for ropes.
|
||||
|
|
@ -229,7 +219,6 @@ iterator leaves*(r: Rope): string =
|
|||
stack.add(it.right)
|
||||
it = it.left
|
||||
assert(it != nil)
|
||||
assert(it.data != nil)
|
||||
yield it.data
|
||||
|
||||
iterator items*(r: Rope): char =
|
||||
|
|
@ -250,54 +239,6 @@ proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}=
|
|||
result = newStringOfCap(r.len)
|
||||
for s in leaves(r): add(result, s)
|
||||
|
||||
when false:
|
||||
# Format string caching seems reasonable: All leaves can be shared and format
|
||||
# string parsing has to be done only once. A compiled format string is stored
|
||||
# as a rope. A negative length is used for the index into the args array.
|
||||
proc compiledArg(idx: int): Rope =
|
||||
new(result)
|
||||
result.length = -idx
|
||||
|
||||
proc compileFrmt(frmt: string): Rope =
|
||||
var i = 0
|
||||
var length = len(frmt)
|
||||
result = nil
|
||||
var num = 0
|
||||
while i < length:
|
||||
if frmt[i] == '$':
|
||||
inc(i)
|
||||
case frmt[i]
|
||||
of '$':
|
||||
add(result, "$")
|
||||
inc(i)
|
||||
of '#':
|
||||
inc(i)
|
||||
add(result, compiledArg(num+1))
|
||||
inc(num)
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if frmt[i] notin {'0'..'9'}: break
|
||||
add(s, compiledArg(j))
|
||||
of '{':
|
||||
inc(i)
|
||||
var j = 0
|
||||
while frmt[i] in {'0'..'9'}:
|
||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if frmt[i] == '}': inc(i)
|
||||
else: raise newException(EInvalidValue, "invalid format string")
|
||||
add(s, compiledArg(j))
|
||||
else: raise newException(EInvalidValue, "invalid format string")
|
||||
var start = i
|
||||
while i < length:
|
||||
if frmt[i] != '$': inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
add(result, substr(frmt, start, i-1))
|
||||
|
||||
proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
|
||||
rtl, extern: "nroFormat".} =
|
||||
## `%` substitution operator for ropes. Does not support the ``$identifier``
|
||||
|
|
|
|||
|
|
@ -119,8 +119,7 @@ proc newSmtp*(useSsl = false, debug=false,
|
|||
when compiledWithSsl:
|
||||
sslContext.wrapSocket(result.sock)
|
||||
else:
|
||||
raise newException(SystemError,
|
||||
"SMTP module compiled without SSL support")
|
||||
{.error: "SMTP module compiled without SSL support".}
|
||||
|
||||
proc newAsyncSmtp*(useSsl = false, debug=false,
|
||||
sslContext = defaultSslContext): AsyncSmtp =
|
||||
|
|
@ -133,8 +132,7 @@ proc newAsyncSmtp*(useSsl = false, debug=false,
|
|||
when compiledWithSsl:
|
||||
sslContext.wrapSocket(result.sock)
|
||||
else:
|
||||
raise newException(SystemError,
|
||||
"SMTP module compiled without SSL support")
|
||||
{.error: "SMTP module compiled without SSL support".}
|
||||
|
||||
proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] =
|
||||
var retFuture = newFuture[void]()
|
||||
|
|
|
|||
|
|
@ -377,7 +377,10 @@ when not defined(js):
|
|||
|
||||
proc ssClose(s: Stream) =
|
||||
var s = StringStream(s)
|
||||
s.data = nil
|
||||
when defined(nimNoNilSeqs):
|
||||
s.data = ""
|
||||
else:
|
||||
s.data = nil
|
||||
|
||||
proc newStringStream*(s: string = ""): StringStream =
|
||||
## creates a new stream from the string `s`.
|
||||
|
|
|
|||
|
|
@ -358,9 +358,6 @@ proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl,
|
|||
|
||||
proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} =
|
||||
## Checks if `s` is nil or consists entirely of whitespace characters.
|
||||
if len(s) == 0:
|
||||
return true
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
if not c.isSpaceAscii():
|
||||
|
|
@ -1378,9 +1375,11 @@ proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.n
|
|||
if sub == s[i]: return i
|
||||
else:
|
||||
when hasCStringBuiltin:
|
||||
let found = c_memchr(s[start].unsafeAddr, sub, last-start+1)
|
||||
if not found.isNil:
|
||||
return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
|
||||
let L = last-start+1
|
||||
if L > 0:
|
||||
let found = c_memchr(s[start].unsafeAddr, sub, L)
|
||||
if not found.isNil:
|
||||
return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
|
||||
else:
|
||||
for i in start..last:
|
||||
if sub == s[i]: return i
|
||||
|
|
@ -1527,7 +1526,7 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
|||
elif subLen == 1:
|
||||
# when the pattern is a single char, we use a faster
|
||||
# char-based search that doesn't need a skip table:
|
||||
var c = sub[0]
|
||||
let c = sub[0]
|
||||
let last = s.high
|
||||
var i = 0
|
||||
while true:
|
||||
|
|
|
|||
|
|
@ -176,10 +176,7 @@ method suiteEnded*(formatter: OutputFormatter) {.base, gcsafe.} =
|
|||
discard
|
||||
|
||||
proc addOutputFormatter*(formatter: OutputFormatter) =
|
||||
if formatters == nil:
|
||||
formatters = @[formatter]
|
||||
else:
|
||||
formatters.add(formatter)
|
||||
formatters.add(formatter)
|
||||
|
||||
proc newConsoleOutputFormatter*(outputLevel: OutputLevel = PRINT_ALL,
|
||||
colorOutput = true): ConsoleOutputFormatter =
|
||||
|
|
@ -225,7 +222,7 @@ method testStarted*(formatter: ConsoleOutputFormatter, testName: string) =
|
|||
formatter.isInTest = true
|
||||
|
||||
method failureOccurred*(formatter: ConsoleOutputFormatter, checkpoints: seq[string], stackTrace: string) =
|
||||
if stackTrace != nil:
|
||||
if stackTrace.len > 0:
|
||||
echo stackTrace
|
||||
let prefix = if formatter.isInSuite: " " else: ""
|
||||
for msg in items(checkpoints):
|
||||
|
|
@ -236,7 +233,7 @@ method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) =
|
|||
|
||||
if formatter.outputLevel != PRINT_NONE and
|
||||
(formatter.outputLevel == PRINT_ALL or testResult.status == FAILED):
|
||||
let prefix = if testResult.suiteName != nil: " " else: ""
|
||||
let prefix = if testResult.suiteName.len > 0: " " else: ""
|
||||
template rawPrint() = echo(prefix, "[", $testResult.status, "] ", testResult.testName)
|
||||
when not defined(ECMAScript):
|
||||
if formatter.colorOutput and not defined(ECMAScript):
|
||||
|
|
@ -301,7 +298,7 @@ method failureOccurred*(formatter: JUnitOutputFormatter, checkpoints: seq[string
|
|||
## ``stackTrace`` is provided only if the failure occurred due to an exception.
|
||||
## ``checkpoints`` is never ``nil``.
|
||||
formatter.testErrors.add(checkpoints)
|
||||
if stackTrace != nil:
|
||||
if stackTrace.len > 0:
|
||||
formatter.testStackTrace = stackTrace
|
||||
|
||||
method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) =
|
||||
|
|
@ -392,7 +389,7 @@ proc shouldRun(currentSuiteName, testName: string): bool =
|
|||
return false
|
||||
|
||||
proc ensureInitialized() =
|
||||
if formatters == nil:
|
||||
if formatters.len == 0:
|
||||
formatters = @[OutputFormatter(defaultConsoleFormatter())]
|
||||
|
||||
if not disabledParamFiltering and not testsFilters.isValid:
|
||||
|
|
@ -507,7 +504,7 @@ template test*(name, body) {.dirty.} =
|
|||
if testStatusIMPL == FAILED:
|
||||
programResult += 1
|
||||
let testResult = TestResult(
|
||||
suiteName: when declared(testSuiteName): testSuiteName else: nil,
|
||||
suiteName: when declared(testSuiteName): testSuiteName else: "",
|
||||
testName: name,
|
||||
status: testStatusIMPL
|
||||
)
|
||||
|
|
@ -555,7 +552,7 @@ template fail* =
|
|||
when declared(stackTrace):
|
||||
formatter.failureOccurred(checkpoints, stackTrace)
|
||||
else:
|
||||
formatter.failureOccurred(checkpoints, nil)
|
||||
formatter.failureOccurred(checkpoints, "")
|
||||
|
||||
when not defined(ECMAScript):
|
||||
if abortOnError: quit(programResult)
|
||||
|
|
|
|||
|
|
@ -217,9 +217,9 @@ proc createAttribute*(doc: PDocument, name: string): PAttr =
|
|||
new(attrNode)
|
||||
attrNode.fName = name
|
||||
attrNode.fNodeName = name
|
||||
attrNode.fLocalName = nil
|
||||
attrNode.prefix = nil
|
||||
attrNode.fNamespaceURI = nil
|
||||
attrNode.fLocalName = ""
|
||||
attrNode.prefix = ""
|
||||
attrNode.fNamespaceURI = ""
|
||||
attrNode.value = ""
|
||||
attrNode.fSpecified = false
|
||||
return attrNode
|
||||
|
|
@ -254,7 +254,7 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
|
|||
attrNode.prefix = qualifiedName.split(':')[0]
|
||||
attrNode.fLocalName = qualifiedName.split(':')[1]
|
||||
else:
|
||||
attrNode.prefix = nil
|
||||
attrNode.prefix = ""
|
||||
attrNode.fLocalName = qualifiedName
|
||||
attrNode.value = ""
|
||||
|
||||
|
|
@ -298,9 +298,9 @@ proc createElement*(doc: PDocument, tagName: string): PElement =
|
|||
new(elNode)
|
||||
elNode.fTagName = tagName
|
||||
elNode.fNodeName = tagName
|
||||
elNode.fLocalName = nil
|
||||
elNode.prefix = nil
|
||||
elNode.fNamespaceURI = nil
|
||||
elNode.fLocalName = ""
|
||||
elNode.prefix = ""
|
||||
elNode.fNamespaceURI = ""
|
||||
elNode.childNodes = @[]
|
||||
elNode.attributes = @[]
|
||||
|
||||
|
|
@ -332,7 +332,7 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin
|
|||
elNode.prefix = qualifiedName.split(':')[0]
|
||||
elNode.fLocalName = qualifiedName.split(':')[1]
|
||||
else:
|
||||
elNode.prefix = nil
|
||||
elNode.prefix = ""
|
||||
elNode.fLocalName = qualifiedName
|
||||
elNode.fNamespaceURI = namespaceURI
|
||||
elNode.childNodes = @[]
|
||||
|
|
@ -893,22 +893,22 @@ proc tagName*(el: PElement): string =
|
|||
proc getAttribute*(el: PNode, name: string): string =
|
||||
## Retrieves an attribute value by ``name``
|
||||
if isNil(el.attributes):
|
||||
return nil
|
||||
return ""
|
||||
var attribute = el.attributes.getNamedItem(name)
|
||||
if not isNil(attribute):
|
||||
return attribute.value
|
||||
else:
|
||||
return nil
|
||||
return ""
|
||||
|
||||
proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string =
|
||||
## Retrieves an attribute value by ``localName`` and ``namespaceURI``
|
||||
if isNil(el.attributes):
|
||||
return nil
|
||||
return ""
|
||||
var attribute = el.attributes.getNamedItemNS(namespaceURI, localName)
|
||||
if not isNil(attribute):
|
||||
return attribute.value
|
||||
else:
|
||||
return nil
|
||||
return ""
|
||||
|
||||
proc getAttributeNode*(el: PElement, name: string): PAttr =
|
||||
## Retrieves an attribute node by ``name``
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ proc loadXMLStream*(stream: Stream): PDocument =
|
|||
## a ``PDocument``
|
||||
|
||||
var x: XmlParser
|
||||
open(x, stream, nil, {reportComments})
|
||||
open(x, stream, "", {reportComments})
|
||||
|
||||
var xmlDoc: PDocument
|
||||
var dom: PDOMImplementation = getDOM()
|
||||
|
|
@ -161,7 +161,7 @@ when not defined(testing) and isMainModule:
|
|||
#echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
|
||||
#echo(xml.getElementsByTagName("test")[0].namespaceURI)
|
||||
for i in items(xml.getElementsByTagName("*")):
|
||||
if i.namespaceURI != nil:
|
||||
if i.namespaceURI.len > 0:
|
||||
echo(i.nodeName, "=", i.namespaceURI)
|
||||
|
||||
|
||||
|
|
|
|||
146
lib/system.nim
146
lib/system.nim
|
|
@ -484,141 +484,103 @@ type
|
|||
raise_id: uint # set when exception is raised
|
||||
up: ref Exception # used for stacking exceptions. Not exported!
|
||||
|
||||
SystemError* = object of Exception ## \
|
||||
## Abstract class for exceptions that the runtime system raises.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
IOError* = object of SystemError ## \
|
||||
Defect* = object of Exception ## \
|
||||
## Abstract base class for all exceptions that Nim's runtime raises
|
||||
## but that are strictly uncatchable as they can also be mapped to
|
||||
## a ``quit`` / ``trap`` / ``exit`` operation.
|
||||
|
||||
CatchableError* = object of Exception ## \
|
||||
## Abstract class for all exceptions that are catchable.
|
||||
IOError* = object of CatchableError ## \
|
||||
## Raised if an IO error occurred.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
EOFError* = object of IOError ## \
|
||||
## Raised if an IO "end of file" error occurred.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
OSError* = object of SystemError ## \
|
||||
OSError* = object of CatchableError ## \
|
||||
## Raised if an operating system service failed.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
errorCode*: int32 ## OS-defined error code describing this error.
|
||||
LibraryError* = object of OSError ## \
|
||||
## Raised if a dynamic library could not be loaded.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
ResourceExhaustedError* = object of SystemError ## \
|
||||
ResourceExhaustedError* = object of CatchableError ## \
|
||||
## Raised if a resource request could not be fulfilled.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
ArithmeticError* = object of Exception ## \
|
||||
ArithmeticError* = object of Defect ## \
|
||||
## Raised if any kind of arithmetic error occurred.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
DivByZeroError* = object of ArithmeticError ## \
|
||||
## Raised for runtime integer divide-by-zero errors.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
|
||||
OverflowError* = object of ArithmeticError ## \
|
||||
## Raised for runtime integer overflows.
|
||||
##
|
||||
## This happens for calculations whose results are too large to fit in the
|
||||
## provided bits. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
AccessViolationError* = object of Exception ## \
|
||||
## provided bits.
|
||||
AccessViolationError* = object of Defect ## \
|
||||
## Raised for invalid memory access errors
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
AssertionError* = object of Exception ## \
|
||||
AssertionError* = object of Defect ## \
|
||||
## Raised when assertion is proved wrong.
|
||||
##
|
||||
## Usually the result of using the `assert() template <#assert>`_. See the
|
||||
## full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
ValueError* = object of Exception ## \
|
||||
## Usually the result of using the `assert() template <#assert>`_.
|
||||
ValueError* = object of Defect ## \
|
||||
## Raised for string and object conversion errors.
|
||||
KeyError* = object of ValueError ## \
|
||||
## Raised if a key cannot be found in a table.
|
||||
##
|
||||
## Mostly used by the `tables <tables.html>`_ module, it can also be raised
|
||||
## by other collection modules like `sets <sets.html>`_ or `strtabs
|
||||
## <strtabs.html>`_. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
OutOfMemError* = object of SystemError ## \
|
||||
## <strtabs.html>`_.
|
||||
OutOfMemError* = object of Defect ## \
|
||||
## Raised for unsuccessful attempts to allocate memory.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
IndexError* = object of Exception ## \
|
||||
IndexError* = object of Defect ## \
|
||||
## Raised if an array index is out of bounds.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
|
||||
FieldError* = object of Exception ## \
|
||||
FieldError* = object of Defect ## \
|
||||
## Raised if a record field is not accessible because its dicriminant's
|
||||
## value does not fit.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
RangeError* = object of Exception ## \
|
||||
RangeError* = object of Defect ## \
|
||||
## Raised if a range check error occurred.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
StackOverflowError* = object of SystemError ## \
|
||||
StackOverflowError* = object of Defect ## \
|
||||
## Raised if the hardware stack used for subroutine calls overflowed.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
ReraiseError* = object of Exception ## \
|
||||
ReraiseError* = object of Defect ## \
|
||||
## Raised if there is no exception to reraise.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
ObjectAssignmentError* = object of Exception ## \
|
||||
ObjectAssignmentError* = object of Defect ## \
|
||||
## Raised if an object gets assigned to its parent's object.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
ObjectConversionError* = object of Exception ## \
|
||||
ObjectConversionError* = object of Defect ## \
|
||||
## Raised if an object is converted to an incompatible object type.
|
||||
## You can use ``of`` operator to check if conversion will succeed.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
FloatingPointError* = object of Exception ## \
|
||||
FloatingPointError* = object of Defect ## \
|
||||
## Base class for floating point exceptions.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
FloatInvalidOpError* = object of FloatingPointError ## \
|
||||
## Raised by invalid operations according to IEEE.
|
||||
##
|
||||
## Raised by ``0.0/0.0``, for example. See the full `exception
|
||||
## hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
## Raised by ``0.0/0.0``, for example.
|
||||
FloatDivByZeroError* = object of FloatingPointError ## \
|
||||
## Raised by division by zero.
|
||||
##
|
||||
## Divisor is zero and dividend is a finite nonzero number. See the full
|
||||
## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
## Divisor is zero and dividend is a finite nonzero number.
|
||||
FloatOverflowError* = object of FloatingPointError ## \
|
||||
## Raised for overflows.
|
||||
##
|
||||
## The operation produced a result that exceeds the range of the exponent.
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
FloatUnderflowError* = object of FloatingPointError ## \
|
||||
## Raised for underflows.
|
||||
##
|
||||
## The operation produced a result that is too small to be represented as a
|
||||
## normal number. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
## normal number.
|
||||
FloatInexactError* = object of FloatingPointError ## \
|
||||
## Raised for inexact results.
|
||||
##
|
||||
## The operation produced a result that cannot be represented with infinite
|
||||
## precision -- for example: ``2.0 / 3.0, log(1.1)``
|
||||
##
|
||||
## **NOTE**: Nim currently does not detect these! See the full
|
||||
## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
DeadThreadError* = object of Exception ## \
|
||||
## **NOTE**: Nim currently does not detect these!
|
||||
DeadThreadError* = object of Defect ## \
|
||||
## Raised if it is attempted to send a message to a dead thread.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
NilAccessError* = object of SystemError ## \
|
||||
NilAccessError* = object of Defect ## \
|
||||
## Raised on dereferences of ``nil`` pointers.
|
||||
##
|
||||
## This is only raised if the ``segfaults.nim`` module was imported!
|
||||
|
||||
when defined(nimNewRuntime):
|
||||
type
|
||||
MoveError* = object of SystemError ## \
|
||||
MoveError* = object of Defect ## \
|
||||
## Raised on attempts to re-sink an already consumed ``sink`` parameter.
|
||||
|
||||
when defined(js) or defined(nimdoc):
|
||||
|
|
@ -2321,9 +2283,9 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
|
|||
inc(i)
|
||||
|
||||
|
||||
proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", deprecated.}
|
||||
proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", deprecated.}
|
||||
proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
|
||||
|
|
@ -2382,8 +2344,12 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} =
|
|||
## Generic equals operator for sequences: relies on a equals operator for
|
||||
## the element type `T`.
|
||||
when nimvm:
|
||||
if x.isNil and y.isNil:
|
||||
return true
|
||||
when not defined(nimNoNil):
|
||||
if x.isNil and y.isNil:
|
||||
return true
|
||||
else:
|
||||
if x.len == 0 and y.len == 0:
|
||||
return true
|
||||
else:
|
||||
when not defined(JS):
|
||||
proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
|
||||
|
|
@ -2520,7 +2486,7 @@ proc `$`*[T: tuple|object](x: T): string =
|
|||
result.add(name)
|
||||
result.add(": ")
|
||||
when compiles($value):
|
||||
when compiles(value.isNil):
|
||||
when value isnot string and value isnot seq and compiles(value.isNil):
|
||||
if value.isNil: result.add "nil"
|
||||
else: result.addQuoted(value)
|
||||
else:
|
||||
|
|
@ -2539,7 +2505,7 @@ proc collectionToString[T](x: T, prefix, separator, suffix: string): string =
|
|||
else:
|
||||
result.add(separator)
|
||||
|
||||
when compiles(value.isNil):
|
||||
when value isnot string and value isnot seq and compiles(value.isNil):
|
||||
# this branch should not be necessary
|
||||
if value.isNil:
|
||||
result.add "nil"
|
||||
|
|
@ -4001,19 +3967,28 @@ when hasAlloc:
|
|||
proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} =
|
||||
## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case,
|
||||
## ``x`` becomes ``@[y]``
|
||||
if x == nil: x = @[y]
|
||||
else: x.add(y)
|
||||
when defined(nimNoNilSeqs):
|
||||
x.add(y)
|
||||
else:
|
||||
if x == nil: x = @[y]
|
||||
else: x.add(y)
|
||||
|
||||
proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} =
|
||||
## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""``
|
||||
if x == nil: x = ""
|
||||
x.add(y)
|
||||
when defined(nimNoNilSeqs):
|
||||
x.add(y)
|
||||
else:
|
||||
if x == nil: x = ""
|
||||
x.add(y)
|
||||
|
||||
proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} =
|
||||
## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that
|
||||
## case, ``x`` becomes ``y``
|
||||
if x == nil: x = y
|
||||
else: x.add(y)
|
||||
when defined(nimNoNilSeqs):
|
||||
x.add(y)
|
||||
else:
|
||||
if x == nil: x = y
|
||||
else: x.add(y)
|
||||
|
||||
proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
|
||||
## generates a tuple constructor expression listing all the local variables
|
||||
|
|
@ -4073,6 +4048,11 @@ proc `==`*(x, y: cstring): bool {.magic: "EqCString", noSideEffect,
|
|||
elif x.isNil or y.isNil: result = false
|
||||
else: result = strcmp(x, y) == 0
|
||||
|
||||
when defined(nimNoNilSeqs2):
|
||||
when not compileOption("nilseqs"):
|
||||
proc `==`*(x: string; y: type(nil)): bool {.error.} = discard
|
||||
proc `==`*(x: type(nil); y: string): bool {.error.} = discard
|
||||
|
||||
template closureScope*(body: untyped): untyped =
|
||||
## Useful when creating a closure in a loop to capture local loop variables by
|
||||
## their current iteration values. Example:
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ proc getStackTrace*(e: ref Exception): string = e.trace
|
|||
proc unhandledException(e: ref Exception) {.
|
||||
compilerproc, asmNoStackFrame.} =
|
||||
var buf = ""
|
||||
if e.msg != nil and e.msg[0] != '\0':
|
||||
if e.msg.len != 0:
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, e.msg)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ proc mnewString(len: int): NimString {.compilerProc.} =
|
|||
|
||||
proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
|
||||
let start = max(start, 0)
|
||||
if s == nil: return nil
|
||||
let len = min(last, s.len-1) - start + 1
|
||||
if len > 0:
|
||||
result = rawNewStringNoInit(len)
|
||||
|
|
@ -109,6 +110,7 @@ proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} =
|
|||
else: result = cstring(addr s.data)
|
||||
|
||||
proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
|
||||
if s == nil: return nil
|
||||
result = copyStrLast(s, start, s.len-1)
|
||||
|
||||
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ proc sexp(s: IdeCmd|TSymKind|PrefixMatch): SexpNode = sexp($s)
|
|||
proc sexp(s: Suggest): SexpNode =
|
||||
# If you change the order here, make sure to change it over in
|
||||
# nim-mode.el too.
|
||||
let qp = if s.qualifiedPath.isNil: @[] else: s.qualifiedPath
|
||||
let qp = if s.qualifiedPath.len == 0: @[] else: s.qualifiedPath
|
||||
result = convertSexp([
|
||||
s.section,
|
||||
TSymKind s.symkind,
|
||||
|
|
@ -176,7 +176,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
|
|||
let dirtyIdx = fileInfoIdx(conf, file, isKnownFile)
|
||||
|
||||
if dirtyfile.len != 0: msgs.setDirtyFile(conf, dirtyIdx, dirtyfile)
|
||||
else: msgs.setDirtyFile(conf, dirtyIdx, nil)
|
||||
else: msgs.setDirtyFile(conf, dirtyIdx, "")
|
||||
|
||||
conf.m.trackPos = newLineInfo(dirtyIdx, line, col)
|
||||
conf.m.trackPosAttached = false
|
||||
|
|
@ -209,7 +209,7 @@ proc executeEpc(cmd: IdeCmd, args: SexpNode;
|
|||
column = args[2].getNum
|
||||
var dirtyfile = ""
|
||||
if len(args) > 3:
|
||||
dirtyfile = args[3].getStr(nil)
|
||||
dirtyfile = args[3].getStr("")
|
||||
execute(cmd, file, dirtyfile, int(line), int(column), graph)
|
||||
|
||||
proc returnEpc(socket: Socket, uid: BiggestInt, s: SexpNode|string,
|
||||
|
|
|
|||
|
|
@ -70,22 +70,22 @@ proc parseCmd(c: string): seq[string] =
|
|||
result = @[]
|
||||
var i = 0
|
||||
var a = ""
|
||||
while true:
|
||||
while i < c.len:
|
||||
setLen(a, 0)
|
||||
# eat all delimiting whitespace
|
||||
while c[i] in {' ', '\t', '\l', '\r'}: inc(i)
|
||||
while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i)
|
||||
if i >= c.len: break
|
||||
case c[i]
|
||||
of '"': raise newException(ValueError, "double quotes not yet supported: " & c)
|
||||
of '\'':
|
||||
var delim = c[i]
|
||||
inc(i) # skip ' or "
|
||||
while c[i] != '\0' and c[i] != delim:
|
||||
while i < c.len and c[i] != delim:
|
||||
add a, c[i]
|
||||
inc(i)
|
||||
if c[i] != '\0': inc(i)
|
||||
of '\0': break
|
||||
if i < c.len: inc(i)
|
||||
else:
|
||||
while c[i] > ' ':
|
||||
while i < c.len and c[i] > ' ':
|
||||
add(a, c[i])
|
||||
inc(i)
|
||||
add(result, a)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ discard """
|
|||
$nimsuggest --tester --maxresults:2 $file
|
||||
>sug $1
|
||||
sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;10;;5;;"";;100;;None
|
||||
sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1575;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None
|
||||
sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1506;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None
|
||||
"""
|
||||
|
||||
import strutils
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
discard """
|
||||
$nimsuggest --tester compiler/nim.nim
|
||||
>def compiler/semexprs.nim:13:50
|
||||
def;;skType;;ast.PSym;;PSym;;*ast.nim;;691;;2;;"";;100
|
||||
>def compiler/semexprs.nim:13:50
|
||||
def;;skType;;ast.PSym;;PSym;;*ast.nim;;691;;2;;"";;100
|
||||
>def compiler/semexprs.nim:25:50
|
||||
def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100
|
||||
>def compiler/semexprs.nim:25:50
|
||||
def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ block: #8399
|
|||
case line[0]
|
||||
of '+', '-': @[]
|
||||
of '$': (let x = await bar(); @[""])
|
||||
else:
|
||||
nil
|
||||
else: @[]
|
||||
|
||||
doAssert(res == @[""])
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ when defined(ssl):
|
|||
var clientCount = 0
|
||||
|
||||
proc sendMessages(client: AsyncSocket) {.async.} =
|
||||
for i in 0 .. <messagesToSend:
|
||||
for i in 0 ..< messagesToSend:
|
||||
await send(client, "Message " & $i & "\c\L")
|
||||
|
||||
proc launchSwarm(port: Port) {.async.} =
|
||||
for i in 0 .. <swarmSize:
|
||||
for i in 0 ..< swarmSize:
|
||||
var sock = newAsyncSocket()
|
||||
var clientContext = newContext(verifyMode = CVerifyNone)
|
||||
clientContext.wrapSocket(sock)
|
||||
|
|
|
|||
|
|
@ -41,16 +41,16 @@ let str2 = "NN"
|
|||
let a = case str1:
|
||||
of "Y": true
|
||||
of "N": false
|
||||
else:
|
||||
else:
|
||||
echo "no good"
|
||||
quit("quiting")
|
||||
|
||||
proc toBool(s: string): bool =
|
||||
proc toBool(s: string): bool =
|
||||
case s:
|
||||
of nil, "": raise newException(ValueError, "Invalid boolean")
|
||||
elif s[0] == 'Y': true
|
||||
elif s[0] == 'N': false
|
||||
else: "error".quit(2)
|
||||
of "": raise newException(ValueError, "Invalid boolean")
|
||||
elif s[0] == 'Y': true
|
||||
elif s[0] == 'N': false
|
||||
else: "error".quit(2)
|
||||
|
||||
|
||||
let b = "NN".toBool()
|
||||
|
|
@ -66,7 +66,7 @@ static:
|
|||
var bb: bool
|
||||
doassert(not compiles(
|
||||
bb = case str2:
|
||||
of nil, "": raise newException(ValueError, "Invalid boolean")
|
||||
of "": raise newException(ValueError, "Invalid boolean")
|
||||
elif str.startsWith("Y"): true
|
||||
elif str.startsWith("N"): false
|
||||
))
|
||||
|
|
@ -94,7 +94,7 @@ doassert(not compiles(
|
|||
bb = case str2:
|
||||
of "Y":
|
||||
raise newException(ValueError, "Invalid Y")
|
||||
true
|
||||
true
|
||||
else: raise newException(ValueError, "Invalid")
|
||||
))
|
||||
|
||||
|
|
@ -103,6 +103,6 @@ doassert(not compiles(
|
|||
bb = case str2:
|
||||
of "Y":
|
||||
"invalid Y".quit(3)
|
||||
true
|
||||
true
|
||||
else: raise newException(ValueError, "Invalid")
|
||||
))
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
discard """
|
||||
targets: "cpp"
|
||||
output: "hello"
|
||||
cmd: "nim cpp --nilseqs:on $file"
|
||||
"""
|
||||
|
||||
# bug #3299
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ discard """
|
|||
type
|
||||
MyPointer = distinct pointer
|
||||
MyString = distinct string
|
||||
MyStringNotNil = distinct (string not nil)
|
||||
MyInt = distinct int
|
||||
|
||||
proc foo(a: MyPointer) =
|
||||
|
|
@ -26,20 +25,6 @@ p = cast[MyPointer](nil)
|
|||
p = nil.MyPointer
|
||||
p = nil
|
||||
|
||||
var c: MyString
|
||||
c = "Test".MyString
|
||||
c = nil.MyString
|
||||
c = nil
|
||||
|
||||
p = nil
|
||||
doAssert(compiles(c = p) == false)
|
||||
|
||||
var n: MyStringNotNil = "Test".MyStringNotNil # Cannot prove warning ...
|
||||
n = "Test".MyStringNotNil
|
||||
doAssert(compiles(n = nil.MyStringNotNil) == false)
|
||||
doAssert(compiles(n = nil.MyStringNotNil) == false)
|
||||
doAssert(compiles(n = nil) == false)
|
||||
|
||||
var i: MyInt
|
||||
i = 1.MyInt
|
||||
doAssert(compiles(i = nil) == false)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ Check passed'''
|
|||
# bug #5628
|
||||
|
||||
proc checkException(ex: ref Exception) =
|
||||
doAssert(ex.name == "ValueError")
|
||||
doAssert(ex.name == cstring"ValueError")
|
||||
doAssert(ex.msg == "SecondException")
|
||||
doAssert(ex.parent != nil)
|
||||
doAssert(ex.parent.name == "KeyError")
|
||||
doAssert(ex.parent.name == cstring"KeyError")
|
||||
doAssert(ex.parent.msg == "FirstException")
|
||||
echo "Check passed"
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ proc parseResponse(): JsonNode =
|
|||
var excMsg = key & "("
|
||||
if (var n=result["key2"]; n != nil):
|
||||
excMsg &= n.str
|
||||
raise newException(SystemError, excMsg)
|
||||
raise newException(CatchableError, excMsg)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ proc DeleteItem[T,D] (n: PNode[T,D], x: int): PNode[T,D] {.inline.} =
|
|||
|
||||
else :
|
||||
result = n.left
|
||||
n.slots = nil
|
||||
n.slots = @[]
|
||||
n.left = nil
|
||||
|
||||
proc internalDelete[T,D] (ANode: PNode[T,D], key: T, Avalue: var D): PNode[T,D] =
|
||||
|
|
@ -200,7 +200,7 @@ proc traceTree[T,D](root: PNode[T,D]) =
|
|||
traceln(space)
|
||||
write stdout, "left: "
|
||||
doTrace(n.left, level+1)
|
||||
for i, el in n.slots :
|
||||
for i, el in n.slots:
|
||||
if el != nil and not isClean(el):
|
||||
traceln(space)
|
||||
traceX(i)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ discard """
|
|||
output: '''(peel: 0, color: 15)
|
||||
(color: 15)
|
||||
17
|
||||
(width: 0.0, taste: nil, color: 13)
|
||||
(width: 0.0, taste: nil, color: 15)
|
||||
(width: 0.0, taste: "", color: 13)
|
||||
(width: 0.0, taste: "", color: 15)
|
||||
cool'''
|
||||
"""
|
||||
|
||||
|
|
@ -11,16 +11,16 @@ cool'''
|
|||
type
|
||||
BaseFruit[T] = object of RootObj
|
||||
color: T
|
||||
|
||||
|
||||
MidLevel[T] = object of BaseFruit[T]
|
||||
|
||||
|
||||
Mango = object of MidLevel[int]
|
||||
peel: int
|
||||
|
||||
|
||||
Peach[X, T, Y] = object of T
|
||||
width: X
|
||||
taste: Y
|
||||
|
||||
|
||||
proc setColor[T](self: var BaseFruit[T]) =
|
||||
self.color = 15
|
||||
|
||||
|
|
|
|||
|
|
@ -48,4 +48,4 @@ for i in 1 .. 10:
|
|||
|
||||
let results = runCallbacks()
|
||||
|
||||
doAssert(expected == results)
|
||||
doAssert(expected == $results)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ var
|
|||
recurse1 = Recurse[int](data: 1, next: recurse2)
|
||||
|
||||
|
||||
doAssert test.name == "Jorden"
|
||||
doAssert test.name == cstring"Jorden"
|
||||
doAssert knight.age == 19
|
||||
doAssert knight.item.price == 50
|
||||
doAssert recurse1.next.next.data == 3
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ block:
|
|||
proc test(): bool =
|
||||
let obj = newJsObject()
|
||||
obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
|
||||
obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == "Result is: 6"
|
||||
obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6"
|
||||
echo test()
|
||||
|
||||
# Test JsObject []()
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ discard """
|
|||
"""
|
||||
|
||||
import macros
|
||||
|
||||
{.experimental: "forLoopMacros".}
|
||||
macro mymacro(): untyped =
|
||||
result = newLit([1, 2, 3])
|
||||
|
||||
|
|
|
|||
|
|
@ -74,14 +74,14 @@ type
|
|||
## nothing prevents you from accessing directly the type of field you want
|
||||
## if you expect only one kind.
|
||||
case kind*: Tparam_kind
|
||||
of PK_EMPTY: nil
|
||||
of PK_EMPTY: discard
|
||||
of PK_INT: int_val*: int
|
||||
of PK_BIGGEST_INT: big_int_val*: BiggestInt
|
||||
of PK_FLOAT: float_val*: float
|
||||
of PK_BIGGEST_FLOAT: big_float_val*: BiggestFloat
|
||||
of PK_STRING: str_val*: string
|
||||
of PK_BOOL: bool_val*: bool
|
||||
of PK_HELP: nil
|
||||
of PK_HELP: discard
|
||||
|
||||
Tcommandline_results* = object of RootObj ## \
|
||||
## Contains the results of the parsing.
|
||||
|
|
@ -319,7 +319,7 @@ proc echo_help*(expected: seq[Tparameter_specification] = @[],
|
|||
|
||||
|
||||
proc parse*(expected: seq[Tparameter_specification] = @[],
|
||||
type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = nil,
|
||||
type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = @[],
|
||||
bad_prefixes = @["-", "--"], end_of_options = "--",
|
||||
quit_on_failure = true): Tcommandline_results =
|
||||
## Parses parameters and returns results.
|
||||
|
|
@ -339,7 +339,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[],
|
|||
##
|
||||
## The args sequence should be the list of parameters passed to your program
|
||||
## without the program binary (usually OSes provide the path to the binary as
|
||||
## the zeroth parameter). If args is nil, the list will be retrieved from the
|
||||
## the zeroth parameter). If args is empty, the list will be retrieved from the
|
||||
## OS.
|
||||
##
|
||||
## If there is any kind of error and quit_on_failure is true, the quit proc
|
||||
|
|
@ -358,7 +358,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[],
|
|||
|
||||
# Prepare the input parameter list, maybe get it from the OS if not available.
|
||||
var args = args
|
||||
if args == nil:
|
||||
if args.len == 0:
|
||||
let total_params = paramCount()
|
||||
#echo "Got no explicit args, retrieving from OS. Count: ", total_params
|
||||
newSeq(args, total_params)
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ proc importHandling(data: JsonNode): THandlingRecord
|
|||
proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord
|
||||
proc importSoul(data: JsonNode): TSoulRecord
|
||||
proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord
|
||||
proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord
|
||||
proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = ""): PSoundRecord
|
||||
|
||||
## this is the only pipe between lobby and main.nim
|
||||
proc getActiveState*(): TGameState =
|
||||
|
|
@ -514,7 +514,7 @@ proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord
|
|||
let expl = data["explode"]
|
||||
result.anim = importAnim(expl, errors)
|
||||
result.sound = importSound(expl, errors, "sound")
|
||||
proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord =
|
||||
proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = ""): PSoundRecord =
|
||||
if data.kind == JObject:
|
||||
checkKey(data, fieldName)
|
||||
result = newSound(data[fieldName].str, errors)
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ proc newGuiContainer*(pos: TVector2f): PGuiContainer =
|
|||
result = newGuiContainer()
|
||||
result.setPosition pos
|
||||
proc free*(container: PGuiContainer) =
|
||||
container.widgets = nil
|
||||
container.buttons = nil
|
||||
container.widgets = @[]
|
||||
container.buttons = @[]
|
||||
proc add*(container: PGuiContainer; widget: PGuiObject) =
|
||||
container.widgets.add(widget)
|
||||
proc add*(container: PGuiContainer; button: PButton) =
|
||||
|
|
|
|||
|
|
@ -44,16 +44,16 @@ import json
|
|||
type
|
||||
|
||||
foo = object
|
||||
thing: string not nil
|
||||
thing: ptr int not nil
|
||||
|
||||
CTS = ref object
|
||||
subs_by_sid: Table[int, foo]
|
||||
|
||||
|
||||
proc parse(cts: CTS, jn: JsonNode) =
|
||||
|
||||
var y = jn.getInt(4523)
|
||||
let ces = foo(
|
||||
thing: jn.getStr("thing")
|
||||
thing: addr y
|
||||
)
|
||||
|
||||
cts.subs_by_sid[0] = ces
|
||||
|
|
@ -63,17 +63,3 @@ proc parse(cts: CTS, jn: JsonNode) =
|
|||
|
||||
proc p(x: proc(){.closure.} not nil) = discard
|
||||
p(proc(){.closure.} = discard)
|
||||
|
||||
# bug #3993
|
||||
|
||||
type
|
||||
List[T] = seq[T] not nil
|
||||
|
||||
proc `^^`[T](v: T, lst: List[T]): List[T] =
|
||||
result = @[v]
|
||||
result.add(lst)
|
||||
|
||||
proc Nil[T](): List[T] = @[]
|
||||
|
||||
when isMainModule:
|
||||
let lst = 1 ^^ 2 ^^ Nil[int]()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
discard """
|
||||
line: 22
|
||||
line: 13
|
||||
errormsg: "type mismatch"
|
||||
"""
|
||||
{.experimental: "notnil".}
|
||||
|
|
@ -8,16 +8,6 @@ type
|
|||
TObj = object
|
||||
x: int
|
||||
|
||||
MyString = string not nil
|
||||
|
||||
#var x: PObj = nil
|
||||
|
||||
proc p(x: string not nil): int =
|
||||
result = 45
|
||||
|
||||
proc q(x: MyString) = discard
|
||||
proc q2(x: string) = discard
|
||||
|
||||
q2(nil)
|
||||
q(nil)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
discard """
|
||||
errormsg: "'y' is provably nil"
|
||||
line:38
|
||||
line:25
|
||||
"""
|
||||
|
||||
import strutils
|
||||
|
|
@ -10,19 +10,6 @@ type
|
|||
TObj = object
|
||||
x, y: int
|
||||
|
||||
type
|
||||
superstring = string not nil
|
||||
|
||||
|
||||
proc q(s: superstring) =
|
||||
echo s
|
||||
|
||||
proc p2() =
|
||||
var a: string = "I am not nil"
|
||||
q(a) # but this should and does not
|
||||
|
||||
p2()
|
||||
|
||||
proc q(x: pointer not nil) =
|
||||
discard
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ discard """
|
|||
# bug #2355
|
||||
type
|
||||
Foo = object
|
||||
foo: string not nil
|
||||
bar: string not nil
|
||||
|
||||
foo: ref int
|
||||
bar: ref int not nil
|
||||
var x: ref int = new(int)
|
||||
# Create instance without initializaing the `bar` field
|
||||
var f = Foo(foo: "foo")
|
||||
var f = Foo(foo: x)
|
||||
echo f.bar.isNil # true
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ type
|
|||
Killer* = object
|
||||
lock: Lock
|
||||
bailed {.guard: lock.}: bool
|
||||
processes {.guard: lock.}: array[0..MAX_WORKERS-1, foreign ptr Process]
|
||||
processes {.guard: lock.}: array[0..MAX_WORKERS-1, ptr Process]
|
||||
|
||||
# Hold a lock for a statement.
|
||||
template hold(lock: Lock, body: untyped) =
|
||||
|
|
@ -32,7 +32,7 @@ proc initKiller*(): Killer =
|
|||
var killer = initKiller()
|
||||
|
||||
# remember that a process has been launched, killing it if we have bailed.
|
||||
proc launched*(process: foreign ptr Process): int {.gcsafe.} =
|
||||
proc launched*(process: ptr Process): int {.gcsafe.} =
|
||||
result = killer.processes.high + 1
|
||||
killer.lock.hold:
|
||||
if killer.bailed:
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ var results: seq[int] = @[]
|
|||
for i in 0 .. durations.high:
|
||||
tasks.add spawn timer(durations[i])
|
||||
|
||||
var index = awaitAny(tasks)
|
||||
var index = blockUntilAny(tasks)
|
||||
while index != -1:
|
||||
results.add ^cast[FlowVar[int]](tasks[index])
|
||||
tasks.del(index)
|
||||
#echo repr results
|
||||
index = awaitAny(tasks)
|
||||
index = blockUntilAny(tasks)
|
||||
|
||||
doAssert results.len == 5
|
||||
doAssert 1000 in results
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
template serializationKey*(s: string) {.pragma.}
|
||||
template defaultValue*(V: typed) {.pragma.}
|
||||
template alternativeKey*(s: string = nil, V: typed) {.pragma.}
|
||||
template alternativeKey*(s: string = "", V: typed) {.pragma.}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ suite "captures":
|
|||
|
||||
let ex2 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
|
||||
check(ex2.captures["foo"] == "foo")
|
||||
check(ex2.captures["bar"] == nil)
|
||||
check(ex2.captures["bar"] == "")
|
||||
|
||||
test "named capture bounds":
|
||||
let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
|
||||
|
|
@ -41,7 +41,7 @@ suite "captures":
|
|||
|
||||
test "named capture table":
|
||||
let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
|
||||
check(ex1.captures.toTable == {"foo" : "foo", "bar" : nil}.toTable())
|
||||
check(ex1.captures.toTable == {"foo" : "foo", "bar" : ""}.toTable())
|
||||
check(ex1.captureBounds.toTable == {"foo" : some(0..2), "bar" : none(Slice[int])}.toTable())
|
||||
check(ex1.captures.toTable("") == {"foo" : "foo", "bar" : ""}.toTable())
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ suite "captures":
|
|||
|
||||
test "capture sequence":
|
||||
let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
|
||||
check(ex1.captures.toSeq == @["foo", nil])
|
||||
check(ex1.captures.toSeq == @["foo", ""])
|
||||
check(ex1.captureBounds.toSeq == @[some(0..2), none(Slice[int])])
|
||||
check(ex1.captures.toSeq("") == @["foo", ""])
|
||||
|
||||
|
|
|
|||
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