diff options
-rw-r--r-- | changelogs/changelog_2_0_0.md | 10 | ||||
-rw-r--r-- | compiler/commands.nim | 3 | ||||
-rw-r--r-- | compiler/jsgen.nim | 209 | ||||
-rw-r--r-- | compiler/options.nim | 4 | ||||
-rw-r--r-- | doc/advopt.txt | 2 | ||||
-rw-r--r-- | lib/js/jscore.nim | 11 | ||||
-rw-r--r-- | lib/pure/json.nim | 2 | ||||
-rw-r--r-- | lib/pure/random.nim | 19 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 10 | ||||
-rw-r--r-- | lib/pure/times.nim | 2 | ||||
-rw-r--r-- | lib/std/exitprocs.nim | 2 | ||||
-rw-r--r-- | lib/std/jsbigints.nim | 4 | ||||
-rw-r--r-- | lib/std/private/jsutils.nim | 17 | ||||
-rw-r--r-- | lib/system/ctypes.nim | 12 | ||||
-rw-r--r-- | lib/system/jssys.nim | 26 | ||||
-rw-r--r-- | lib/system/reprjs.nim | 8 | ||||
-rw-r--r-- | tests/js/ttypedarray.nim | 11 | ||||
-rw-r--r-- | tests/lexer/tunary_minus.nim | 4 | ||||
-rw-r--r-- | tests/misc/tints.nim | 20 | ||||
-rw-r--r-- | tests/stdlib/thashes.nim | 2 | ||||
-rw-r--r-- | tests/stdlib/tjson.nim | 7 | ||||
-rw-r--r-- | tests/stdlib/tjsonmacro.nim | 6 | ||||
-rw-r--r-- | tests/stdlib/trandom.nim | 19 | ||||
-rw-r--r-- | tests/stdlib/tstrutils.nim | 18 | ||||
-rw-r--r-- | tests/stdlib/ttimes.nim | 2 | ||||
-rw-r--r-- | tests/system/tdollars.nim | 10 |
26 files changed, 329 insertions, 111 deletions
diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index bef5f6073..02310eea3 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -175,6 +175,16 @@ - - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. +- The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) + for 64-bit integer types (`int64` and `uint64`) by default. As this affects + JS code generation, code using these types to interface with the JS backend + may need to be updated. Note that `int` and `uint` are not affected. + + For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint) + and in the case of potential bugs with the new implementation, the + old behavior is currently still supported with the command line option + `--jsbigint64:off`. + - The `proc` and `iterator` type classes now respectively only match procs and iterators. Previously both type classes matched any of procs or iterators. diff --git a/compiler/commands.nim b/compiler/commands.nim index 0c46a1bc0..4ed21d282 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -336,6 +336,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch) of "panics": result = contains(conf.globalOptions, optPanics) + of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64) else: invalidCmdLineOption(conf, passCmd1, switch, info) proc processPath(conf: ConfigRef; path: string, info: TLineInfo, @@ -1078,6 +1079,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optPanics}, arg, pass, info) if optPanics in conf.globalOptions: defineSymbol(conf.symbols, "nimPanics") + of "jsbigint64": + processOnOffSwitchG(conf, {optJsBigInt64}, arg, pass, info) of "sourcemap": # xxx document in --fullhelp conf.globalOptions.incl optSourcemap conf.options.incl optLineDir diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index a20492740..619555969 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -571,12 +571,20 @@ proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) - let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size) + let size = n[1].typ.skipTypes(abstractRange).size when reassign: let (a, tmp) = maybeMakeTempAssignable(p, n[1], x) - r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp] + if size == 8 and optJsBigInt64 in p.config.globalOptions: + r.res = "$1 = BigInt.asUintN(64, ($4 $2 $3))" % [a, rope op, y.rdLoc, tmp] + else: + let trimmer = unsignedTrimmer(size) + r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp] else: - r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer] + if size == 8 and optJsBigInt64 in p.config.globalOptions: + r.res = "BigInt.asUintN(64, ($1 $2 $3))" % [x.rdLoc, rope op, y.rdLoc] + else: + let trimmer = unsignedTrimmer(size) + r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer] r.kind = resExpr template ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = @@ -618,11 +626,45 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = if i == 0: applyFormat(frmtA) else: applyFormat(frmtB) case op - of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)") - of mSubI: applyFormat("subInt($1, $2)", "($1 - $2)") - of mMulI: applyFormat("mulInt($1, $2)", "($1 * $2)") - of mDivI: applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)") - of mModI: applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)") + of mAddI: + if i == 0: + if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions: + useMagic(p, "addInt64") + applyFormat("addInt64($1, $2)") + else: + applyFormat("addInt($1, $2)") + else: + applyFormat("($1 + $2)") + of mSubI: + if i == 0: + if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions: + useMagic(p, "subInt64") + applyFormat("subInt64($1, $2)") + else: + applyFormat("subInt($1, $2)") + else: + applyFormat("($1 - $2)") + of mMulI: + if i == 0: + if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions: + useMagic(p, "mulInt64") + applyFormat("mulInt64($1, $2)") + else: + applyFormat("mulInt($1, $2)") + else: + applyFormat("($1 * $2)") + of mDivI: + if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions: + useMagic(p, "divInt64") + applyFormat("divInt64($1, $2)", "$1 / $2") + else: + applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)") + of mModI: + if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions: + useMagic(p, "modInt64") + applyFormat("modInt64($1, $2)", "$1 % $2") + else: + applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)") of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)") of mPred: applyFormat("subInt($1, $2)", "($1 - $2)") of mAddF64: applyFormat("($1 + $2)", "($1 + $2)") @@ -631,15 +673,27 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mDivF64: applyFormat("($1 / $2)", "($1 / $2)") of mShrI: applyFormat("", "") of mShlI: - if n[1].typ.size <= 4: - applyFormat("($1 << $2)", "($1 << $2)") + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.size == 8: + if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asIntN(64, $1 << BigInt($2))") + elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asUintN(64, $1 << BigInt($2))") + else: + applyFormat("($1 * Math.pow(2, $2))") else: - applyFormat("($1 * Math.pow(2, $2))", "($1 * Math.pow(2, $2))") + applyFormat("($1 << $2)", "($1 << $2)") of mAshrI: - if n[1].typ.size <= 4: - applyFormat("($1 >> $2)", "($1 >> $2)") + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.size == 8: + if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asIntN(64, $1 >> BigInt($2))") + elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asUintN(64, $1 >> BigInt($2))") + else: + applyFormat("Math.floor($1 / Math.pow(2, $2))") else: - applyFormat("Math.floor($1 / Math.pow(2, $2))", "Math.floor($1 / Math.pow(2, $2))") + applyFormat("($1 >> $2)", "($1 >> $2)") of mBitandI: applyFormat("($1 & $2)", "($1 & $2)") of mBitorI: applyFormat("($1 | $2)", "($1 | $2)") of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)") @@ -697,7 +751,9 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mMulU: binaryUintExpr(p, n, r, "*") of mDivU: binaryUintExpr(p, n, r, "/") - if n[1].typ.skipTypes(abstractRange).size == 8: + if optJsBigInt64 notin p.config.globalOptions and + n[1].typ.skipTypes(abstractRange).size == 8: + # bigint / already truncates r.res = "Math.trunc($1)" % [r.res] of mDivI: arithAux(p, n, r, op) @@ -707,7 +763,13 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) - r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc] + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + r.res = "BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))" % [x.rdLoc, y.rdLoc] + elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + r.res = "($1 >> BigInt($2))" % [x.rdLoc, y.rdLoc] + else: + r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc] of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr: arithAux(p, n, r, op) of mEqRef: @@ -1764,15 +1826,25 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v createRecordVarAux(p, t.n, excludedFieldIDs, output) t = t[0] -proc arrayTypeForElemType(typ: PType): string = +proc arrayTypeForElemType(conf: ConfigRef; typ: PType): string = let typ = typ.skipTypes(abstractRange) case typ.kind of tyInt, tyInt32: "Int32Array" of tyInt16: "Int16Array" of tyInt8: "Int8Array" + of tyInt64: + if optJsBigInt64 in conf.globalOptions: + "BigInt64Array" + else: + "" of tyUInt, tyUInt32: "Uint32Array" of tyUInt16: "Uint16Array" of tyUInt8, tyChar, tyBool: "Uint8Array" + of tyUInt64: + if optJsBigInt64 in conf.globalOptions: + "BigUint64Array" + else: + "" of tyFloat32: "Float32Array" of tyFloat64, tyFloat: "Float64Array" of tyEnum: @@ -1786,11 +1858,18 @@ proc arrayTypeForElemType(typ: PType): string = proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) case t.kind - of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: + of tyInt8..tyInt32, tyUInt8..tyUInt32, tyEnum, tyChar: + result = putToSeq("0", indirect) + of tyInt, tyUInt: if $t.sym.loc.r == "bigint": result = putToSeq("0n", indirect) else: result = putToSeq("0", indirect) + of tyInt64, tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + result = putToSeq("0n", indirect) + else: + result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent: @@ -1804,7 +1883,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = of tyArray: let length = toInt(lengthOrd(p.config, t)) let e = elemType(t) - let jsTyp = arrayTypeForElemType(e) + let jsTyp = arrayTypeForElemType(p.config, e) if jsTyp.len > 0: result = "new $1($2)" % [rope(jsTyp), rope(length)] elif length > 32: @@ -1979,7 +2058,11 @@ proc genNewSeq(p: PProc, n: PNode) = proc genOrd(p: PProc, n: PNode, r: var TCompRes) = case skipTypes(n[1].typ, abstractVar + abstractRange).kind - of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r) + of tyEnum, tyInt..tyInt32, tyUInt..tyUInt32, tyChar: gen(p, n[1], r) + of tyInt64, tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + unaryExpr(p, n, r, "", "Number($1)") + else: gen(p, n[1], r) of tyBool: unaryExpr(p, n, r, "", "($1 ? 1 : 0)") else: internalError(p.config, n.info, "genOrd") @@ -2202,14 +2285,34 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = r.res = "($1).length - 1" % [x.rdLoc] r.kind = resExpr of mInc: - if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: + let typ = n[1].typ.skipTypes(abstractVarRange) + case typ.kind + of tyUInt..tyUInt32: binaryUintExpr(p, n, r, "+", true) + of tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 + BigInt($2))", true) + else: binaryUintExpr(p, n, r, "+", true) + elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if optOverflowCheck notin p.options: + binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 + BigInt($2))", true) + else: binaryExpr(p, n, r, "addInt64", "$1 = addInt64($3, BigInt($2))", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2") else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true) of ast.mDec: - if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: + let typ = n[1].typ.skipTypes(abstractVarRange) + case typ.kind + of tyUInt..tyUInt32: binaryUintExpr(p, n, r, "-", true) + of tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 - BigInt($2))", true) + else: binaryUintExpr(p, n, r, "+", true) + elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if optOverflowCheck notin p.options: + binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 - BigInt($2))", true) + else: binaryExpr(p, n, r, "subInt64", "$1 = subInt64($3, BigInt($2))", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true) @@ -2303,7 +2406,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = ## Nim sequence maps to JS array. var t = skipTypes(n.typ, abstractInst) let e = elemType(t) - let jsTyp = arrayTypeForElemType(e) + let jsTyp = arrayTypeForElemType(p.config, e) if skipTypes(n.typ, abstractVarRange).kind != tySequence and jsTyp.len > 0: # generate typed array # for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]` @@ -2384,7 +2487,27 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) = r.res = "(!!($1))" % [r.res] r.kind = resExpr elif toInt: - r.res = "(($1) | 0)" % [r.res] + if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] + else: + r.res = "(($1) | 0)" % [r.res] + elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyUInt64: + r.res = "BigInt.asIntN(64, $1)" % [r.res] + elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyInt64: + r.res = "BigInt.asUintN(64, $1)" % [r.res] + elif toUint or dest.kind in tyFloat..tyFloat64: + if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] else: # TODO: What types must we handle here? discard @@ -2395,7 +2518,11 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) = proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = var a, b: TCompRes gen(p, n[0], r) - if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and + let src = skipTypes(n[0].typ, abstractVarRange) + let dest = skipTypes(n.typ, abstractVarRange) + if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] + if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures): discard "XXX maybe emit masking instructions here" else: @@ -2587,6 +2714,8 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = if toUint and (fromInt or fromUint): let trimmer = unsignedTrimmer(dest.size) r.res = "($1 $2)" % [r.res, trimmer] + elif toUint and src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number(BigInt.asUintN($1, $2))" % [$(dest.size * 8), r.res] elif toInt: if fromInt: return @@ -2602,6 +2731,25 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = of 4: "0xfffffffe" else: "" r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer] + elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number(BigInt.asIntN($1, $2))" % [$(dest.size * 8), r.res] + elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyUInt64: + r.res = "BigInt.asIntN(64, $1)" % [r.res] + elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyInt64: + r.res = "BigInt.asUintN(64, $1)" % [r.res] + elif dest.kind in tyFloat..tyFloat64: + if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer: r.address = r.res r.res = "null" @@ -2620,8 +2768,17 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkSym: genSym(p, n, r) of nkCharLit..nkUInt64Lit: - if n.typ.kind == tyBool: + case n.typ.skipTypes(abstractVarRange).kind + of tyBool: r.res = if n.intVal == 0: rope"false" else: rope"true" + of tyUInt64: + r.res = rope($cast[BiggestUInt](n.intVal)) + if optJsBigInt64 in p.config.globalOptions: + r.res.add('n') + of tyInt64: + r.res = rope(n.intVal) + if optJsBigInt64 in p.config.globalOptions: + r.res.add('n') else: r.res = rope(n.intVal) r.kind = resExpr diff --git a/compiler/options.nim b/compiler/options.nim index 6df9723f2..da9c9cbbb 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -106,6 +106,7 @@ type # please make sure we have under 32 options optProfileVM # enable VM profiler optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types. optShowNonExportedFields # for documentation: show fields that are not exported + optJsBigInt64 # use bigints for 64-bit integers in JS TGlobalOptions* = set[TGlobalOption] @@ -476,7 +477,8 @@ const optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs` optTrMacros, optStyleCheck, optCursorInference} - DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace} + DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace, + optJsBigInt64} proc getSrcTimestamp(): DateTime = try: diff --git a/doc/advopt.txt b/doc/advopt.txt index 03649ffdd..9a3912e35 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -174,3 +174,5 @@ Advanced options: --sinkInference:on|off turn sink parameter inference on|off (default: off) --panics:on|off turn panics into process terminations (default: off) --deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc`` + --jsbigint64:on|off toggle the use of [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) + for 64-bit integers on the JavaScript backend (default: on) diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index 781e8fd57..5147b550d 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -13,7 +13,7 @@ ## specific requirements and solely targets JavaScript, you should be using ## the relevant functions in the `math`, `json`, and `times` stdlib ## modules instead. -import std/private/since +import std/private/[since, jsutils] when not defined(js): {.error: "This module only works on the JavaScript platform".} @@ -74,9 +74,16 @@ proc parse*(d: DateLib, s: cstring): int {.importcpp.} proc newDate*(): DateTime {. importcpp: "new Date()".} -proc newDate*(date: int|int64|string): DateTime {. +proc newDate*(date: int|string): DateTime {. importcpp: "new Date(#)".} +whenJsNoBigInt64: + proc newDate*(date: int64): DateTime {. + importcpp: "new Date(#)".} +do: + proc newDate*(date: int64): DateTime {. + importcpp: "new Date(Number(#))".} + proc newDate*(year, month, day, hours, minutes, seconds, milliseconds: int): DateTime {. importcpp: "new Date(#,#,#,#,#,#,#)".} diff --git a/lib/pure/json.nim b/lib/pure/json.nim index d91da3545..45b22cea5 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1110,7 +1110,7 @@ proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = dst = jsonNode.copy proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = - when T is uint|uint64 or (not defined(js) and int.sizeof == 4): + when T is uint|uint64 or int.sizeof == 4: verifyJsonKind(jsonNode, {JInt, JString}, jsonPath) case jsonNode.kind of JString: diff --git a/lib/pure/random.nim b/lib/pure/random.nim index c36ab445b..422f42a8b 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -72,7 +72,7 @@ runnableExamples: ## in the standard library import algorithm, math -import std/private/since +import std/private/[since, jsutils] when defined(nimPreviewSlimSystem): import std/[assertions] @@ -231,11 +231,14 @@ proc rand[T: uint | uint64](r: var Rand; max: T): T = let max = uint64(max) when T.high.uint64 == uint64.high: if max == uint64.high: return T(next(r)) + var iters = 0 while true: let x = next(r) # avoid `mod` bias - if x <= randMax - (randMax mod max): + if x <= randMax - (randMax mod max) or iters > 20: return T(x mod (max + 1)) + else: + inc iters proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random integer in the range `0..max` using the given state. @@ -337,9 +340,9 @@ proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = when T is SomeFloat: result = rand(r, x.b - x.a) + x.a else: # Integers and Enum types - when defined(js): + whenJsNoBigInt64: result = cast[T](rand(r, cast[uint](x.b) - cast[uint](x.a)) + cast[uint](x.a)) - else: + do: result = cast[T](rand(r, cast[uint64](x.b) - cast[uint64](x.a)) + cast[uint64](x.a)) proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = @@ -378,14 +381,14 @@ proc rand*[T: Ordinal](r: var Rand; t: typedesc[T]): T {.since: (1, 7, 1).} = when T is range or T is enum: result = rand(r, low(T)..high(T)) elif T is bool: - when defined(js): + whenJsNoBigInt64: result = (r.next or 0) < 0 - else: + do: result = cast[int64](r.next) < 0 else: - when defined(js): + whenJsNoBigInt64: result = cast[T](r.next shr (sizeof(uint)*8 - sizeof(T)*8)) - else: + do: result = cast[T](r.next shr (sizeof(uint64)*8 - sizeof(T)*8)) proc rand*[T: Ordinal](t: typedesc[T]): T = diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index c458d605e..0a77e8bf6 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -79,7 +79,7 @@ from unicode import toLower, toUpper export toLower, toUpper include "system/inclrtl" -import std/private/since +import std/private/[since, jsutils] from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, startsWithImpl, endsWithImpl @@ -944,9 +944,9 @@ func toHex*[T: SomeInteger](x: T, len: Positive): string = doAssert b.toHex(4) == "1001" doAssert toHex(62, 3) == "03E" doAssert toHex(-8, 6) == "FFFFF8" - when defined(js): + whenJsNoBigInt64: toHexImpl(cast[BiggestUInt](x), len, x < 0) - else: + do: when T is SomeSignedInt: toHexImpl(cast[BiggestUInt](BiggestInt(x)), len, x < 0) else: @@ -957,9 +957,9 @@ func toHex*[T: SomeInteger](x: T): string = runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" doAssert toHex(1984'i16) == "07C0" - when defined(js): + whenJsNoBigInt64: toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) - else: + do: when T is SomeSignedInt: toHexImpl(cast[BiggestUInt](BiggestInt(x)), 2*sizeof(T), x < 0) else: diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 138f2d9ec..3d644d361 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -537,7 +537,7 @@ proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay assertValidDate monthday, month, year # 1970-01-01 is a Thursday, we adjust to the previous Monday let days = toEpochDay(monthday, month, year) - 3 - let weeks = floorDiv(days, 7) + let weeks = floorDiv(days, 7'i64) let wd = days - weeks * 7 # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. # so we must correct for the WeekDay type. diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index 48b4fca7f..36f22a5d1 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -10,6 +10,8 @@ ## This module allows adding hooks to program exit. import locks +when defined(js) and not defined(nodejs): + import std/assertions type FunKind = enum kClosure, kNoconv # extend as needed diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim index 04578fc87..fda299e7b 100644 --- a/lib/std/jsbigints.nim +++ b/lib/std/jsbigints.nim @@ -64,10 +64,10 @@ func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs: runnableExamples: doAssert (big("3") + big("2") ** big("66")).wrapToUint(66) == big("3") -func toNumber*(this: JsBigInt): BiggestInt {.importjs: "Number(#)".} = +func toNumber*(this: JsBigInt): int {.importjs: "Number(#)".} = ## Does not do any bounds check and may or may not return an inexact representation. runnableExamples: - doAssert toNumber(big"2147483647") == 2147483647.BiggestInt + doAssert toNumber(big"2147483647") == 2147483647.int func `+`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} = runnableExamples: diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim index 836b3512a..fd1f395f3 100644 --- a/lib/std/private/jsutils.nim +++ b/lib/std/private/jsutils.nim @@ -79,5 +79,18 @@ when defined(js): assert not "123".toJs.isSafeInteger assert 123.isSafeInteger assert 123.toJs.isSafeInteger - assert 9007199254740991.toJs.isSafeInteger - assert not 9007199254740992.toJs.isSafeInteger + when false: + assert 9007199254740991.toJs.isSafeInteger + assert not 9007199254740992.toJs.isSafeInteger + +template whenJsNoBigInt64*(no64, yes64): untyped = + when defined(js): + when compiles(compileOption("jsbigint64")): + when compileOption("jsbigint64"): + yes64 + else: + no64 + else: + no64 + else: + no64 diff --git a/lib/system/ctypes.nim b/lib/system/ctypes.nim index f6a341477..b788274bd 100644 --- a/lib/system/ctypes.nim +++ b/lib/system/ctypes.nim @@ -12,16 +12,10 @@ type ## compiler supports. Currently this is `float64`, but it is ## platform-dependent in general. -when defined(js): - type BiggestUInt* = uint32 + BiggestUInt* = uint64 ## is an alias for the biggest unsigned integer type the Nim compiler - ## supports. Currently this is `uint32` for JS and `uint64` for other - ## targets. -else: - type BiggestUInt* = uint64 - ## is an alias for the biggest unsigned integer type the Nim compiler - ## supports. Currently this is `uint32` for JS and `uint64` for other - ## targets. + ## supports. Currently this is `uint64`, but it is platform-dependent + ## in general. when defined(windows): type diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 4f64403fe..3bf506e1e 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -451,44 +451,44 @@ proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = return Math.trunc(`a` % `b`); """ -proc checkOverflowInt64(a: int) {.asmNoStackFrame, compilerproc.} = +proc checkOverflowInt64(a: int64) {.asmNoStackFrame, compilerproc.} = asm """ - if (`a` > 9223372036854775807 || `a` < -9223372036854775808) `raiseOverflow`(); + if (`a` > 9223372036854775807n || `a` < -9223372036854775808n) `raiseOverflow`(); """ -proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc addInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` + `b`; `checkOverflowInt64`(result); return result; """ -proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc subInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` - `b`; `checkOverflowInt64`(result); return result; """ -proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc mulInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` * `b`; `checkOverflowInt64`(result); return result; """ -proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc divInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` / `b`); + if (`b` == 0n) `raiseDivByZero`(); + if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); + return `a` / `b`; """ -proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc modInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` % `b`); + if (`b` == 0n) `raiseDivByZero`(); + if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); + return `a` % `b`; """ proc negInt(a: int): int {.compilerproc.} = diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index 0818f9cc9..30e84ebee 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -12,6 +12,8 @@ when defined(nimPreviewSlimSystem): import std/formatfloat proc reprInt(x: int64): string {.compilerproc.} = $x +proc reprInt(x: uint64): string {.compilerproc.} = $x +proc reprInt(x: int): string {.compilerproc.} = $x proc reprFloat(x: float): string {.compilerproc.} = $x proc reprPointer(p: pointer): string {.compilerproc.} = @@ -192,8 +194,12 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, return dec(cl.recDepth) case typ.kind - of tyInt..tyInt64, tyUInt..tyUInt64: + of tyInt..tyInt32, tyUInt..tyUInt32: add(result, reprInt(cast[int](p))) + of tyInt64: + add(result, reprInt(cast[int64](p))) + of tyUInt64: + add(result, reprInt(cast[uint64](p))) of tyChar: add(result, reprChar(cast[char](p))) of tyBool: diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim index 222f66569..08b5fcdde 100644 --- a/tests/js/ttypedarray.nim +++ b/tests/js/ttypedarray.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--jsbigint64:off; --jsbigint64:on" +""" + import std/private/jsutils proc main()= @@ -5,9 +9,10 @@ proc main()= doAssert fn(array[2, int8].default) == "Int8Array" doAssert fn(array[2, uint8].default) == "Uint8Array" doAssert fn(array[2, byte].default) == "Uint8Array" - # doAssert fn(array[2, char].default) == "Uint8Array" # xxx fails; bug? - doAssert fn(array[2, uint64].default) == "Array" - # pending https://github.com/nim-lang/RFCs/issues/187 maybe use `BigUint64Array` + doAssert fn(array[2, char].default) == "Uint8Array" + whenJsNoBigInt64: discard + do: + doAssert fn(array[2, uint64].default) == "BigUint64Array" doAssert fn([1'u8]) == "Uint8Array" doAssert fn([1'u16]) == "Uint16Array" doAssert fn([byte(1)]) == "Uint8Array" diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim index 1641e918c..5ec2b5c70 100644 --- a/tests/lexer/tunary_minus.nim +++ b/tests/lexer/tunary_minus.nim @@ -5,6 +5,7 @@ discard """ # Test numeric literals and handling of minus symbol import std/[macros, strutils] +import std/private/jsutils import mlexerutils @@ -60,7 +61,8 @@ template main = doAssert -2147483648'i32 == int32.low when int.sizeof > 4: doAssert -9223372036854775808 == int.low - when not defined(js): + whenJsNoBigInt64: discard + do: doAssert -9223372036854775808 == int64.low block: # check when a minus (-) is an unary op diff --git a/tests/misc/tints.nim b/tests/misc/tints.nim index d24cbd4ac..cb77d4d89 100644 --- a/tests/misc/tints.nim +++ b/tests/misc/tints.nim @@ -1,4 +1,5 @@ discard """ + matrix: "; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" output: ''' 0 0 0 0 @@ -6,6 +7,8 @@ Success''' """ # Test the different integer operations +import std/private/jsutils + var testNumber = 0 template test(opr, a, b, c: untyped): untyped = @@ -23,28 +26,37 @@ template test(opr, a, b, c: untyped): untyped = test(`+`, 12'i8, -13'i16, -1'i16) test(`shl`, 0b11, 0b100, 0b110000) +whenJsNoBigInt64: discard +do: + test(`shl`, 0b11'i64, 0b100'i64, 0b110000'i64) when not defined(js): + # mixed type shr needlessly complicates codegen with bigint + # and thus is not yet supported in JS for 64 bit ints test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64) test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32) test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16) test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16) -when not defined(js): +whenJsNoBigInt64: discard +do: test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0xffffffffffffffff'i64) test(`shr`, 0xffff'i16, 0x4'i16, 0xffff'i16) test(`shr`, 0xff'i8, 0x4'i8, 0xff'i8) -when not defined(js): +whenJsNoBigInt64: discard +do: test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64) test(`shr`, 0xffffffff'i32, 0x4'i32, 0xffffffff'i32) -when not defined(js): +whenJsNoBigInt64: discard +do: test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64) test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16) test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8) -when not defined(js): +whenJsNoBigInt64: discard +do: test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64) test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32) diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index caae79213..526a2839f 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,5 +1,5 @@ discard """ - targets: "c cpp js" + matrix: "; --backend:cpp; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" """ import std/hashes diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index a60d45aab..691bedeaa 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -1,6 +1,5 @@ discard """ - matrix: "--mm:refc" - targets: "c cpp js" + matrix: "--mm:refc; --backend:cpp --mm:refc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" """ @@ -9,6 +8,7 @@ Note: Macro tests are in tests/stdlib/tjsonmacro.nim ]# import std/[json,parsejson,strutils] +import std/private/jsutils from std/math import isNaN when not defined(js): import std/streams @@ -314,7 +314,8 @@ block: # bug #17383 else: testRoundtrip(int.high): "9223372036854775807" testRoundtrip(uint.high): "18446744073709551615" - when not defined(js): + whenJsNoBigInt64: discard + do: testRoundtrip(int64.high): "9223372036854775807" testRoundtrip(uint64.high): "18446744073709551615" diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 9c1fa833d..f08c3946b 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -436,11 +436,7 @@ proc testJson() = block: let s = """{"a": 1, "b": 2}""" let t = parseJson(s).to(Table[string, int]) - when not defined(js): - # For some reason on the JS backend `{"b": 2, "a": 0}` is - # sometimes the value of `t`. This needs investigation. I can't - # reproduce it right now in an isolated test. - doAssert t["a"] == 1 + doAssert t["a"] == 1 doAssert t["b"] == 2 block: diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index ef71c3442..c35fc47da 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -1,9 +1,10 @@ discard """ joinable: false # to avoid messing with global rand state - targets: "c js" + matrix: "; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" """ import std/[assertions, formatfloat] import std/[random, math, stats, sets, tables] +import std/private/jsutils when not defined(js): import std/os @@ -208,8 +209,8 @@ block: # bug #16360 when withUint: test cast[uint](int.high) test cast[uint](int.high) + 1 - when not defined(js): - # pending bug #16411 + whenJsNoBigInt64: discard + do: test uint64.high test uint64.high - 1 test uint.high - 2 @@ -239,16 +240,12 @@ block: # bug #16296 test(int.low .. -1) test(int.low .. 1) test(int64.low .. 1'i64) - when not defined(js): - # pending bug #16411 - test(10'u64 .. uint64.high) + test(10'u64 .. uint64.high) block: # bug #17670 - when not defined(js): - # pending bug #16411 - type UInt48 = range[0'u64..2'u64^48-1] - let x = rand(UInt48) - doAssert x is UInt48 + type UInt48 = range[0'u64..2'u64^48-1] + let x = rand(UInt48) + doAssert x is UInt48 block: # bug #17898 # Checks whether `initRand()` generates unique states. diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 4e88197ff..12b0c13b1 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -1,10 +1,11 @@ discard """ - targets: "c cpp js" + matrix: "; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" """ import std/strutils from stdtest/testutils import disableVm import std/assertions +import std/private/jsutils # xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed template rejectParse(e) = @@ -509,7 +510,8 @@ template main() = block: # toHex doAssert(toHex(100i16, 32) == "00000000000000000000000000000064") doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") - when not defined js: + whenJsNoBigInt64: discard + do: doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") @@ -530,11 +532,12 @@ template main() = doAssert(spaces(0) == "") block: # toBin, toOct - block:# bug #11369 + whenJsNoBigInt64: # bug #11369 + discard + do: var num: int64 = -1 - when not defined js: - doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" - doAssert num.toOct(24) == "001777777777777777777777" + doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" + doAssert num.toOct(24) == "001777777777777777777777" block: # replace doAssert "oo".replace("", "abc") == "oo" @@ -741,7 +744,8 @@ bar block: # formatSize disableVm: - when not defined(js): + whenJsNoBigInt64: discard + do: doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" doAssert formatSize(4096) == "4KiB" diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index f6159d942..47d2efcf1 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -1,5 +1,5 @@ discard """ - targets: "c js" + matrix: "; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" """ import times, strutils, unittest diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 93fa5cb9e..7eb26cd6b 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -1,5 +1,5 @@ discard """ - targets: "c cpp js" + matrix: "; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" """ #[ @@ -12,6 +12,7 @@ duplication (which always results in weaker test coverage in practice). ]# import std/unittest +import std/private/jsutils template test[T](a: T, expected: string) = check $a == expected var b = a @@ -66,7 +67,8 @@ block: # `$`(SomeInteger) testType int testType bool - when not defined(js): # requires BigInt support + whenJsNoBigInt64: discard + do: testType uint64 testType int64 testType BiggestInt @@ -176,10 +178,10 @@ proc main()= res.addInt int64(i) doAssert res == "-9-8-7-6-5-4-3-2-10" - when not defined(js): + whenJsNoBigInt64: discard + do: test2 high(int64), "9223372036854775807" test2 low(int64), "-9223372036854775808" - test2 high(int32), "2147483647" test2 low(int32), "-2147483648" test2 high(int16), "32767" |