correct comparisons for nil strings/seqs

This commit is contained in:
Andreas Rumpf
2018-04-28 15:13:44 +02:00
parent 13a380bca6
commit f64f9e50cc
7 changed files with 91 additions and 23 deletions

View File

@@ -980,10 +980,10 @@ proc genEcho(p: BProc, n: PNode) =
var a: TLoc
for it in n.sons:
if it.skipConv.kind == nkNilLit:
add(args, ", \"nil\"")
add(args, ", \"\"")
else:
initLocExpr(p, it, a)
addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
addf(args, ", $1? ($1)->data:\"\"", [rdLoc(a)])
p.module.includeHeader("<base/log.h>")
linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args)
else:
@@ -1755,16 +1755,14 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
var x: TLoc
var a = e.sons[1]
var b = e.sons[2]
if (a.kind == nkNilLit) or (b.kind == nkNilLit):
binaryExpr(p, e, d, "($1 == $2)")
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
initLocExpr(p, e.sons[2], x)
putIntoDest(p, d, e,
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
initLocExpr(p, e.sons[1], x)
putIntoDest(p, d, e,
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
else:
binaryExpr(p, e, d, "#eqStrings($1, $2)")

View File

@@ -82,7 +82,6 @@ proc countDefinedSymbols*(): int =
proc initDefines*() =
gSymbols = newStringTable(modeStyleInsensitive)
defineSymbol("nimrod") # 'nimrod' is always defined
# for bootstrapping purposes and old code:
defineSymbol("nimhygiene")
defineSymbol("niminheritable")
@@ -115,3 +114,4 @@ proc initDefines*() =
defineSymbol("nimHasNilChecks")
defineSymbol("nimSymKind")
defineSymbol("nimVmEqIdent")
defineSymbol("nimNoNil")

View File

@@ -1553,6 +1553,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkFloatLit, info, t)
of tyCString, tyString:
result = newNodeIT(nkStrLit, info, t)
result.strVal = ""
of tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr,
tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
result = newNodeIT(nkNilLit, info, t)

View File

@@ -645,7 +645,6 @@ template replaceImpl(str: string, pattern: Regex,
let bounds = match.matchBounds
result.add(str.substr(lastIdx, bounds.a - 1))
let nextVal = replacement
assert(nextVal != nil)
result.add(nextVal)
lastIdx = bounds.b + 1

View File

@@ -2412,8 +2412,9 @@ proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
if seqToPtr(x) == seqToPtr(y):
return true
if x.isNil or y.isNil:
return false
when not defined(nimNoNil):
if x.isNil or y.isNil:
return false
if x.len != y.len:
return false
@@ -4010,18 +4011,18 @@ proc addQuoted*[T](s: var string, x: T) =
when hasAlloc:
# XXX: make these the default (or implement the NilObject optimization)
proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} =
proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} =
## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case,
## ``x`` becomes ``@[y]``
if x == nil: x = @[y]
else: x.add(y)
proc safeAdd*(x: var string, y: char) =
proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} =
## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""``
if x == nil: x = ""
x.add(y)
proc safeAdd*(x: var string, y: string) =
proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} =
## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that
## case, ``x`` becomes ``y``
if x == nil: x = y

View File

@@ -22,21 +22,34 @@ proc resize(old: int): int {.inline.} =
proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
if a == b: return 0
if a == nil: return -1
if b == nil: return 1
let minlen = min(a.len, b.len)
when defined(nimNoNil):
let alen = if a == nil: 0 else: a.len
let blen = if b == nil: 0 else: b.len
else:
if a == nil: return -1
if b == nil: return 1
let alen = a.len
let blen = b.len
let minlen = min(alen, blen)
if minlen > 0:
result = c_memcmp(addr a.data, addr b.data, minlen.csize)
if result == 0:
result = a.len - b.len
result = alen - blen
else:
result = a.len - b.len
result = alen - blen
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
if a == b: return true
if a == nil or b == nil: return false
return a.len == b.len and
equalMem(addr(a.data), addr(b.data), a.len)
when defined(nimNoNil):
let alen = if a == nil: 0 else: a.len
let blen = if b == nil: 0 else: b.len
else:
if a == nil or b == nil: return false
let alen = a.len
let blen = b.len
if alen == blen:
if alen == 0: return true
return equalMem(addr(a.data), addr(b.data), alen)
when declared(allocAtomic):
template allocStr(size: untyped): untyped =

View File

@@ -51,3 +51,59 @@ import strutils
let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0']
doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\\x00']"
doAssert $cstring(unsafeAddr arr) == "Hello World!"
proc takes(c: cstring) =
doAssert c == ""
proc testm() =
var x: string
# nil is mapped to "":
takes(x)
testm()
# nil tests
var xx: seq[string]
var yy: string
doAssert xx == @[]
doAssert yy == ""
proc bar(arg: cstring): void =
doAssert arg[0] == '\0'
proc baz(arg: openarray[char]): void =
doAssert arg.len == 0
proc stringCompare(): void =
var a,b,c,d,e,f,g: string
a.add 'a'
doAssert a == "a"
b.add "bee"
doAssert b == "bee"
b.add g
doAssert b == "bee"
c.add 123.456
doAssert c == "123.456"
d.add 123456
doAssert d == "123456"
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"
doAssert "" != "\0\0\0\0\0\0\0\0\0\0"
var nilstring: string
bar(nilstring)
baz(nilstring)
stringCompare()
static:
stringCompare()