Merge branch 'araq-misc' into devel

This commit is contained in:
Araq 2018-08-16 12:30:00 +02:00
commit 2870ca5d71
122 changed files with 772 additions and 882 deletions

View file

@ -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 )

View file

@ -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

View file

@ -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")

View file

@ -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

View file

@ -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)

View file

@ -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")

View file

@ -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)

View file

@ -74,3 +74,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimVmExportFixed")
defineSymbol("nimIncrSeqV3")
defineSymbol("nimAshr")
defineSymbol("nimNoNilSeqs")
defineSymbol("nimNoNilSeqs2")

View file

@ -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:

View file

@ -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()

View file

@ -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)

View file

@ -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()

View file

@ -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 =

View file

@ -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

View file

@ -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:

View file

@ -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 =

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

@ -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)):

View file

@ -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

View file

@ -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:

View file

@ -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))

View file

@ -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

View file

@ -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 =

View file

@ -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 =

View file

@ -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")

View file

@ -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,

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>`_

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -42,6 +42,6 @@ test "arithmetic failure":
expect(ArithmeticError):
err()
expect(ArithmeticError, SystemError):
expect(ArithmeticError, CatchableError):
discard foo()

View file

@ -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) =

View file

@ -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`.

View file

@ -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)

View file

@ -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)

View file

@ -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, "''")

View file

@ -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 =

View file

@ -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

View file

@ -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"().*":

View file

@ -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)

View file

@ -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.

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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()

View file

@ -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:

View file

@ -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") == ">"

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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"{''}.*":

View file

@ -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``

View file

@ -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]()

View file

@ -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`.

View file

@ -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:

View file

@ -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)

View file

@ -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``

View file

@ -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)

View file

@ -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:

View file

@ -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:

View file

@ -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.} =

View file

@ -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,

View file

@ -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)

View file

@ -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

View file

@ -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
"""

View file

@ -37,8 +37,7 @@ block: #8399
case line[0]
of '+', '-': @[]
of '$': (let x = await bar(); @[""])
else:
nil
else: @[]
doAssert(res == @[""])

View file

@ -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)

View file

@ -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")
))

View file

@ -1,6 +1,7 @@
discard """
targets: "cpp"
output: "hello"
cmd: "nim cpp --nilseqs:on $file"
"""
# bug #3299

View file

@ -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)

View file

@ -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"

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -48,4 +48,4 @@ for i in 1 .. 10:
let results = runCallbacks()
doAssert(expected == results)
doAssert(expected == $results)

View file

@ -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

View file

@ -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 []()

View file

@ -12,7 +12,7 @@ discard """
"""
import macros
{.experimental: "forLoopMacros".}
macro mymacro(): untyped =
result = newLit([1, 2, 3])

View file

@ -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)

View file

@ -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)

View file

@ -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) =

View file

@ -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]()

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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.}

View file

@ -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