WIP: disallow 'nil' for strings and seqs

This commit is contained in:
Andreas Rumpf 2018-08-13 11:41:33 +02:00
commit dae5450947
43 changed files with 207 additions and 173 deletions

View file

@ -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] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc discardSons*(father: PNode) = proc discardSons*(father: PNode) =
father.sons = nil when defined(nimNoNilSeqs):
father.sons = @[]
else:
father.sons = nil
proc withInfo*(n: PNode, info: TLineInfo): PNode = proc withInfo*(n: PNode, info: TLineInfo): PNode =
n.info = info n.info = info
@ -1367,7 +1370,7 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo;
result.loc = s.loc result.loc = s.loc
result.annex = s.annex result.annex = s.annex
# XXX once usedGenerics is used, ensure module aliases keep working! # XXX once usedGenerics is used, ensure module aliases keep working!
assert s.usedGenerics == nil assert s.usedGenerics.len == 0
proc initStrTable*(x: var TStrTable) = proc initStrTable*(x: var TStrTable) =
x.counter = 0 x.counter = 0
@ -1592,7 +1595,10 @@ proc getStr*(a: PNode): string =
of nkStrLit..nkTripleStrLit: result = a.strVal of nkStrLit..nkTripleStrLit: result = a.strVal
of nkNilLit: of nkNilLit:
# let's hope this fixes more problems than it creates: # let's hope this fixes more problems than it creates:
result = nil when defined(nimNoNilSeqs):
result = ""
else:
result = nil
else: else:
doAssert false, "getStr" doAssert false, "getStr"
#internalError(a.info, "getStr") #internalError(a.info, "getStr")

View file

@ -431,7 +431,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
# don't call '$' here for efficiency: # don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data let pat = ri.sons[0].sym.loc.r.data
internalAssert p.config, pat != nil internalAssert p.config, pat.len > 0
if pat.contains({'#', '(', '@', '\''}): if pat.contains({'#', '(', '@', '\''}):
var pl = genPatternCall(p, ri, pat, typ) var pl = genPatternCall(p, ri, pat, typ)
# simpler version of 'fixupCall' that works with the pl+params combination: # 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: # don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data let pat = ri.sons[0].sym.loc.r.data
internalAssert p.config, pat != nil internalAssert p.config, pat.len > 0
var start = 3 var start = 3
if ' ' in pat: if ' ' in pat:
start = 1 start = 1

View file

@ -65,7 +65,8 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
of tyString: of tyString:
# with the new semantics for 'nil' strings, we can map "" to nil and # with the new semantics for 'nil' strings, we can map "" to nil and
# save tons of allocations: # save tons of allocations:
if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info) if n.strVal.len == 0 and optNilSeqs notin p.options:
result = genNilStringLiteral(p.module, n.info)
else: else:
result = genStringLiteral(p.module, n) result = genStringLiteral(p.module, n)
else: else:

View file

@ -58,7 +58,7 @@ proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope = proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf): if compilationCachePresent(conf):
result = rope(nil) result = rope("")
add(result, "\n/*\t") add(result, "\n/*\t")
add(result, CProcSectionNames[ps]) add(result, CProcSectionNames[ps])
add(result, ":*/\n") add(result, ":*/\n")

View file

@ -496,6 +496,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else: else:
localError(conf, info, errOnOrOffExpectedButXFound % arg) localError(conf, info, errOnOrOffExpectedButXFound % arg)
of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info) 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 "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
of "floatchecks": of "floatchecks":
processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)

View file

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

View file

@ -191,7 +191,7 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
proc genComment(d: PDoc, n: PNode): string = proc genComment(d: PDoc, n: PNode): string =
result = "" result = ""
var dummyHasToc: bool var dummyHasToc: bool
if n.comment != nil: if n.comment.len > 0:
renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info), renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
toLinenumber(n.info), toColumn(n.info), toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options, d.conf), result) dummyHasToc, d.options, d.conf), result)
@ -205,7 +205,8 @@ proc genRecComment(d: PDoc, n: PNode): Rope =
result = genRecComment(d, n.sons[i]) result = genRecComment(d, n.sons[i])
if result != nil: return if result != nil: return
else: else:
n.comment = nil when defined(nimNoNilSeqs): n.comment = ""
else: n.comment = nil
proc getPlainDocstring(n: PNode): string = proc getPlainDocstring(n: PNode): string =
## Gets the plain text docstring of a node non destructively. ## 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. ## the concatenated ``##`` comments of the node.
result = "" result = ""
if n == nil: return if n == nil: return
if n.comment != nil and startsWith(n.comment, "##"): if startsWith(n.comment, "##"):
result = n.comment result = n.comment
if result.len < 1: if result.len < 1:
for i in countup(0, safeLen(n)-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, result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
"col": %n.info.col} "col": %n.info.col}
if comm != nil and comm != "": if comm.len > 0:
result["description"] = %comm result["description"] = %comm
if r.buf != nil: if r.buf.len > 0:
result["code"] = %r.buf result["code"] = %r.buf
proc checkForFalse(n: PNode): bool = proc checkForFalse(n: PNode): bool =
@ -634,7 +635,7 @@ proc add(d: PDoc; j: JsonNode) =
proc generateJson*(d: PDoc, n: PNode) = proc generateJson*(d: PDoc, n: PNode) =
case n.kind case n.kind
of nkCommentStmt: of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"): if startsWith(n.comment, "##"):
let stripped = n.comment.substr(2).strip let stripped = n.comment.substr(2).strip
d.add %{ "comment": %stripped, "line": %n.info.line.int, d.add %{ "comment": %stripped, "line": %n.info.line.int,
"col": %n.info.col } "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) = proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
case n.kind case n.kind
of nkCommentStmt: of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"): if startsWith(n.comment, "##"):
let stripped = n.comment.substr(2).strip let stripped = n.comment.substr(2).strip
r.add stripped r.add stripped
of nkProcDef: of nkProcDef:

View file

@ -1267,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
if sfInfixCall in f.flags: if sfInfixCall in f.flags:
let pat = n.sons[0].sym.loc.r.data let pat = n.sons[0].sym.loc.r.data
internalAssert p.config, pat != nil internalAssert p.config, pat.len > 0
if pat.contains({'#', '(', '@'}): if pat.contains({'#', '(', '@'}):
var typ = skipTypes(n.sons[0].typ, abstractInst) var typ = skipTypes(n.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
@ -1350,7 +1350,7 @@ proc arrayTypeForElemType(typ: PType): string =
of tyUint8: "Uint8Array" of tyUint8: "Uint8Array"
of tyFloat32: "Float32Array" of tyFloat32: "Float32Array"
of tyFloat64, tyFloat: "Float64Array" of tyFloat64, tyFloat: "Float64Array"
else: nil else: ""
proc createVar(p: PProc, typ: PType, indirect: bool): Rope = proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
var t = skipTypes(typ, abstractInst) var t = skipTypes(typ, abstractInst)

View file

@ -164,13 +164,13 @@ type
TNoteKinds* = set[TNoteKind] TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] = proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result[3] = {low(TNoteKind)..high(TNoteKind)} - {} result[3] = {low(TNoteKind)..high(TNoteKind)} - {}
result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex, result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
hintSource, hintGlobalVar, hintGCStats} hintSource, hintGlobalVar, hintGCStats}
result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
hintProcessing, hintPattern, hintExecuting, hintLinking} hintProcessing, hintPattern, hintExecuting, hintLinking}
const const
NotesVerbosity* = computeNotesVerbosity() NotesVerbosity* = computeNotesVerbosity()

View file

@ -262,7 +262,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
err.add "\nThis might be caused by a recursive module dependency: " err.add "\nThis might be caused by a recursive module dependency: "
err.add c.recursiveDep err.add c.recursiveDep
# prevent excessive errors for 'nim check' # prevent excessive errors for 'nim check'
c.recursiveDep = nil c.recursiveDep = ""
localError(c.config, info, errGenerated, err) localError(c.config, info, errGenerated, err)
proc lookUp*(c: PContext, n: PNode): PSym = proc lookUp*(c: PContext, n: PNode): PSym =

View file

@ -391,10 +391,10 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
if conf.structuredErrorHook != nil: if conf.structuredErrorHook != nil:
conf.structuredErrorHook(conf, unknownLineInfo(), conf.structuredErrorHook(conf, unknownLineInfo(),
s & (if kind != nil: KindFormat % kind else: ""), sev) s & (if kind.len > 0: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg): if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil: if kind.len > 0:
styledMsgWriteln(color, title, resetStyle, s, styledMsgWriteln(color, title, resetStyle, s,
KindColor, `%`(KindFormat, kind)) KindColor, `%`(KindFormat, kind))
else: else:
@ -483,9 +483,9 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
if not ignoreMsg: if not ignoreMsg:
if conf.structuredErrorHook != nil: 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 not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil: if kind.len > 0:
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
KindColor, `%`(KindFormat, kind)) KindColor, `%`(KindFormat, kind))
else: else:

View file

@ -38,7 +38,8 @@ type # please make sure we have under 32 options
optPatterns, # en/disable pattern matching optPatterns, # en/disable pattern matching
optMemTracker, optMemTracker,
optHotCodeReloading, optHotCodeReloading,
optLaxStrings optLaxStrings,
optNilSeqs
TOptions* = set[TOption] TOptions* = set[TOption]
TGlobalOption* = enum # **keep binary compatible** TGlobalOption* = enum # **keep binary compatible**

View file

@ -150,7 +150,8 @@ template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0
proc rawSkipComment(p: var TParser, node: PNode) = proc rawSkipComment(p: var TParser, node: PNode) =
if p.tok.tokType == tkComment: if p.tok.tokType == tkComment:
if node != nil: if node != nil:
if node.comment == nil: node.comment = "" when not defined(nimNoNilSeqs):
if node.comment == nil: node.comment = ""
when defined(nimpretty): when defined(nimpretty):
if p.tok.commentOffsetB > p.tok.commentOffsetA: if p.tok.commentOffsetB > p.tok.commentOffsetA:
add node.comment, fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB) add node.comment, fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)

View file

@ -209,7 +209,10 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
for j in 0 ..< p.len: for j in 0 ..< p.len:
if not matches(c, p.sons[j], n.sons[i+j]): if not matches(c, p.sons[j], n.sons[i+j]):
# we need to undo any bindings: # we need to undo any bindings:
if not isNil(c.mapping): c.mapping = nil when defined(nimNoNilSeqs):
c.mapping = @[]
else:
if not isNil(c.mapping): c.mapping = nil
return false return false
result = true result = true

View file

@ -281,7 +281,7 @@ const
proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
result = false result = false
if n.comment != nil: if n.comment.len > 0:
result = (renderNoComments notin g.flags) or result = (renderNoComments notin g.flags) or
(renderDocComments in g.flags) (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 = proc lsub(g: TSrcGen; n: PNode): int =
# computes the length of a tree # computes the length of a tree
if isNil(n): return 0 if isNil(n): return 0
if n.comment != nil: return MaxLineLen + 1 if n.comment.len > 0: return MaxLineLen + 1
case n.kind case n.kind
of nkEmpty: result = 0 of nkEmpty: result = 0
of nkTripleStrLit: of nkTripleStrLit:
@ -500,7 +500,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_") of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_")
of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_") of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_")
of nkPragma: result = lcomma(g, n) + 4 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 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 nkImportAs: result = lsub(g, n.sons[0]) + len("_as_") + lsub(g, n.sons[1])
of nkElifBranch: result = lsons(g, n) + len("elif_:_") of nkElifBranch: result = lsons(g, n) + len("elif_:_")
@ -539,7 +539,7 @@ proc gsub(g: var TSrcGen, n: PNode) =
proc hasCom(n: PNode): bool = proc hasCom(n: PNode): bool =
result = false result = false
if n.isNil: return false if n.isNil: return false
if n.comment != nil: return true if n.comment.len > 0: return true
case n.kind case n.kind
of nkEmpty..nkNilLit: discard of nkEmpty..nkNilLit: discard
else: else:
@ -602,7 +602,7 @@ proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
dedent(g) dedent(g)
proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool = 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: if not result:
# check further # check further
for i in countup(start, sonsLen(n) + theEnd): 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) = proc gcond(g: var TSrcGen, n: PNode) =
if n.kind == nkStmtListExpr: if n.kind == nkStmtListExpr:
put(g, tkParLe, "(") put(g, tkParLe, "(")
gsub(g, n) gsub(g, n)
if n.kind == nkStmtListExpr: if n.kind == nkStmtListExpr:
put(g, tkParRi, ")") put(g, tkParRi, ")")
@ -864,7 +864,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
if isNil(n): return if isNil(n): return
var var
a: TContext a: TContext
if n.comment != nil: pushCom(g, n) if n.comment.len > 0: pushCom(g, n)
case n.kind # atoms: case n.kind # atoms:
of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n)) of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
of nkEmpty: discard 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 elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
else: nil else: nil
var n_next = n[1] 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: nkStringToCString, nkCStringToString} and n_next.len > 0:
n_next = n_next[0] n_next = n_next[0]
if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)): if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):

View file

@ -66,29 +66,19 @@ type
Rope* = ref RopeObj Rope* = ref RopeObj
RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
# by nil to safe space # by nil to safe space
left*, right*: Rope left, right: Rope
length*: int L: int # <= 0 if a leaf
data*: string # != nil if a leaf data*: string
proc len*(a: Rope): int = proc len*(a: Rope): int =
## the rope's length ## the rope's length
if a == nil: result = 0 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) new(result)
if data != nil: result.L = -len(data)
result.length = len(data) result.data = 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
var var
cache: array[0..2048*2 - 1, Rope] # XXX Global here! cache: array[0..2048*2 - 1, Rope] # XXX Global here!
@ -147,7 +137,7 @@ proc `&`*(a, b: Rope): Rope =
result = a result = a
else: else:
result = newRope() result = newRope()
result.length = a.length + b.length result.L = abs(a.L) + abs(b.L)
result.left = a result.left = a
result.right = b result.right = b

View file

@ -45,7 +45,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
template cbos(name, body) {.dirty.} = template cbos(name, body) {.dirty.} =
result.registerCallback "stdlib.system." & astToStr(name), result.registerCallback "stdlib.system." & astToStr(name),
proc (a: VmArgs) = proc (a: VmArgs) =
errorMsg = nil errorMsg = ""
try: try:
body body
except OSError: except OSError:

View file

@ -119,7 +119,7 @@ proc commonType*(x, y: PType): PType =
elif b.kind == tyStmt: result = b elif b.kind == tyStmt: result = b
elif a.kind == tyTypeDesc: elif a.kind == tyTypeDesc:
# turn any concrete typedesc into the abstract typedesc type # turn any concrete typedesc into the abstract typedesc type
if a.sons == nil: result = a if a.len == 0: result = a
else: else:
result = newType(tyTypeDesc, a.owner) result = newType(tyTypeDesc, a.owner)
rawAddSon(result, newType(tyNone, a.owner)) rawAddSon(result, newType(tyNone, a.owner))

View file

@ -89,7 +89,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
continue continue
determineType(c, sym) determineType(c, sym)
initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag) 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) matches(c, n, orig, z)
if z.state == csMatch: if z.state == csMatch:
#if sym.name.s == "==" and (n.info ?? "temp3"): #if sym.name.s == "==" and (n.info ?? "temp3"):
@ -237,7 +237,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
if symx.kind in routineKinds: if symx.kind in routineKinds:
errors.add(CandidateError(sym: symx, errors.add(CandidateError(sym: symx,
unmatchedVarParam: 0, firstMismatch: 0, unmatchedVarParam: 0, firstMismatch: 0,
diagnostics: nil, diagnostics: @[],
enabled: false)) enabled: false))
symx = nextOverloadIter(o, c, headSymbol) symx = nextOverloadIter(o, c, headSymbol)
if errors.len == 0: if errors.len == 0:
@ -455,7 +455,7 @@ proc tryDeref(n: PNode): PNode =
proc semOverloadedCall(c: PContext, n, nOrig: PNode, proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags): PNode = filter: TSymKinds, flags: TExprFlags): PNode =
var errors: CandidateErrors = if efExplain in flags: @[] else: nil var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags) var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
if r.state == csMatch: if r.state == csMatch:
# this may be triggered, when the explain pragma is used # this may be triggered, when the explain pragma is used

View file

@ -37,6 +37,7 @@ type
# in standalone ``except`` and ``finally`` # in standalone ``except`` and ``finally``
next*: PProcCon # used for stacking procedure contexts next*: PProcCon # used for stacking procedure contexts
wasForwarded*: bool # whether the current proc has a separate header wasForwarded*: bool # whether the current proc has a separate header
mappingExists*: bool
mapping*: TIdTable mapping*: TIdTable
TMatchedConcept* = object TMatchedConcept* = object
@ -176,12 +177,14 @@ proc lastOptionEntry*(c: PContext): POptionEntry =
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
proc put*(p: PProcCon; key, val: PSym) = 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 #echo "put into table ", key.info
p.mapping.idTablePut(key, val) p.mapping.idTablePut(key, val)
proc get*(p: PProcCon; key: PSym): PSym = 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)) result = PSym(p.mapping.idTableGet(key))
proc getGenSym*(c: PContext; s: PSym): PSym = proc getGenSym*(c: PContext; s: PSym): PSym =

View file

@ -97,10 +97,9 @@ proc sameInstantiation(a, b: TInstantiation): bool =
proc genericCacheGet(genericSym: PSym, entry: TInstantiation; proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
id: CompilesId): PSym = id: CompilesId): PSym =
if genericSym.procInstCache != nil: for inst in genericSym.procInstCache:
for inst in genericSym.procInstCache: if inst.compilesId == id and sameInstantiation(entry, inst[]):
if inst.compilesId == id and sameInstantiation(entry, inst[]): return inst.sym
return inst.sym
when false: when false:
proc `$`(x: PSym): string = proc `$`(x: PSym): string =

View file

@ -121,7 +121,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}: if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}:
let assignment = locateFieldInInitExpr(c, r.sym, initExpr) let assignment = locateFieldInInitExpr(c, r.sym, initExpr)
if assignment == nil: if assignment == nil:
if result == nil: if result.len == 0:
result = r.sym.name.s result = r.sym.name.s
else: else:
result.add ", " result.add ", "
@ -129,7 +129,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
proc checkForMissingFields(c: PContext, recList, initExpr: PNode) = proc checkForMissingFields(c: PContext, recList, initExpr: PNode) =
let missing = missingMandatoryFields(c, recList, initExpr) let missing = missingMandatoryFields(c, recList, initExpr)
if missing != nil: if missing.len > 0:
localError(c.config, initExpr.info, "fields not initialized: $1.", [missing]) localError(c.config, initExpr.info, "fields not initialized: $1.", [missing])
proc semConstructFields(c: PContext, recNode: PNode, proc semConstructFields(c: PContext, recNode: PNode,

View file

@ -970,7 +970,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
var body = s.typ.lastSon var body = s.typ.lastSon
if body.kind == tyObject: if body.kind == tyObject:
# erases all declared fields # erases all declared fields
body.n.sons = nil when defined(nimNoNilSeqs):
body.n.sons = @[]
else:
body.n.sons = nil
popOwner(c) popOwner(c)
closeScope(c) closeScope(c)

View file

@ -40,8 +40,8 @@ proc searchInstTypes*(key: PType): PType =
if not (genericTyp.kind == tyGenericBody and if not (genericTyp.kind == tyGenericBody and
key.sons[0] == genericTyp and genericTyp.sym != nil): return key.sons[0] == genericTyp and genericTyp.sym != nil): return
if genericTyp.sym.typeInstCache == nil: when not defined(nimNoNilSeqs):
return if genericTyp.sym.typeInstCache == nil: return
for inst in genericTyp.sym.typeInstCache: for inst in genericTyp.sym.typeInstCache:
if inst.id == key.id: return inst if inst.id == key.id: return inst

View file

@ -143,7 +143,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
c.calleeScope = 1 c.calleeScope = 1
else: else:
c.calleeScope = calleeScope c.calleeScope = calleeScope
c.diagnostics = if diagnosticsEnabled: @[] else: nil c.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil
c.diagnosticsEnabled = diagnosticsEnabled c.diagnosticsEnabled = diagnosticsEnabled
c.magic = c.calleeSym.magic c.magic = c.calleeSym.magic
initIdTable(c.bindings) initIdTable(c.bindings)
@ -535,6 +535,12 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
proc allowsNil(f: PType): TTypeRelation {.inline.} = proc allowsNil(f: PType): TTypeRelation {.inline.} =
result = if tfNotNil notin f.flags: isSubtype else: isNone 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.} = proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
result = f.kind != a.kind and (f.kind in {tyVar, tyLent} or a.kind in {tyVar, tyLent}) 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 = @[] diagnostics = @[]
flags = {efExplain} flags = {efExplain}
m.c.config.writelnHook = proc (s: string) = 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) let msg = s.replace("Error:", errorPrefix)
if oldWriteHook != nil: oldWriteHook msg if oldWriteHook != nil: oldWriteHook msg
diagnostics.add msg diagnostics.add msg
@ -1253,7 +1259,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
result = isNone result = isNone
elif tfNotNil in f.flags and tfNotNil notin a.flags: elif tfNotNil in f.flags and tfNotNil notin a.flags:
result = isNilConversion result = isNilConversion
of tyNil: result = f.allowsNil of tyNil: result = allowsNilDeprecated(c, f)
else: discard else: discard
of tyOrdinal: of tyOrdinal:
if isOrdinalType(a): if isOrdinalType(a):
@ -1338,7 +1344,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
result = isNilConversion result = isNilConversion
else: else:
result = isEqual result = isEqual
of tyNil: result = f.allowsNil of tyNil: result = allowsNilDeprecated(c, f)
else: discard else: discard
of tyCString: of tyCString:
# conversion from string to cstring is automatic: # conversion from string to cstring is automatic:
@ -1349,7 +1355,11 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
else: else:
result = isEqual result = isEqual
of tyNil: result = f.allowsNil of tyNil: result = f.allowsNil
of tyString: result = isConvertible of tyString:
if optNilSeqs in c.c.config.options or c.magic != mEqCString:
result = isConvertible
else:
result = isNone
of tyPtr: of tyPtr:
# ptr[Tag, char] is not convertible to 'cstring' for now: # ptr[Tag, char] is not convertible to 'cstring' for now:
if a.len == 1: if a.len == 1:
@ -1612,7 +1622,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
if f.sonsLen == 0: if f.sonsLen == 0:
result = isGeneric result = isGeneric
else: 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 c.typedescMatched = true
var aa = a var aa = a
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0: while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:

View file

@ -428,7 +428,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = t.sym.name.s & " literal(" & $t.n.intVal & ")" result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil: elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
result = t.sym.name.s 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 ": " result.add ": "
var first = true var first = true
for son in t.sons: for son in t.sons:
@ -1528,10 +1528,9 @@ proc isCompileTimeOnly*(t: PType): bool {.inline.} =
proc containsCompileTimeOnly*(t: PType): bool = proc containsCompileTimeOnly*(t: PType): bool =
if isCompileTimeOnly(t): return true if isCompileTimeOnly(t): return true
if t.sons != nil: for i in 0 ..< t.sonsLen:
for i in 0 ..< t.sonsLen: if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]): return true
return true
return false return false
type type

View file

@ -113,7 +113,7 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string],
var b = rawMatches[i * 2 + 1] var b = rawMatches[i * 2 + 1]
if a >= 0'i32: if a >= 0'i32:
matches[i-1] = bufSubstr(buf, int(a), int(b)) matches[i-1] = bufSubstr(buf, int(a), int(b))
else: matches[i-1] = nil else: matches[i-1] = ""
return rawMatches[1] - rawMatches[0] return rawMatches[1] - rawMatches[0]
proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], 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 a = rawMatches[i * 2]
var b = rawMatches[i * 2 + 1] var b = rawMatches[i * 2 + 1]
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)) 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) return (rawMatches[0].int, rawMatches[1].int - 1)
proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], 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 a = rawMatches[i * 2]
var b = rawMatches[i * 2 + 1] var b = rawMatches[i * 2 + 1]
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)) 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] return rawMatches[0]
proc find*(s: string, pattern: Regex, matches: var openArray[string], 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: while true:
var match = findBounds(s, sub, caps, prev) var match = findBounds(s, sub, caps, prev)
if match.first < 0: break if match.first < 0: break
assert result != nil
assert s != nil
add(result, substr(s, prev, match.first-1)) add(result, substr(s, prev, match.first-1))
addf(result, by, caps) addf(result, by, caps)
prev = match.last + 1 prev = match.last + 1

View file

@ -293,9 +293,9 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
(key: "kind", val: %($node.kind)), (key: "kind", val: %($node.kind)),
(key: "level", val: %BiggestInt(node.level)) (key: "level", val: %BiggestInt(node.level))
] ]
if node.text != nil: if node.text.len > 0:
result.add("text", %node.text) 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)) var accm = newSeq[JsonNode](len(node.sons))
for i, son in node.sons: for i, son in node.sons:
accm[i] = renderRstToJsonNode(son) accm[i] = renderRstToJsonNode(son)

View file

@ -397,9 +397,9 @@ proc hash(x: IndexEntry): Hash =
proc `<-`(a: var IndexEntry, b: IndexEntry) = proc `<-`(a: var IndexEntry, b: IndexEntry) =
shallowCopy a.keyword, b.keyword shallowCopy a.keyword, b.keyword
shallowCopy a.link, b.link shallowCopy a.link, b.link
if b.linkTitle.isNil: a.linkTitle = nil if b.linkTitle.isNil: a.linkTitle = ""
else: shallowCopy a.linkTitle, b.linkTitle else: shallowCopy a.linkTitle, b.linkTitle
if b.linkDesc.isNil: a.linkDesc = nil if b.linkDesc.isNil: a.linkDesc = ""
else: shallowCopy a.linkDesc, b.linkDesc else: shallowCopy a.linkDesc, b.linkDesc
proc sortIndex(a: var openArray[IndexEntry]) = proc sortIndex(a: var openArray[IndexEntry]) =
@ -607,8 +607,8 @@ proc readIndexDir(dir: string):
fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
else: else:
fileEntries[F].linkTitle = nil fileEntries[F].linkTitle = ""
fileEntries[F].linkDesc = nil fileEntries[F].linkDesc = ""
inc F inc F
# Depending on type add this to the list of symbols or table of APIs. # Depending on type add this to the list of symbols or table of APIs.
if title.keyword.isNil: if title.keyword.isNil:
@ -656,7 +656,6 @@ proc mergeIndexes*(dir: string): string =
## Returns the merged and sorted indices into a single HTML block which can ## Returns the merged and sorted indices into a single HTML block which can
## be further embedded into nimdoc templates. ## be further embedded into nimdoc templates.
var (modules, symbols, docs) = readIndexDir(dir) var (modules, symbols, docs) = readIndexDir(dir)
assert(not symbols.isNil)
result = "" result = ""
# Generate a quick jump list of documents. # Generate a quick jump list of documents.

View file

@ -219,10 +219,10 @@ proc getHint(entry: StackTraceEntry): string =
## We try to provide some hints about stack trace entries that the user ## We try to provide some hints about stack trace entries that the user
## may not be familiar with, in particular calls inside the stdlib. ## may not be familiar with, in particular calls inside the stdlib.
result = "" result = ""
if entry.procname == "processPendingCallbacks": if entry.procname == cstring"processPendingCallbacks":
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
return "Executes pending callbacks" return "Executes pending callbacks"
elif entry.procname == "poll": elif entry.procname == cstring"poll":
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
return "Processes asynchronous completion events" return "Processes asynchronous completion events"

View file

@ -655,7 +655,7 @@ when defineSsl:
proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket, proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket,
handshake: SslHandshakeType, handshake: SslHandshakeType,
hostname: string = nil) = hostname: string = "") =
## Wraps a connected socket in an SSL context. This function effectively ## Wraps a connected socket in an SSL context. This function effectively
## turns ``socket`` into an SSL socket. ## turns ``socket`` into an SSL socket.
## ``hostname`` should be specified so that the client knows which hostname ## ``hostname`` should be specified so that the client knows which hostname
@ -670,7 +670,7 @@ when defineSsl:
case handshake case handshake
of handshakeAsClient: 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 # Set the SNI address for this connection. This call can fail if
# we're not using TLSv1+. # we're not using TLSv1+.
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)

View file

@ -184,7 +184,7 @@ proc missingOrExcl*(s: var IntSet, key: int) : bool =
## `key` is removed from `s` and false is returned. ## `key` is removed from `s` and false is returned.
var count = s.elems var count = s.elems
exclImpl(s, key) exclImpl(s, key)
result = count == s.elems result = count == s.elems
proc containsOrIncl*(s: var IntSet, key: int): bool = proc containsOrIncl*(s: var IntSet, key: int): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s` ## returns true if `s` contains `key`, otherwise `key` is included in `s`
@ -212,7 +212,10 @@ proc initIntSet*: IntSet =
#newSeq(result.data, InitIntSetSize) #newSeq(result.data, InitIntSetSize)
#result.max = InitIntSetSize-1 #result.max = InitIntSetSize-1
result.data = nil when defined(nimNoNilSeqs):
result.data = @[]
else:
result.data = nil
result.max = 0 result.max = 0
result.counter = 0 result.counter = 0
result.head = nil result.head = nil
@ -222,7 +225,10 @@ proc clear*(result: var IntSet) =
#setLen(result.data, InitIntSetSize) #setLen(result.data, InitIntSetSize)
#for i in 0..InitIntSetSize-1: result.data[i] = nil #for i in 0..InitIntSetSize-1: result.data[i] = nil
#result.max = InitIntSetSize-1 #result.max = InitIntSetSize-1
result.data = nil when defined(nimNoNilSeqs):
result.data = @[]
else:
result.data = nil
result.max = 0 result.max = 0
result.counter = 0 result.counter = 0
result.head = nil 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 ## copies `src` to `dest`. `dest` does not need to be initialized by
## `initIntSet`. ## `initIntSet`.
if src.elems <= src.a.len: if src.elems <= src.a.len:
dest.data = nil when defined(nimNoNilSeqs):
dest.data = @[]
else:
dest.data = nil
dest.max = 0 dest.max = 0
dest.counter = src.counter dest.counter = src.counter
dest.head = nil dest.head = nil
@ -247,11 +256,9 @@ proc assign*(dest: var IntSet, src: IntSet) =
var it = src.head var it = src.head
while it != nil: while it != nil:
var h = it.key and dest.max var h = it.key and dest.max
while dest.data[h] != nil: h = nextTry(h, dest.max) while dest.data[h] != nil: h = nextTry(h, dest.max)
assert(dest.data[h] == nil) assert(dest.data[h] == nil)
var n: PTrunk var n: PTrunk
new(n) new(n)
n.next = dest.head n.next = dest.head
@ -259,7 +266,6 @@ proc assign*(dest: var IntSet, src: IntSet) =
n.bits = it.bits n.bits = it.bits
dest.head = n dest.head = n
dest.data[h] = n dest.data[h] = n
it = it.next it = it.next
proc union*(s1, s2: IntSet): IntSet = proc union*(s1, s2: IntSet): IntSet =
@ -315,7 +321,7 @@ proc len*(s: IntSet): int {.inline.} =
for _ in s: for _ in s:
inc(result) inc(result)
proc card*(s: IntSet): int {.inline.} = proc card*(s: IntSet): int {.inline.} =
## alias for `len() <#len>` _. ## alias for `len() <#len>` _.
result = s.len() result = s.len()
@ -361,7 +367,7 @@ when isMainModule:
x.incl(1056) x.incl(1056)
x.incl(1044) x.incl(1044)
x.excl(1044) x.excl(1044)
assert x.containsOrIncl(888) == false assert x.containsOrIncl(888) == false
assert 888 in x assert 888 in x

View file

@ -231,7 +231,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
raiseOSError(osLastError()) raiseOSError(osLastError())
result = newSocket(fd, domain, sockType, protocol, buffered) result = newSocket(fd, domain, sockType, protocol, buffered)
proc parseIPv4Address(address_str: string): IpAddress = proc parseIPv4Address(addressStr: string): IpAddress =
## Parses IPv4 adresses ## Parses IPv4 adresses
## Raises EInvalidValue on errors ## Raises EInvalidValue on errors
var var
@ -241,15 +241,15 @@ proc parseIPv4Address(address_str: string): IpAddress =
result.family = IpAddressFamily.IPv4 result.family = IpAddressFamily.IPv4
for i in 0 .. high(address_str): for i in 0 .. high(addressStr):
if address_str[i] in strutils.Digits: # Character is a number if addressStr[i] in strutils.Digits: # Character is a number
currentByte = currentByte * 10 + currentByte = currentByte * 10 +
cast[uint16](ord(address_str[i]) - ord('0')) cast[uint16](ord(addressStr[i]) - ord('0'))
if currentByte > 255'u16: if currentByte > 255'u16:
raise newException(ValueError, raise newException(ValueError,
"Invalid IP Address. Value is out of range") "Invalid IP Address. Value is out of range")
seperatorValid = true seperatorValid = true
elif address_str[i] == '.': # IPv4 address separator elif addressStr[i] == '.': # IPv4 address separator
if not seperatorValid or byteCount >= 3: if not seperatorValid or byteCount >= 3:
raise newException(ValueError, raise newException(ValueError,
"Invalid IP Address. The address consists of too many groups") "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") raise newException(ValueError, "Invalid IP Address")
result.address_v4[byteCount] = cast[uint8](currentByte) result.address_v4[byteCount] = cast[uint8](currentByte)
proc parseIPv6Address(address_str: string): IpAddress = proc parseIPv6Address(addressStr: string): IpAddress =
## Parses IPv6 adresses ## Parses IPv6 adresses
## Raises EInvalidValue on errors ## Raises EInvalidValue on errors
result.family = IpAddressFamily.IPv6 result.family = IpAddressFamily.IPv6
if address_str.len < 2: if addressStr.len < 2:
raise newException(ValueError, "Invalid IP Address") raise newException(ValueError, "Invalid IP Address")
var var
@ -282,7 +282,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
v4StartPos = -1 v4StartPos = -1
byteCount = 0 byteCount = 0
for i,c in address_str: for i,c in addressStr:
if c == ':': if c == ':':
if not seperatorValid: if not seperatorValid:
raise newException(ValueError, raise newException(ValueError,
@ -293,7 +293,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
"Invalid IP Address. Address contains more than one \"::\" seperator") "Invalid IP Address. Address contains more than one \"::\" seperator")
dualColonGroup = groupCount dualColonGroup = groupCount
seperatorValid = false seperatorValid = false
elif i != 0 and i != high(address_str): elif i != 0 and i != high(addressStr):
if groupCount >= 8: if groupCount >= 8:
raise newException(ValueError, raise newException(ValueError,
"Invalid IP Address. The address consists of too many groups") "Invalid IP Address. The address consists of too many groups")
@ -303,11 +303,11 @@ proc parseIPv6Address(address_str: string): IpAddress =
groupCount.inc() groupCount.inc()
if dualColonGroup != -1: seperatorValid = false if dualColonGroup != -1: seperatorValid = false
elif i == 0: # only valid if address starts with :: elif i == 0: # only valid if address starts with ::
if address_str[1] != ':': if addressStr[1] != ':':
raise newException(ValueError, raise newException(ValueError,
"Invalid IP Address. Address may not start with \":\"") "Invalid IP Address. Address may not start with \":\"")
else: # i == high(address_str) - only valid if address ends with :: else: # i == high(addressStr) - only valid if address ends with ::
if address_str[high(address_str)-1] != ':': if addressStr[high(addressStr)-1] != ':':
raise newException(ValueError, raise newException(ValueError,
"Invalid IP Address. Address may not end with \":\"") "Invalid IP Address. Address may not end with \":\"")
lastWasColon = true lastWasColon = true
@ -345,7 +345,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
groupCount.inc() groupCount.inc()
else: # Must parse IPv4 address 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 if c in strutils.Digits: # Character is a number
currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0')) currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
if currentShort > 255'u32: if currentShort > 255'u32:
@ -386,21 +386,21 @@ proc parseIPv6Address(address_str: string): IpAddress =
raise newException(ValueError, raise newException(ValueError,
"Invalid IP Address. The address consists of too many groups") "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 ## Parses an IP address
## Raises EInvalidValue on error ## Raises EInvalidValue on error
if address_str == nil: if addressStr.len == 0:
raise newException(ValueError, "IP Address string is nil") raise newException(ValueError, "IP Address string is empty")
if address_str.contains(':'): if addressStr.contains(':'):
return parseIPv6Address(address_str) return parseIPv6Address(addressStr)
else: 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 ## Checks if a string is an IP address
## Returns true if it is, false otherwise ## Returns true if it is, false otherwise
try: try:
discard parseIpAddress(address_str) discard parseIpAddress(addressStr)
except ValueError: except ValueError:
return false return false
return true return true
@ -587,7 +587,7 @@ when defineSsl:
proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar;
max_psk_len: cuint): cuint {.cdecl.} = max_psk_len: cuint): cuint {.cdecl.} =
let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) 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) let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
if psk.len.cuint > max_psk_len: if psk.len.cuint > max_psk_len:
return 0 return 0
@ -657,7 +657,7 @@ when defineSsl:
proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket, proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket,
handshake: SslHandshakeType, handshake: SslHandshakeType,
hostname: string = nil) = hostname: string = "") =
## Wraps a connected socket in an SSL context. This function effectively ## Wraps a connected socket in an SSL context. This function effectively
## turns ``socket`` into an SSL socket. ## turns ``socket`` into an SSL socket.
## ``hostname`` should be specified so that the client knows which hostname ## ``hostname`` should be specified so that the client knows which hostname
@ -671,7 +671,7 @@ when defineSsl:
wrapSocket(ctx, socket) wrapSocket(ctx, socket)
case handshake case handshake
of handshakeAsClient: 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 # Discard result in case OpenSSL version doesn't support SNI, or we're
# not using TLSv1+ # not using TLSv1+
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)

View file

@ -44,10 +44,10 @@ type
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} = proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
## Initalizes option parses with cmdline. cmdline should not contain ## Initalizes option parses with cmdline. cmdline should not contain
## argument 0 - program name. ## 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 = "" result.remainingShortOptions = ""
when not defined(createNimRtl): when not defined(createNimRtl):
if cmdline == nil: if cmdline.len == 0:
result.cmd = commandLineParams() result.cmd = commandLineParams()
return return
else: else:
@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
## and calls initOptParser(openarray[string]) ## and calls initOptParser(openarray[string])
## Do not use. ## Do not use.
if cmdline == "": # backward compatibility if cmdline == "": # backward compatibility
return initOptParser(seq[string](nil)) return initOptParser(@[])
else: else:
return initOptParser(cmdline.split) return initOptParser(cmdline.split)

View file

@ -95,6 +95,7 @@ type
kind: XmlEventKind kind: XmlEventKind
err: XmlErrorKind err: XmlErrorKind
state: ParserState state: ParserState
cIsEmpty: bool
filename: string filename: string
options: set[XmlParseOption] options: set[XmlParseOption]
@ -125,7 +126,8 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
my.kind = xmlError my.kind = xmlError
my.a = "" my.a = ""
my.b = "" my.b = ""
my.c = nil my.c = ""
my.cIsEmpty = true
my.options = options my.options = options
proc close*(my: var XmlParser) {.inline.} = proc close*(my: var XmlParser) {.inline.} =
@ -482,6 +484,7 @@ proc parseTag(my: var XmlParser) =
my.kind = xmlElementOpen my.kind = xmlElementOpen
my.state = stateAttr my.state = stateAttr
my.c = my.a # save for later my.c = my.a # save for later
my.cIsEmpty = false
else: else:
my.kind = xmlElementStart my.kind = xmlElementStart
let slash = my.buf[my.bufpos] == '/' let slash = my.buf[my.bufpos] == '/'
@ -490,7 +493,8 @@ proc parseTag(my: var XmlParser) =
if slash and my.buf[my.bufpos] == '>': if slash and my.buf[my.bufpos] == '>':
inc(my.bufpos) inc(my.bufpos)
my.state = stateEmptyElementTag my.state = stateEmptyElementTag
my.c = nil my.c = ""
my.cIsEmpty = true
elif my.buf[my.bufpos] == '>': elif my.buf[my.bufpos] == '>':
inc(my.bufpos) inc(my.bufpos)
else: else:
@ -678,7 +682,7 @@ proc next*(my: var XmlParser) =
of stateEmptyElementTag: of stateEmptyElementTag:
my.state = stateNormal my.state = stateNormal
my.kind = xmlElementEnd my.kind = xmlElementEnd
if not my.c.isNil: if not my.cIsEmpty:
my.a = my.c my.a = my.c
of stateError: of stateError:
my.kind = xmlError my.kind = xmlError

View file

@ -765,7 +765,7 @@ template fillMatches(s, caps, c) =
if startIdx != -1: if startIdx != -1:
caps[k] = substr(s, startIdx, endIdx) caps[k] = substr(s, startIdx, endIdx)
else: else:
caps[k] = nil caps[k] = ""
proc matchLen*(s: string, pattern: Peg, matches: var openArray[string], proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =

View file

@ -377,7 +377,10 @@ when not defined(js):
proc ssClose(s: Stream) = proc ssClose(s: Stream) =
var s = StringStream(s) var s = StringStream(s)
s.data = nil when defined(nimNoNilSeqs):
s.data = ""
else:
s.data = nil
proc newStringStream*(s: string = ""): StringStream = proc newStringStream*(s: string = ""): StringStream =
## creates a new stream from the string `s`. ## creates a new stream from the string `s`.

View file

@ -176,10 +176,7 @@ method suiteEnded*(formatter: OutputFormatter) {.base, gcsafe.} =
discard discard
proc addOutputFormatter*(formatter: OutputFormatter) = proc addOutputFormatter*(formatter: OutputFormatter) =
if formatters == nil: formatters.add(formatter)
formatters = @[formatter]
else:
formatters.add(formatter)
proc newConsoleOutputFormatter*(outputLevel: OutputLevel = PRINT_ALL, proc newConsoleOutputFormatter*(outputLevel: OutputLevel = PRINT_ALL,
colorOutput = true): ConsoleOutputFormatter = colorOutput = true): ConsoleOutputFormatter =
@ -225,7 +222,7 @@ method testStarted*(formatter: ConsoleOutputFormatter, testName: string) =
formatter.isInTest = true formatter.isInTest = true
method failureOccurred*(formatter: ConsoleOutputFormatter, checkpoints: seq[string], stackTrace: string) = method failureOccurred*(formatter: ConsoleOutputFormatter, checkpoints: seq[string], stackTrace: string) =
if stackTrace != nil: if stackTrace.len > 0:
echo stackTrace echo stackTrace
let prefix = if formatter.isInSuite: " " else: "" let prefix = if formatter.isInSuite: " " else: ""
for msg in items(checkpoints): for msg in items(checkpoints):
@ -236,7 +233,7 @@ method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) =
if formatter.outputLevel != PRINT_NONE and if formatter.outputLevel != PRINT_NONE and
(formatter.outputLevel == PRINT_ALL or testResult.status == FAILED): (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) template rawPrint() = echo(prefix, "[", $testResult.status, "] ", testResult.testName)
when not defined(ECMAScript): when not defined(ECMAScript):
if formatter.colorOutput and 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. ## ``stackTrace`` is provided only if the failure occurred due to an exception.
## ``checkpoints`` is never ``nil``. ## ``checkpoints`` is never ``nil``.
formatter.testErrors.add(checkpoints) formatter.testErrors.add(checkpoints)
if stackTrace != nil: if stackTrace.len > 0:
formatter.testStackTrace = stackTrace formatter.testStackTrace = stackTrace
method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) = method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) =
@ -392,7 +389,7 @@ proc shouldRun(currentSuiteName, testName: string): bool =
return false return false
proc ensureInitialized() = proc ensureInitialized() =
if formatters == nil: if formatters.len == 0:
formatters = @[OutputFormatter(defaultConsoleFormatter())] formatters = @[OutputFormatter(defaultConsoleFormatter())]
if not disabledParamFiltering and not testsFilters.isValid: if not disabledParamFiltering and not testsFilters.isValid:

View file

@ -217,9 +217,9 @@ proc createAttribute*(doc: PDocument, name: string): PAttr =
new(attrNode) new(attrNode)
attrNode.fName = name attrNode.fName = name
attrNode.fNodeName = name attrNode.fNodeName = name
attrNode.fLocalName = nil attrNode.fLocalName = ""
attrNode.prefix = nil attrNode.prefix = ""
attrNode.fNamespaceURI = nil attrNode.fNamespaceURI = ""
attrNode.value = "" attrNode.value = ""
attrNode.fSpecified = false attrNode.fSpecified = false
return attrNode return attrNode
@ -254,7 +254,7 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
attrNode.prefix = qualifiedName.split(':')[0] attrNode.prefix = qualifiedName.split(':')[0]
attrNode.fLocalName = qualifiedName.split(':')[1] attrNode.fLocalName = qualifiedName.split(':')[1]
else: else:
attrNode.prefix = nil attrNode.prefix = ""
attrNode.fLocalName = qualifiedName attrNode.fLocalName = qualifiedName
attrNode.value = "" attrNode.value = ""
@ -298,9 +298,9 @@ proc createElement*(doc: PDocument, tagName: string): PElement =
new(elNode) new(elNode)
elNode.fTagName = tagName elNode.fTagName = tagName
elNode.fNodeName = tagName elNode.fNodeName = tagName
elNode.fLocalName = nil elNode.fLocalName = ""
elNode.prefix = nil elNode.prefix = ""
elNode.fNamespaceURI = nil elNode.fNamespaceURI = ""
elNode.childNodes = @[] elNode.childNodes = @[]
elNode.attributes = @[] elNode.attributes = @[]
@ -332,7 +332,7 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin
elNode.prefix = qualifiedName.split(':')[0] elNode.prefix = qualifiedName.split(':')[0]
elNode.fLocalName = qualifiedName.split(':')[1] elNode.fLocalName = qualifiedName.split(':')[1]
else: else:
elNode.prefix = nil elNode.prefix = ""
elNode.fLocalName = qualifiedName elNode.fLocalName = qualifiedName
elNode.fNamespaceURI = namespaceURI elNode.fNamespaceURI = namespaceURI
elNode.childNodes = @[] elNode.childNodes = @[]
@ -893,22 +893,22 @@ proc tagName*(el: PElement): string =
proc getAttribute*(el: PNode, name: string): string = proc getAttribute*(el: PNode, name: string): string =
## Retrieves an attribute value by ``name`` ## Retrieves an attribute value by ``name``
if isNil(el.attributes): if isNil(el.attributes):
return nil return ""
var attribute = el.attributes.getNamedItem(name) var attribute = el.attributes.getNamedItem(name)
if not isNil(attribute): if not isNil(attribute):
return attribute.value return attribute.value
else: else:
return nil return ""
proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string = proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string =
## Retrieves an attribute value by ``localName`` and ``namespaceURI`` ## Retrieves an attribute value by ``localName`` and ``namespaceURI``
if isNil(el.attributes): if isNil(el.attributes):
return nil return ""
var attribute = el.attributes.getNamedItemNS(namespaceURI, localName) var attribute = el.attributes.getNamedItemNS(namespaceURI, localName)
if not isNil(attribute): if not isNil(attribute):
return attribute.value return attribute.value
else: else:
return nil return ""
proc getAttributeNode*(el: PElement, name: string): PAttr = proc getAttributeNode*(el: PElement, name: string): PAttr =
## Retrieves an attribute node by ``name`` ## Retrieves an attribute node by ``name``

View file

@ -119,7 +119,7 @@ proc loadXMLStream*(stream: Stream): PDocument =
## a ``PDocument`` ## a ``PDocument``
var x: XmlParser var x: XmlParser
open(x, stream, nil, {reportComments}) open(x, stream, "", {reportComments})
var xmlDoc: PDocument var xmlDoc: PDocument
var dom: PDOMImplementation = getDOM() var dom: PDOMImplementation = getDOM()
@ -161,7 +161,7 @@ when not defined(testing) and isMainModule:
#echo(xml.getElementsByTagName("bla:test")[0].namespaceURI) #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
#echo(xml.getElementsByTagName("test")[0].namespaceURI) #echo(xml.getElementsByTagName("test")[0].namespaceURI)
for i in items(xml.getElementsByTagName("*")): for i in items(xml.getElementsByTagName("*")):
if i.namespaceURI != nil: if i.namespaceURI.len > 0:
echo(i.nodeName, "=", i.namespaceURI) echo(i.nodeName, "=", i.namespaceURI)

View file

@ -3963,19 +3963,28 @@ when hasAlloc:
proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} = proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} =
## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case, ## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case,
## ``x`` becomes ``@[y]`` ## ``x`` becomes ``@[y]``
if x == nil: x = @[y] when defined(nimNoNilSeqs):
else: x.add(y) x.add(y)
else:
if x == nil: x = @[y]
else: x.add(y)
proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} = proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} =
## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""`` ## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""``
if x == nil: x = "" when defined(nimNoNilSeqs):
x.add(y) x.add(y)
else:
if x == nil: x = ""
x.add(y)
proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} = proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} =
## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that ## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that
## case, ``x`` becomes ``y`` ## case, ``x`` becomes ``y``
if x == nil: x = y when defined(nimNoNilSeqs):
else: x.add(y) x.add(y)
else:
if x == nil: x = y
else: x.add(y)
proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
## generates a tuple constructor expression listing all the local variables ## generates a tuple constructor expression listing all the local variables

View file

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

View file

@ -15,11 +15,11 @@ when defined(ssl):
var clientCount = 0 var clientCount = 0
proc sendMessages(client: AsyncSocket) {.async.} = proc sendMessages(client: AsyncSocket) {.async.} =
for i in 0 .. <messagesToSend: for i in 0 ..< messagesToSend:
await send(client, "Message " & $i & "\c\L") await send(client, "Message " & $i & "\c\L")
proc launchSwarm(port: Port) {.async.} = proc launchSwarm(port: Port) {.async.} =
for i in 0 .. <swarmSize: for i in 0 ..< swarmSize:
var sock = newAsyncSocket() var sock = newAsyncSocket()
var clientContext = newContext(verifyMode = CVerifyNone) var clientContext = newContext(verifyMode = CVerifyNone)
clientContext.wrapSocket(sock) clientContext.wrapSocket(sock)