Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions json_serialization/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import
./reader_desc,
./lexer

from json import JsonNode, JsonNodeKind, escapeJson
from json import JsonNode, JsonNodeKind, escapeJson, parseJson

export
reader_desc
Expand Down Expand Up @@ -418,7 +418,7 @@ template parseObjectSkipNullFields*(r: var JsonReader, key: untyped, body: untyp
body
do: # error action
r.raiseParserError()

template parseObjectCustomKey*(r: var JsonReader, keyAction: untyped, body: untyped) =
mixin flavorSkipNullFields
type
Expand Down Expand Up @@ -456,14 +456,33 @@ proc parseJsonNode(r: var JsonReader): JsonNode =
of JsonValueKind.String:
result = JsonNode(kind: JString, str: r.parseString())
of JsonValueKind.Number:
var val: JsonNumber[uint64]
r.lex.scanNumber(val)
r.checkError
if val.isFloat:
result = JsonNode(kind: JFloat, fnum: r.toFloat(val, typeof(result.fnum)))
if JsonReaderFlag.legacyJsonNodeNumber in r.lex.flags:
var val: JsonNumber[uint64]
r.lex.scanNumber(val)
r.checkError
if val.isFloat:
result = JsonNode(kind: JFloat, fnum: r.toFloat(val, typeof(result.fnum)))
else:
result = JsonNode(kind: JInt, num:
r.toInt(val, typeof(result.num), JsonReaderFlag.portableInt in r.lex.flags))
else:
result = JsonNode(kind: JInt, num:
r.toInt(val, typeof(result.num), JsonReaderFlag.portableInt in r.lex.flags))
var val: string
r.lex.scanNumber(val)
r.checkError
when (NimMajor, NimMinor) > (1,6):
try:
# Cannot access `newJRawNumber` directly, because it's not exported.
# But this should produce either JInt, JFloat, or JString/Raw
result = parseJson(val)
except ValueError as exc:
r.raiseUnexpectedValue(exc.msg)
except OSError as exc:
raiseAssert "parseJson here should not raise OSError exception: " & exc.msg
else:
try:
result = parseJson(val)
except Exception as exc:
r.raiseUnexpectedValue(exc.msg)
of JsonValueKind.Object:
result = JsonNode(kind: JObject)
parseObjectImpl(r.lex, false): discard # initial action
Expand Down
1 change: 1 addition & 0 deletions json_serialization/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type
allowComments # on
leadingFraction # on
integerPositiveSign # on
legacyJsonNodeNumber

JsonReaderFlags* = set[JsonReaderFlag]

Expand Down
38 changes: 36 additions & 2 deletions tests/test_parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ const
}
}

"""

jsonBigNum = """
{
"bignum": 9999999999999999999999999999999999999999999,
"float": 124.123,
"int": -12345
}
"""

suite "Parse to runtime dynamic structure":
Expand All @@ -345,6 +353,7 @@ suite "Parse to runtime dynamic structure":
n["array"][0].bval == true
n["array"][1].fnum == 567.89
n["array"][2].str == "string in array"
$n["array"][2] == "\"string in array\"" # quoted string
n["array"][3].kind == JNull
n["array"][4].kind == JArray
n["array"][4].len == 1
Expand All @@ -358,6 +367,7 @@ suite "Parse to runtime dynamic structure":
check:
n["string"].strVal == "hello world"
n["bool"].boolVal == true
n["int"].numVal.integer == 789
n["array"].len == 5
n["array"][0].boolVal == true
n["array"][2].strVal == "string in array"
Expand All @@ -366,14 +376,38 @@ suite "Parse to runtime dynamic structure":
n["array"][4].len == 1
n["object"]["def"].boolVal == false

test "parse to json node bignum":
var r = toReader(jsonBigNum)
let n = r.parseJsonNode()
check:
n["bignum"].kind == JString
n["bignum"].str == "9999999999999999999999999999999999999999999"
$n["bignum"] == "9999999999999999999999999999999999999999999" # unquoted raw string
n["float"].kind == JFloat
n["float"].fnum == 124.123
n["int"].kind == JInt
n["int"].num == -12345

test "parseValue bignum":
var r = toReader(jsonBigNum)
let n = r.parseValue(string)
check:
n["bignum"].kind == JsonValueKind.Number
n["bignum"].numVal.integer == "9999999999999999999999999999999999999999999"

test "parseValue bignum overflow":
var r = toReader(jsonBigNum)
expect JsonReaderError:
let n = r.parseValue(uint64)

test "nim v2 regression #23233":
# Nim compiler bug #23233 will prevent
# compilation if both JsonValueRef[uint64] and JsonValueRef[string]
# are instantiated at together.
var r1 = toReader(jsonText)
let n1 = r1.parseValue(uint64)
discard n1
check n1["int"].numVal.integer == 789

var r2 = toReader(jsonText)
let n2 = r2.parseValue(string)
discard n2
check n2["int"].numVal.integer == "789"