diff --git a/.travis.yml b/.travis.yml index e9b76bf6a..b07de1df1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 ) diff --git a/changelog.md b/changelog.md index 9ab7a0b72..441b09042 100644 --- a/changelog.md +++ b/changelog.md @@ -63,6 +63,10 @@ - ``lineInfoObj`` now returns absolute path instead of project path. It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc. +- `threadpool`'s `await` and derivatives have been renamed to `blockUntil` + to avoid confusions with `await` from the `async` macro. + + #### Breaking changes in the compiler - The undocumented ``#? braces`` parsing mode was removed. @@ -91,7 +95,7 @@ - Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals. - Added the proc ``math.prod`` for product of elements in openArray. - Added the proc ``parseBinInt`` to parse a binary integer from a string, which returns the value. -- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt`` +- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``. - Added the proc ``flush`` for memory mapped files. - Added the ``MemMapFileStream``. - Added ``macros.copyLineInfo`` to copy lineInfo from other node. @@ -134,7 +138,13 @@ - ``func`` is now an alias for ``proc {.noSideEffect.}``. - In order to make ``for`` loops and iterators more flexible to use Nim now supports so called "for-loop macros". See - the `manual `_ 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 diff --git a/compiler/ast.nim b/compiler/ast.nim index e686160dc..01e70ce75 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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") diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 9712d5dce..2621574a6 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -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 diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 6803a9478..dd1c72ab6 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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) diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 664f89b73..067a60c57 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -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") diff --git a/compiler/commands.nim b/compiler/commands.nim index 866405f9f..1e5384f16 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -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) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 5a62b46ad..0955a84ae 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -74,3 +74,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimVmExportFixed") defineSymbol("nimIncrSeqV3") defineSymbol("nimAshr") + defineSymbol("nimNoNilSeqs") + defineSymbol("nimNoNilSeqs2") diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 8d233566c..b35452365 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -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: diff --git a/compiler/idents.nim b/compiler/idents.nim index 0a2f2d5cf..58800b73d 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -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() diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 63100a68d..462c622aa 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -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) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 4f0c3a778..c5a641713 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -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() diff --git a/compiler/lookups.nim b/compiler/lookups.nim index bab631e6f..1e9d963fa 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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 = diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 334cd1ae6..1eecc4176 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -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.. 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: diff --git a/compiler/options.nim b/compiler/options.nim index 44519ea22..1873d9d5b 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -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 = diff --git a/compiler/parser.nim b/compiler/parser.nim index 5664a9f67..98ccb05b9 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -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) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 2d2aeba76..ebb3a7c1d 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -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 diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index afe60e9dd..a067f2074 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -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: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ce27e1cd9..c3e151f5a 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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)): diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 973f16916..81ee01dbf 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -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 diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index ae7e030b8..f3d6ccfdd 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -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: diff --git a/compiler/sem.nim b/compiler/sem.nim index 427b44e04..6128c02d1 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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)) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index aa5394a71..ef452fcdc 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -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 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index aa0cb6e8e..4189a5214 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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 = diff --git a/compiler/seminst.nim b/compiler/seminst.nim index fac04e3a0..f9d7c3754 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -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 = diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 02c56c035..3056f5d72 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -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") diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 8b639806d..90ab2c57a 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -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, diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6ef03456e..170ac799e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 972c8c709..99f2cf20d 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index ff7cb0bb0..c315cbebb 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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 diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index c665aad7f..f206119ec 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 diff --git a/compiler/types.nim b/compiler/types.nim index 23fbc9f1b..80624502c 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 50235c95f..1abd9ae4a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -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 diff --git a/doc/advopt.txt b/doc/advopt.txt index 685c8127d..150025509 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -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 diff --git a/doc/exception_hierarchy_fragment.txt b/doc/exception_hierarchy_fragment.txt deleted file mode 100644 index a02d9ccef..000000000 --- a/doc/exception_hierarchy_fragment.txt +++ /dev/null @@ -1,28 +0,0 @@ -* `Exception `_ - * `AccessViolationError `_ - * `ArithmeticError `_ - * `DivByZeroError `_ - * `OverflowError `_ - * `AssertionError `_ - * `DeadThreadError `_ - * `FloatingPointError `_ - * `FloatDivByZeroError `_ - * `FloatInexactError `_ - * `FloatInvalidOpError `_ - * `FloatOverflowError `_ - * `FloatUnderflowError `_ - * `FieldError `_ - * `IndexError `_ - * `ObjectAssignmentError `_ - * `ObjectConversionError `_ - * `ValueError `_ - * `KeyError `_ - * `ReraiseError `_ - * `RangeError `_ - * `OutOfMemoryError `_ - * `ResourceExhaustedError `_ - * `StackOverflowError `_ - * `SystemError `_ - * `IOError `_ - * `OSError `_ - * `LibraryError `_ diff --git a/doc/manual.rst b/doc/manual.rst index de0a13143..bb2650799 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -769,8 +769,8 @@ Pre-defined floating point types The following floating point types are pre-defined: ``float`` - the generic floating point type; its size is platform dependent - (the compiler chooses the processor's fastest floating point type). + the generic floating point type; its size used to be platform dependent, + but now it is always mapped to ``float64``. This type should be used in general. floatXX @@ -1507,68 +1507,6 @@ non nilable pointers. The details of this analysis are still to be specified here. -Memory regions --------------- - -The types ``ref`` and ``ptr`` can get an optional ``region`` annotation. -A region has to be an object type. - -Regions are very useful to separate user space and kernel memory in the -development of OS kernels: - -.. code-block:: nim - type - Kernel = object - Userspace = object - - var a: Kernel ptr Stat - var b: Userspace ptr Stat - - # the following does not compile as the pointer types are incompatible: - a = b - -As the example shows ``ptr`` can also be used as a binary -operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``. - -In order to make generic code easier to write ``ptr T`` is a subtype -of ``ptr[R, T]`` for any ``R``. - -Furthermore the subtype relation of the region object types is lifted to -the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be -used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is -not compatible to ``pointer`` to prevent the following from compiling: - -.. code-block:: nim - # from system - proc dealloc(p: pointer) - - # wrap some scripting language - type - PythonsHeap = object - PyObjectHeader = object - rc: int - typ: pointer - PyObject = ptr[PythonsHeap, PyObjectHeader] - - proc createPyObject(): PyObject {.importc: "...".} - proc destroyPyObject(x: PyObject) {.importc: "...".} - - var foo = createPyObject() - # type error here, how convenient: - dealloc(foo) - - -Future directions: - -* Memory regions might become available for ``string`` and ``seq`` too. -* Builtin regions like ``private``, ``global`` and ``local`` might be - useful for an OpenCL target. -* Builtin "regions" can model ``lent`` and ``unique`` pointers. -* An assignment operator can be attached to a region so that proper write - barriers can be generated. This would imply that the GC can be implemented - completely in user-space. - - Procedural type --------------- A procedural type is internally a pointer to a procedure. ``nil`` is @@ -2337,6 +2275,8 @@ pointer type and overloading resolution is tried with ``a[]`` instead. Automatic self insertions ------------------------- +**Note**: The ``.this`` pragma is deprecated and should not be used anymore. + Starting with version 0.14 of the language, Nim supports ``field`` as a shortcut for ``self.field`` comparable to the `this`:idx: keyword in Java or C++. This feature has to be explicitly enabled via a ``{.this: self.}`` @@ -4029,9 +3969,13 @@ exception. Exception hierarchy ------------------- -The exception tree is defined in the `system `_ module: - -.. include:: exception_hierarchy_fragment.txt +The exception tree is defined in the `system `_ 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 diff --git a/doc/nimc.rst b/doc/nimc.rst index 9c81d912f..31df4b6f7 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -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. diff --git a/doc/spawn.txt b/doc/spawn.txt index 522c94464..ab667ff48 100644 --- a/doc/spawn.txt +++ b/doc/spawn.txt @@ -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 diff --git a/examples/tunit.nim b/examples/tunit.nim index 26bcafda1..785b9aa5e 100644 --- a/examples/tunit.nim +++ b/examples/tunit.nim @@ -42,6 +42,6 @@ test "arithmetic failure": expect(ArithmeticError): err() - expect(ArithmeticError, SystemError): + expect(ArithmeticError, CatchableError): discard foo() diff --git a/koch.nim b/koch.nim index aa36d94a1..c302be4ca 100644 --- a/koch.nim +++ b/koch.nim @@ -183,7 +183,7 @@ proc bundleNimbleExe() = bundleNimbleSrc() # now compile Nimble and copy it to $nim/bin for the installer.ini # to pick it up: - nimexec("c -d:release dist/nimble/src/nimble.nim") + nimexec("c -d:release --nilseqs:on dist/nimble/src/nimble.nim") copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe) proc buildNimble(latest: bool) = @@ -210,7 +210,7 @@ proc buildNimble(latest: bool) = else: exec("git checkout -f stable") exec("git pull") - nimexec("c --noNimblePath -p:compiler -d:release " & installDir / "src/nimble.nim") + nimexec("c --noNimblePath -p:compiler --nilseqs:on -d:release " & installDir / "src/nimble.nim") copyExe(installDir / "src/nimble".exe, "bin/nimble".exe) proc bundleNimsuggest(buildExe: bool) = diff --git a/lib/deprecated/pure/actors.nim b/lib/deprecated/pure/actors.nim index 17321cc0e..451668825 100644 --- a/lib/deprecated/pure/actors.nim +++ b/lib/deprecated/pure/actors.nim @@ -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..= 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"().*": diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index f3596b571..4a77b4f34 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -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) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 43a429a17..5b0b6c6ee 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -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 `_. - 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 .. $2 """, [url, text, desc]) else: - result.addf("""
  • $2
  • """, [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("""
  • + result.addf("""
  • $3
  • """, [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. diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 863a6843b..5bf9183ed 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -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" diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index e7552e3e3..71a1600dc 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -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) diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index bfecfe447..545958977 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -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 diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 308f31eae..f85de7546 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -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() diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 6ec71e912..f3b13fac5 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -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: diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index c38c36874..f54fe87f7 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -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") == ">" diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 72de72718..0192e71e7 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -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 diff --git a/lib/pure/json.nim b/lib/pure/json.nim index b9279b18c..69ffb1796 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -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: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 771e7de10..0e56100d9 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -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) diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index b54a56c0c..51a70b6d1 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -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) diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index e0000aad3..fe933fb79 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -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 diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index d16527a56..02a2d6900 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -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"{''}.*": diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 9b9cdb52a..fb371cdce 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -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`` diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index c2c674b84..d9b863a52 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -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]() diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 1ab73faea..09626136f 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -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`. diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index be7ff60a2..33f153587 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -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: diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index aa07a4fa6..757bf4745 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -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) diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index 8cd47aa39..1a9e4ae26 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -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`` diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim index 7c7f7b99c..8d995102e 100644 --- a/lib/pure/xmldomparser.nim +++ b/lib/pure/xmldomparser.nim @@ -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) diff --git a/lib/system.nim b/lib/system.nim index de6e96611..d33344d0a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -484,141 +484,103 @@ type raise_id: uint # set when exception is raised up: ref Exception # used for stacking exceptions. Not exported! - SystemError* = object of Exception ## \ - ## Abstract class for exceptions that the runtime system raises. - ## - ## See the full `exception hierarchy `_. - 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 `_. EOFError* = object of IOError ## \ ## Raised if an IO "end of file" error occurred. - ## - ## See the full `exception hierarchy `_. - OSError* = object of SystemError ## \ + OSError* = object of CatchableError ## \ ## Raised if an operating system service failed. - ## - ## See the full `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 `_. - ResourceExhaustedError* = object of SystemError ## \ + ResourceExhaustedError* = object of CatchableError ## \ ## Raised if a resource request could not be fulfilled. - ## - ## See the full `exception hierarchy `_. - ArithmeticError* = object of Exception ## \ + ArithmeticError* = object of Defect ## \ ## Raised if any kind of arithmetic error occurred. - ## - ## See the full `exception hierarchy `_. DivByZeroError* = object of ArithmeticError ## \ ## Raised for runtime integer divide-by-zero errors. - ## - ## See the full `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 `_. - AccessViolationError* = object of Exception ## \ + ## provided bits. + AccessViolationError* = object of Defect ## \ ## Raised for invalid memory access errors - ## - ## See the full `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 `_. - 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 `_ module, it can also be raised ## by other collection modules like `sets `_ or `strtabs - ## `_. See the full `exception hierarchy `_. - OutOfMemError* = object of SystemError ## \ + ## `_. + OutOfMemError* = object of Defect ## \ ## Raised for unsuccessful attempts to allocate memory. - ## - ## See the full `exception hierarchy `_. - IndexError* = object of Exception ## \ + IndexError* = object of Defect ## \ ## Raised if an array index is out of bounds. - ## - ## See the full `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 `_. - RangeError* = object of Exception ## \ + RangeError* = object of Defect ## \ ## Raised if a range check error occurred. - ## - ## See the full `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 `_. - ReraiseError* = object of Exception ## \ + ReraiseError* = object of Defect ## \ ## Raised if there is no exception to reraise. - ## - ## See the full `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 `_. - 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 `_. - FloatingPointError* = object of Exception ## \ + FloatingPointError* = object of Defect ## \ ## Base class for floating point exceptions. - ## - ## See the full `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 `_. + ## 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 `_. + ## 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 `_. 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 `_. + ## 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 `_. - 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 `_. - 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: diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index e12bab184..8d4a2e482 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -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: diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 19c2c62ad..0e690d832 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -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.} = diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 3ba1120b2..4b5ce0a57 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -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, diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 4cda272af..b962a9f83 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -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) diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim index 25e77ed04..8510162ac 100644 --- a/nimsuggest/tests/tdot4.nim +++ b/nimsuggest/tests/tdot4.nim @@ -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 diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim index 12d40d1e7..0616b7164 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -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 """ diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim index 695dcd98a..dbc2ea434 100644 --- a/tests/async/tasync_misc.nim +++ b/tests/async/tasync_misc.nim @@ -37,8 +37,7 @@ block: #8399 case line[0] of '+', '-': @[] of '$': (let x = await bar(); @[""]) - else: - nil + else: @[] doAssert(res == @[""]) diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim index 3dc131036..0607cf3c6 100644 --- a/tests/async/tasyncssl.nim +++ b/tests/async/tasyncssl.nim @@ -15,11 +15,11 @@ when defined(ssl): var clientCount = 0 proc sendMessages(client: AsyncSocket) {.async.} = - for i in 0 .. foo)(?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)(?bar)?")) @@ -41,7 +41,7 @@ suite "captures": test "named capture table": let ex1 = "foo".find(re("(?foo)(?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)(?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", ""]) diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim index 516fd4328..b762271a2 100644 --- a/tests/stdlib/nre/replace.nim +++ b/tests/stdlib/nre/replace.nim @@ -16,5 +16,5 @@ suite "replace": check("123".replace(re"(?\d)(\d)", "${foo}$#$#") == "1123") test "replacing missing captures should throw instead of segfaulting": - expect ValueError: discard "ab".replace(re"(a)|(b)", "$1$2") - expect ValueError: discard "b".replace(re"(a)?(b)", "$1$2") + discard "ab".replace(re"(a)|(b)", "$1$2") + discard "b".replace(re"(a)?(b)", "$1$2") diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index c0b4d5f78..bf0bb3ea7 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -40,7 +40,7 @@ when isMainModule: test: 18827361, test2: "hello world", test3: true, - testNil: nil + testNil: "nil" ) let node = %x @@ -53,7 +53,7 @@ when isMainModule: doAssert y.test == 18827361 doAssert y.test2 == "hello world" doAssert y.test3 - doAssert y.testNil.isNil + doAssert y.testNil == "nil" # Test for custom object variants (without an enum) and with an else branch. block: diff --git a/tests/stdlib/tnilecho.nim b/tests/stdlib/tnilecho.nim index 147b5e492..ec8d71dab 100644 --- a/tests/stdlib/tnilecho.nim +++ b/tests/stdlib/tnilecho.nim @@ -1,2 +1,6 @@ -var x = @["1", nil, "3"] -doAssert $x == "@[1, nil, 3]" +discard """ + output: "" +""" + +var x = @["1", "", "3"] +doAssert $x == """@["1", "", "3"]""" diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim index ce059b7b0..5e4a1b317 100644 --- a/tests/system/tnilconcats.nim +++ b/tests/system/tnilconcats.nim @@ -1,5 +1,5 @@ discard """ - output: '''@[nil, nil, nil, nil, nil, nil, nil, "meh"]''' + output: '''@["", "", "", "", "", "", "", "meh"]''' exitcode: "0" """ diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index 9a6b83f95..99299f203 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -26,8 +26,8 @@ doAssert "nan" == $(0.0/0.0) var x: seq[string] doAssert "nil" == $(x) -var y: string = nil -doAssert nil == $(y) +var y: string +doAssert "" == $(y) type Foo = object @@ -54,7 +54,7 @@ doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', ' doAssert $cstring(unsafeAddr arr) == "Hello World!" proc takes(c: cstring) = - doAssert c == "" + doAssert c == cstring"" proc testm() = var x: string @@ -90,12 +90,8 @@ proc stringCompare() = doAssert e == "" doAssert "" == e - doAssert nil == e - doAssert e == nil doAssert f == g doAssert "" == "" - doAssert "" == nil - doAssert nil == "" g.setLen(10) doAssert g == "\0\0\0\0\0\0\0\0\0\0" diff --git a/tests/template/mgensym_generic_cross_module.nim b/tests/template/mgensym_generic_cross_module.nim index 80b681db4..ea88f67e6 100644 --- a/tests/template/mgensym_generic_cross_module.nim +++ b/tests/template/mgensym_generic_cross_module.nim @@ -1,6 +1,6 @@ -template makeDomElement(x: untyped, name: string = nil) = - const tag {.gensym.} = if name == nil: astToStr(x) else: name +template makeDomElement(x: untyped, name: string = "") = + const tag {.gensym.} = if name.len == 0: astToStr(x) else: name proc x*(p: int|float) = echo tag, p diff --git a/tests/template/tdefault_nil.nim b/tests/template/tdefault_nil.nim index c5c372d9e..311a6c090 100644 --- a/tests/template/tdefault_nil.nim +++ b/tests/template/tdefault_nil.nim @@ -2,7 +2,7 @@ # bug #2629 import sequtils, os -template glob_rst(basedir: string = nil): untyped = +template glob_rst(basedir: string = ""): untyped = if baseDir.isNil: to_seq(walk_files("*.rst")) else: diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index fca6927d4..2c55bd0bd 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -260,6 +260,8 @@ proc jsTests(r: var TResults, cat: Category, options: string) = # ------------------------- nim in action ----------- proc testNimInAction(r: var TResults, cat: Category, options: string) = + let options = options & " --nilseqs:on" + template test(filename: untyped, action: untyped) = testSpec r, makeTest(filename, options, cat, action) @@ -488,7 +490,9 @@ proc processCategory(r: var TResults, cat: Category, options: string) = of "js": # only run the JS tests on Windows or Linux because Travis is bad # and other OSes like Haiku might lack nodejs: - when defined(linux) or defined(windows): + if not defined(linux) and isTravis: + discard + else: jsTests(r, cat, options) of "dll": dllTests(r, cat, options) diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index ac79e3942..fbe930a4f 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -12,8 +12,8 @@ import parseutils, strutils, os, osproc, streams, parsecfg var compilerPrefix* = "compiler" / "nim " -let isTravis = existsEnv("TRAVIS") -let isAppVeyor = existsEnv("APPVEYOR") +let isTravis* = existsEnv("TRAVIS") +let isAppVeyor* = existsEnv("APPVEYOR") proc cmdTemplate*(): string = compilerPrefix & "$target --lib:lib --hints:on -d:testing $options $file" diff --git a/tests/threads/tactors.nim b/tests/threads/tactors.nim index 45a03ebb7..ea052b9bd 100644 --- a/tests/threads/tactors.nim +++ b/tests/threads/tactors.nim @@ -5,9 +5,9 @@ discard """ import actors var - pool: TActorPool[int, void] + pool: ActorPool[int, void] createActorPool(pool) -for i in 0 .. < 300: +for i in 0 ..< 300: pool.spawn(i, proc (x: int) {.thread.} = echo x) pool.join() diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim index ec48337bd..e09c53407 100644 --- a/tests/tuples/tuple_with_nil.nim +++ b/tests/tuples/tuple_with_nil.nim @@ -73,7 +73,7 @@ type const DefaultPrec = 6 ## Default precision for floating point numbers. - DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil) + DefaultFmt: Format = (ftDefault, -1, -1, "", faDefault, fsMinus, false, false, false, "") ## Default format corresponding to the empty format string, i.e. ## `x.format("") == x.format(DefaultFmt)`. round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005] @@ -124,7 +124,7 @@ proc parse(fmt: string): Format {.nosideeffect.} = if fmt.rawmatch(p, 0, caps) < 0: raise newException(FormatError, "Invalid format string") - result.fill = fmt.get(caps, 0, nil) + result.fill = fmt.get(caps, 0, "") case fmt.get(caps, 1, 0.char) of '<': result.align = faLeft @@ -144,7 +144,7 @@ proc parse(fmt: string): Format {.nosideeffect.} = result.width = fmt.get(caps, 4, -1) if caps.has(4) and fmt[caps.bounds(4).first] == '0': - if result.fill != nil: + if result.fill != "": raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character") if result.align != faDefault: raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment") @@ -171,7 +171,7 @@ proc parse(fmt: string): Format {.nosideeffect.} = of '%': result.typ = ftPercent else: result.typ = ftDefault - result.arysep = fmt.get(caps, 8, nil, 1) + result.arysep = fmt.get(caps, 8, "", 1) proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} = ## Returns the number of left and right padding characters for a @@ -218,7 +218,7 @@ proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) = elif fmt.sign == fsPlus: write(o, '+') elif fmt.sign == fsSpace: write(o, ' ') - if fmt.fill == nil: + if fmt.fill.len == 0: for i in 1..n: write(o, ' ') else: for i in 1..n: @@ -626,19 +626,19 @@ proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} = else: lvl.dec let clpos = pos - var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested) + var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: "", index: int.high, nested: nested) if fmtpart.fmt.len > 0: var m: array[0..3, string] if not fmtpart.fmt.match(subpeg, m): error("invalid format string") - if m[1] != nil and m[1].len > 0: + if m[1].len > 0: fmtpart.field = m[1].substr(1) - if m[2] != nil and m[2].len > 0: + if m[2].len > 0: discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index) if m[0].len > 0: discard parseInt(m[0], fmtpart.arg) - if m[3] == nil or m[3].len == 0: + if m[3].len == 0: fmtpart.fmt = "" elif m[3][0] == ':': fmtpart.fmt = m[3].substr(1) @@ -650,7 +650,7 @@ proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} = proc literal(s: string): NimNode {.compiletime, nosideeffect.} = ## Return the nim literal of string `s`. This handles the case if ## `s` is nil. - result = if s == nil: newNilLit() else: newLit(s) + result = newLit(s) proc literal(b: bool): NimNode {.compiletime, nosideeffect.} = ## Return the nim literal of boolean `b`. This is either `true` @@ -713,7 +713,7 @@ proc generatefmt(fmtstr: string; args[arg].cnt = args[arg].cnt + 1 arg.inc # possible field access - if part.field != nil and part.field.len > 0: + if part.field.len > 0: argexpr = newDotExpr(argexpr, part.field.ident) # possible array access if part.index < int.high: @@ -724,7 +724,7 @@ proc generatefmt(fmtstr: string; # nested format string. Compute the format string by # concatenating the parts of the substring. for e in generatefmt(part.fmt, args, arg): - var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt) + var newexpr = if part.fmt.len == 0: e.val else: newCall(bindsym"format", e.val, e.fmt) if fmtexpr != nil and fmtexpr.kind != nnkNilLit: fmtexpr = infix(fmtexpr, "&", newexpr) else: diff --git a/tests/tuples/tuple_with_seq.nim b/tests/tuples/tuple_with_seq.nim index 39edb500f..00b07dd2c 100644 --- a/tests/tuples/tuple_with_seq.nim +++ b/tests/tuples/tuple_with_seq.nim @@ -3,8 +3,8 @@ discard """ @[1, 2, 3]''' """ -template foo(s: string = nil) = - if isNil(s): +template foo(s: string = "") = + if s.len == 0: echo "it's nil" else: echo s diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim index 834f63729..28c3b87b8 100644 --- a/tests/types/temptyseqs.nim +++ b/tests/types/temptyseqs.nim @@ -22,7 +22,7 @@ when true: import os type - In_out = tuple[src, dest, options: string] + In_out = tuple[src, dest: string, options: ref int] let nil_var: In_out = ("hey"/"there", "something", nil) diff --git a/tests/vm/meta.nim b/tests/vm/meta.nim index 2aa01b5b3..32a441f27 100644 --- a/tests/vm/meta.nim +++ b/tests/vm/meta.nim @@ -39,7 +39,7 @@ proc newIdent*(node: NimNode): Ident = raise newException(ValueError, msg) proc render*(i: Ident): NimNode {.compileTime.} = - if i.name == nil: + if i.name == "": return newNimNode(nnkEmpty) if i.exported: @@ -67,7 +67,7 @@ proc newBracket*(node: NimNode): Bracket = raise newException(ValueError, msg) # Field procs -proc newField*(identifier: Ident, type_name: string, default: string = nil): Field = +proc newField*(identifier: Ident, type_name: string, default: string = ""): Field = result.identifier = identifier result.type_name = type_name result.default = default @@ -84,7 +84,7 @@ proc newField*(node: NimNode): Field = of nnkIdent: result.default = $(node[2]) else: - result.default = nil + result.default = "" else: let msg = "newField cannot initialize from node kind: " & $(node.kind) raise newException(ValueError, msg) @@ -102,7 +102,7 @@ proc newFieldSeq*(node: NimNode): FieldSeq = of nnkIdent: default = $(default_node) else: - default = nil + default = "" for i in 0..node.len - 3: let name = newIdent(node[i]) result.add(newField(name, type_name, default)) @@ -115,8 +115,8 @@ proc newFieldSeq*(node: NimNode): FieldSeq = proc render*(f: Field): NimNode {.compileTime.} = let identifier = f.identifier.render() - let type_name = if f.type_name != nil: ident(f.type_name) else: newEmptyNode() - let default = if f.default != nil: ident(f.default) else: newEmptyNode() + let type_name = if f.type_name != "": ident(f.type_name) else: newEmptyNode() + let default = if f.default != "": ident(f.default) else: newEmptyNode() newIdentDefs(identifier, type_name, default) proc render*(fs: FieldSeq): NimNode {.compileTime.} = @@ -127,7 +127,7 @@ proc render*(fs: FieldSeq): NimNode {.compileTime.} = # TypeDef procs proc newTypeDef*(identifier: Ident, is_ref = false, object_type = "object", - base_type: string = nil): TypeDef {.compileTime.} = + base_type: string = ""): TypeDef {.compileTime.} = result.identifier = identifier result.fields = @[] result.is_ref = is_ref @@ -165,7 +165,7 @@ proc render*(typedef: TypeDef): NimNode {.compileTime.} = result.add(newEmptyNode()) let object_node = newNimNode(nnkObjectTy) object_node.add(newEmptyNode()) - if typedef.base_type == nil: + if typedef.base_type == "": object_node.add(newEmptyNode()) else: var base_type = newNimNode(nnkOfInherit) @@ -195,8 +195,8 @@ proc render*(typeseq: TypeDefSeq): NimNode {.compileTime.} = for typedef in typeseq: result.add(typedef.render()) -proc newProc*(identifier: Ident, params: FieldSeq = nil, - returns: Ident, generics: FieldSeq = nil): Proc = +proc newProc*(identifier: Ident, params: FieldSeq = @[], + returns: Ident, generics: FieldSeq = @[]): Proc = result.identifier = identifier result.params = params result.returns = returns @@ -209,7 +209,7 @@ proc newProc*(node: NimNode): Proc = case node[2].kind: of nnkGenericParams: result.generics = newFieldSeq(node[2]) - else: result.generics = nil + else: result.generics = @[] let formal_params = node[3] case formal_params[0].kind: of nnkIdent: diff --git a/tests/vm/tcomponent.nim b/tests/vm/tcomponent.nim index e7962e7ab..b509bc5d7 100644 --- a/tests/vm/tcomponent.nim +++ b/tests/vm/tcomponent.nim @@ -11,7 +11,7 @@ FOO: blah''' import macros, sequtils, tables import strutils -import future, meta +import sugar, meta type Component = object diff --git a/tests/vm/tseq_badinit.nim b/tests/vm/tseq_badinit.nim index 15889d60e..5fa223c85 100644 --- a/tests/vm/tseq_badinit.nim +++ b/tests/vm/tseq_badinit.nim @@ -22,14 +22,14 @@ template test(typename, default: untyped) = result = newSeq[typename]() result.add(default) result.setLen(3) - for i in 0 .. <2: + for i in 0 ..< 2: result[i] = default const constval = `abc typename`() doAssert(constval == `abc typename`()) proc `arr typename`(): array[4, typename] = - for i in 0 .. <2: + for i in 0 ..< 2: result[i] = default const constarr = `arr typename`() doAssert(constarr == `arr typename`()) diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim index 39e4040dc..df408910e 100644 --- a/tests/vm/tstringnil.nim +++ b/tests/vm/tstringnil.nim @@ -20,16 +20,16 @@ proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: NimNode): tuple[tests: var testObj = SuiteTest() if suiteName.kind == nnkNilLit: - testObj.suiteName = nil + testObj.suiteName = "" else: testObj.suiteName = $suiteName if suiteDesc.kind == nnkNilLit: - testObj.suiteDesc = nil + testObj.suiteDesc = "" else: testObj.suiteDesc = suiteDesc.strVal testObj.testName = $child[1] # should not ever be nil if child[2].kind == nnkNilLit: - testObj.testDesc = nil + testObj.testDesc = "" else: testObj.testDesc = child[2].strVal testObj.testBlock = child[1] @@ -46,5 +46,5 @@ macro suite(suiteName, suiteDesc, suiteBloc: untyped): typed = # Test above suite basics, "Description of such": - test(t5, nil): + test(t5, ""): assert false diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 8cc27b6eb..61c61225d 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -28,7 +28,7 @@ proc parentWith(x: Element; tag: cstring): Element = proc extractItems(x: Element; items: var seq[Element]) = if x == nil: return - if x.nodeName == "A": + if x.nodeName == cstring"A": items.add x else: for i in 0..: x86 | amd64 | arm | x86_amd64 | x86_arm | amd64_x86 | amd64_arm --winstore Use Windows Store (rather than desktop) development tools --sdkversion: Use a specific Windows SDK version: - is either the full Windows 10 SDK version number or + is either the full Windows 10 SDK version number or "8.1" to use the windows 8.1 SDK Other command line arguments are passed on to the @@ -34,8 +34,8 @@ Microsoft C/C++ compiler for the specified SDK toolset """ when isMainModule: - var platformArg: string = nil - var sdkVersionArg: string = nil + var platformArg: string = "" + var sdkVersionArg: string = "" var storeArg: bool = false var clArgs: seq[TaintedString] = @[] @@ -54,7 +54,7 @@ when isMainModule: echo HelpText clArgs.add(wargv) - var vccEnvStrTab = getVccEnv(platformArg, storeArg, sdkVersionArg) + var vccEnvStrTab = getVccEnv(platformArg, storeArg, sdkVersionArg) if vccEnvStrTab != nil: for vccEnvKey, vccEnvVal in vccEnvStrTab: putEnv(vccEnvKey, vccEnvVal) diff --git a/tools/website.tmpl b/tools/website.tmpl index f9b1a219a..9e5eb2460 100644 --- a/tools/website.tmpl +++ b/tools/website.tmpl @@ -203,7 +203,7 @@ runForever() # if currentTab == "index": # end if -# if c.gaId != nil: +# if c.gaId.len != 0: