From 040adf415bbeb7330abf8770b8ac7987dfffc974 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 6 Jan 2021 11:28:24 -0800 Subject: [PATCH] [backport 1.0] add backend support for js bigint (#16606) * add backend support for js bigint * cleanup * add tests * add -d:nimHasJsBigIntBackend * cleanup * more tests (cherry picked from commit 025ca660f7fe396ec6794137c29845feaf7ab9a3) --- compiler/condsyms.nim | 1 + compiler/jsgen.nim | 5 +++- tests/js/tbigint_backend.nim | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/js/tbigint_backend.nim diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index b4d7249e72..c4f23603f7 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -117,3 +117,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasInvariant") defineSymbol("nimHasStacktraceMsgs") defineSymbol("nimHasStacktracesModule") + defineSymbol("nimHasJsBigIntBackend") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index e5b60f0ae1..ba10e0497e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1591,7 +1591,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) case t.kind of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: - result = putToSeq("0", indirect) + if $t.sym.loc.r == "bigint": + result = putToSeq("0n", indirect) + else: + result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) of tyRange, tyGenericInst, tyAlias, tySink, tyOwned: diff --git a/tests/js/tbigint_backend.nim b/tests/js/tbigint_backend.nim new file mode 100644 index 0000000000..db7ebb065f --- /dev/null +++ b/tests/js/tbigint_backend.nim @@ -0,0 +1,58 @@ +proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".} + ## Returns the name of the JsObject's JavaScript type as a cstring. + # xxx replace jsffi.jsTypeOf with this definition and add tests + +type JsBigIntImpl {.importc: "bigint".} = int +type JsBigInt = distinct JsBigIntImpl + +doAssert JsBigInt isnot int +func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} +func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} +func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} +func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".} +func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".} +func inc2*(x: var JsBigInt) {.importjs: "#++".} +func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".} +func `$`*(this: JsBigInt): string = + $toCstring(this) + +block: + doAssert defined(nimHasJsBigIntBackend) + let z1 = big"10" + let z2 = big"15" + doAssert z1 == big"10" + doAssert z1 == z1 + doAssert z1 != z2 + var s: seq[cstring] + for i in z1 .. z2: + s.add $i + doAssert s == @["10".cstring, "11", "12", "13", "14", "15"] + block: + var a=big"3" + a.inc + doAssert a == big"4" + block: + var z: JsBigInt + doAssert $z == "0" + doAssert z.jsTypeOf == "bigint" # would fail without codegen change + doAssert z != big(1) + doAssert z == big"0" # ditto + + # ditto below + block: + let z: JsBigInt = big"1" + doAssert $z == "1" + doAssert z.jsTypeOf == "bigint" + doAssert z == big"1" + + block: + let z = JsBigInt.default + doAssert $z == "0" + doAssert z.jsTypeOf == "bigint" + doAssert z == big"0" + + block: + var a: seq[JsBigInt] + a.setLen 3 + doAssert a[^1].jsTypeOf == "bigint" + doAssert a[^1] == big"0"