From 9bd38a470c2e9e3ec7538058ecbb89deec5ecc5b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 10 Oct 2020 13:53:49 -0700 Subject: [PATCH] fix #15413: Json now supports numbers in int64.high+1 .. uint64.high --- lib/pure/json.nim | 31 +++++++++++++++++++++++++++++-- lib/system.nim | 3 +++ lib/system/strmantle.nim | 17 +++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 3f2e369f61442..01b404fd66387 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -173,7 +173,8 @@ type JFloat, JString, JObject, - JArray + JArray, + JUInt JsonNode* = ref JsonNodeObj ## JSON node JsonNodeObj* {.acyclic.} = object @@ -182,6 +183,8 @@ type str*: string of JInt: num*: BiggestInt + of JUInt: + unum*: BiggestUInt of JFloat: fnum*: float of JBool: @@ -205,6 +208,10 @@ proc newJInt*(n: BiggestInt): JsonNode = ## Creates a new `JInt JsonNode`. result = JsonNode(kind: JInt, num: n) +proc newJUInt*(n: BiggestUInt): JsonNode = + ## Creates a new `JUInt JsonNode`. + result = JsonNode(kind: JUInt, unum: n) + proc newJFloat*(n: float): JsonNode = ## Creates a new `JFloat JsonNode`. result = JsonNode(kind: JFloat, fnum: n) @@ -419,6 +426,8 @@ proc `==`*(a, b: JsonNode): bool = result = a.str == b.str of JInt: result = a.num == b.num + of JUInt: + result = a.unum == b.unum of JFloat: result = a.fnum == b.fnum of JBool: @@ -447,6 +456,8 @@ proc hash*(n: JsonNode): Hash = result = hash(n.fields) of JInt: result = hash(n.num) + of JUInt: + result = hash(n.unum) of JFloat: result = hash(n.fnum) of JBool: @@ -564,6 +575,8 @@ proc copy*(p: JsonNode): JsonNode = result = newJString(p.str) of JInt: result = newJInt(p.num) + of JUInt: + result = newJUInt(p.unum) of JFloat: result = newJFloat(p.fnum) of JBool: @@ -657,6 +670,11 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, if lstArr: result.indent(currIndent) when defined(js): result.add($node.num) else: result.addInt(node.num) + of JUInt: + if lstArr: result.indent(currIndent) + when defined(js): result.add($node.unum) + else: + result.addInt(node.unum) of JFloat: if lstArr: result.indent(currIndent) # Fixme: implement new system.add ops for the JS target @@ -738,6 +756,9 @@ proc toUgly*(result: var string, node: JsonNode) = of JInt: when defined(js): result.add($node.num) else: result.addInt(node.num) + of JUInt: + when defined(js): result.add($node.unum) + else: result.addInt(node.unum) of JFloat: when defined(js): result.add($node.fnum) else: result.addFloat(node.fnum) @@ -792,7 +813,11 @@ proc parseJson(p: var JsonParser): JsonNode = p.a = "" discard getTok(p) of tkInt: - result = newJInt(parseBiggestInt(p.a)) + try: + result = newJInt(parseBiggestInt(p.a)) + except ValueError: + # this can still raise for numbers outside of 64bit range + result = newJUInt(parseBiggestUInt(p.a)) discard getTok(p) of tkFloat: result = newJFloat(parseFloat(p.a)) @@ -921,6 +946,8 @@ when defined(js): asm "}}" of JInt: result = newJInt(cast[int](x)) + of JUInt: + result = newJUInt(cast[uint](x)) of JFloat: result = newJFloat(cast[float](x)) of JString: diff --git a/lib/system.nim b/lib/system.nim index e41dfe1ca9f31..209488d5ff629 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2402,6 +2402,9 @@ when defined(js) or defined(nimscript): proc addInt*(result: var string; x: int64) = result.add $x + proc addInt*(result: var string; x: uint64) = + addInt(result, cast[int64](x)) # checkme + proc addFloat*(result: var string; x: float) = result.add $x diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 43a769b5f795b..08d23039c7356 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -66,6 +66,23 @@ proc addInt*(result: var string; x: int64) = for j in 0..i div 2 - 1: swap(result[base+j], result[base+i-j-1]) +proc addInt*(result: var string; x: uint64) = + # PRTEMP: TODO: add tests + let base = result.len + setLen(result, base + sizeof(x)*4) + var i = 0 + var y = x + while true: + var d = y div 10 + result[base+i] = chr(abs(int(y - d*10)) + ord('0')) + inc(i) + y = d + if y == 0: break + setLen(result, base+i) + # mirror the string: + for j in 0..i div 2 - 1: + swap(result[base+j], result[base+i-j-1]) + proc nimIntToStr(x: int): string {.compilerRtl.} = result = newStringOfCap(sizeof(x)*4) result.addInt x