From c55506006fb79965a493a24cbef99fea7475e13b Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Thu, 11 Feb 2021 19:04:32 +0300 Subject: [PATCH] [backport:1.4] JS cstring null fixes (#16979) * [backport:1.4] JS cstring null fixes * fix JS move string * make it look cleaner (cherry picked from commit 81533a0014a8372207426dc9d067aff4b59db8af) --- compiler/jsgen.nim | 22 ++++++++++++++--- lib/system.nim | 18 ++++++++++++-- lib/system/jssys.nim | 2 +- tests/js/tnilstrs.nim | 10 +++++++- tests/system/tdollars.nim | 51 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 95 insertions(+), 8 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index ed39e7c5cd..be59404efa 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1997,7 +1997,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[2], rhs) if skipTypes(n[1].typ, abstractVarRange).kind == tyCString: - r.res = "$1 += $2;" % [lhs.rdLoc, rhs.rdLoc] + let (b, tmp) = maybeMakeTemp(p, n[2], rhs) + r.res = "if (null != $1) { if (null == $2) $2 = $3; else $2 += $3; }" % + [b, lhs.rdLoc, tmp] else: let (a, tmp) = maybeMakeTemp(p, n[1], lhs) r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp] @@ -2048,9 +2050,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mDestroy: discard "ignore calls to the default destructor" of mOrd: genOrd(p, n, r) of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: - unaryExpr(p, n, r, "", "($1).length") + var x: TCompRes + gen(p, n[1], x) + if skipTypes(n[1].typ, abstractInst).kind == tyCString: + let (a, tmp) = maybeMakeTemp(p, n[1], x) + r.res = "(($1) == null ? 0 : ($2).length)" % [a, tmp] + else: + r.res = "($1).length" % [x.rdLoc] + r.kind = resExpr of mHigh: - unaryExpr(p, n, r, "", "(($1).length-1)") + var x: TCompRes + gen(p, n[1], x) + if skipTypes(n[1].typ, abstractInst).kind == tyCString: + let (a, tmp) = maybeMakeTemp(p, n[1], x) + r.res = "(($1) == null ? -1 : ($2).length - 1)" % [a, tmp] + else: + r.res = "($1).length - 1" % [x.rdLoc] + r.kind = resExpr of mInc: if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: binaryUintExpr(p, n, r, "+", true) diff --git a/lib/system.nim b/lib/system.nim index 07c0f3062d..104eb420ce 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1957,8 +1957,14 @@ type when NimStackTraceMsgs: frameMsgLen*: int ## end position in frameMsgBuf for this frame. -when defined(js): +when defined(js) or defined(nimdoc): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = + ## Appends `y` to `x` in place. + runnableExamples: + var tmp = "" + tmp.add(cstring("ab")) + tmp.add(cstring("cd")) + doAssert tmp == "abcd" asm """ if (`x` === null) { `x` = []; } var off = `x`.length; @@ -1967,7 +1973,15 @@ when defined(js): `x`[off+i] = `y`.charCodeAt(i); } """ - proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} + proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} = + ## Appends `y` to `x` in place. + ## Only implemented for JS backend. + runnableExamples: + when defined(js): + var tmp: cstring = "" + tmp.add(cstring("ab")) + tmp.add(cstring("cd")) + doAssert tmp == cstring("abcd") elif hasAlloc: {.push stackTrace: off, profiler: off.} diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index c4c671ea3c..1c4caf5401 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -634,7 +634,7 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} = asm "`result` = {m_type: `ti`};" else: asm "`result` = {};" - of tySequence, tyOpenArray: + of tySequence, tyOpenArray, tyString: asm """ `result` = []; """ diff --git a/tests/js/tnilstrs.nim b/tests/js/tnilstrs.nim index c0048cb240..6c1e4e4016 100644 --- a/tests/js/tnilstrs.nim +++ b/tests/js/tnilstrs.nim @@ -14,4 +14,12 @@ block: var x = "foo".cstring var y: string add(y, x) - doAssert y == "foo" \ No newline at end of file + doAssert y == "foo" + +block: + type Foo = object + a: string + var foo = Foo(a: "foo") + var y = move foo.a + doAssert foo.a.len == 0 + doAssert y == "foo" diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 6ddec911fc..62f77c8578 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -71,9 +71,58 @@ block: # `$`(SomeInteger) testType int64 testType BiggestInt -block: # #14350 for JS +block: # #14350, #16674, #16686 for JS var cstr: cstring doAssert cstr == cstring(nil) doAssert cstr == nil doAssert cstr.isNil doAssert cstr != cstring("") + doAssert cstr.len == 0 + + when defined(js): + cstr.add(cstring("abc")) + doAssert cstr == cstring("abc") + + var nil1, nil2: cstring = nil + + nil1.add(nil2) + doAssert nil1 == cstring(nil) + doAssert nil2 == cstring(nil) + + nil1.add(cstring("")) + doAssert nil1 == cstring("") + doAssert nil2 == cstring(nil) + + nil1.add(nil2) + doAssert nil1 == cstring("") + doAssert nil2 == cstring(nil) + + nil2.add(nil1) + doAssert nil1 == cstring("") + doAssert nil2 == cstring("") + + +proc main()= + block: + let a = -0.0 + doAssert $a == "-0.0" + doAssert $(-0.0) == "-0.0" + + block: + let a = 0.0 + doAssert $a == "0.0" + doAssert $(0.0) == "0.0" + + block: + let b = -0 + doAssert $b == "0" + doAssert $(-0) == "0" + + block: + let b = 0 + doAssert $b == "0" + doAssert $(0) == "0" + + +static: main() +main()