From 216119212c256548a3e7557d5190fe61a7b9524a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 29 Nov 2017 08:07:16 -0800 Subject: [PATCH 1/9] Emit relative object file paths in genScript (#6835) --- compiler/extccomp.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index e6b23aae52..42c341651b 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -764,8 +764,9 @@ proc callCCompiler*(projectfile: string) = add(objfiles, quoteShell( addFileExt(objFile, CC[cCompiler].objExt))) for x in toCompile: + let objFile = if noAbsolutePaths(): x.obj.extractFilename else: x.obj add(objfiles, ' ') - add(objfiles, quoteShell(x.obj)) + add(objfiles, quoteShell(objFile)) linkCmd = getLinkCmd(projectfile, objfiles) if optCompileOnly notin gGlobalOptions: From 11fcae57052b3c886b4d2b593acb3ac0d717edd1 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 28 Nov 2017 21:49:34 +0000 Subject: [PATCH 2/9] Fixes #5856. Code based on @loloiccl's PR (#5879). --- lib/pure/json.nim | 28 +++++++++++++++++++++++----- tests/stdlib/tjsonmacro.nim | 15 ++++++++++++++- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index cea485c439..1b887a0c54 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1524,6 +1524,27 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] = doAssert result.len > 0 +proc processObjFields(obj: NimNode, + jsonNode: NimNode): seq[NimNode] {.compileTime.} = + ## Process all the fields of an ``ObjectTy`` and any of its + ## parent type's fields (via inheritance). + result = @[] + + expectKind(obj[2], nnkRecList) + for field in obj[2]: + let nodes = processObjField(field, jsonNode) + result.add(nodes) + + # process parent type fields + case obj[1].kind + of nnkBracketExpr: + assert $obj[1][0] == "ref" + result.add(processObjFields(getType(obj[1][1]), jsonNode)) + of nnkSym: + result.add(processObjFields(getType(obj[1]), jsonNode)) + else: + discard + proc processType(typeName: NimNode, obj: NimNode, jsonNode: NimNode, isRef: bool): NimNode {.compileTime.} = ## Process a type such as ``Sym "float"`` or ``ObjectTy ...``. @@ -1533,7 +1554,7 @@ proc processType(typeName: NimNode, obj: NimNode, ## .. code-block::plain ## ObjectTy ## Empty - ## Empty + ## InheritanceInformation ## RecList ## Sym "events" case obj.kind @@ -1543,10 +1564,7 @@ proc processType(typeName: NimNode, obj: NimNode, result.add(typeName) # Name of the type to construct. # Process each object field and add it as an exprColonExpr - expectKind(obj[2], nnkRecList) - for field in obj[2]: - let nodes = processObjField(field, jsonNode) - result.add(nodes) + result.add(processObjFields(obj, jsonNode)) # Object might be null. So we need to check for that. if isRef: diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 153cf85563..2d20063ab3 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -246,4 +246,17 @@ when isMainModule: var b = Bird(age: 3, height: 1.734, name: "bardo", colors: [red, blue]) let jnode = %b let data = jnode.to(Bird) - doAssert data == b \ No newline at end of file + doAssert data == b + + block: + type + MsgBase = ref object of RootObj + name*: string + + MsgChallenge = ref object of MsgBase + challenge*: string + + let data = %*{"name": "foo", "challenge": "bar"} + let msg = data.to(MsgChallenge) + doAssert msg.name == "foo" + doAssert msg.challenge == "bar" \ No newline at end of file From e0681715dc9c54135937f54510015f66d384aa29 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 29 Nov 2017 14:48:17 +0000 Subject: [PATCH 3/9] Fixes #6095. --- lib/pure/json.nim | 55 +++++++++++++++++++++++-------------- tests/stdlib/tjsonmacro.nim | 18 +++++++++++- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 1b887a0c54..b9f49f0bdc 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1524,26 +1524,34 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] = doAssert result.len > 0 -proc processObjFields(obj: NimNode, - jsonNode: NimNode): seq[NimNode] {.compileTime.} = +proc processFields(obj: NimNode, + jsonNode: NimNode): seq[NimNode] {.compileTime.} = ## Process all the fields of an ``ObjectTy`` and any of its ## parent type's fields (via inheritance). result = @[] + case obj.kind + of nnkObjectTy: + expectKind(obj[2], nnkRecList) + for field in obj[2]: + let nodes = processObjField(field, jsonNode) + result.add(nodes) - expectKind(obj[2], nnkRecList) - for field in obj[2]: - let nodes = processObjField(field, jsonNode) - result.add(nodes) - - # process parent type fields - case obj[1].kind - of nnkBracketExpr: - assert $obj[1][0] == "ref" - result.add(processObjFields(getType(obj[1][1]), jsonNode)) - of nnkSym: - result.add(processObjFields(getType(obj[1]), jsonNode)) + # process parent type fields + case obj[1].kind + of nnkBracketExpr: + assert $obj[1][0] == "ref" + result.add(processFields(getType(obj[1][1]), jsonNode)) + of nnkSym: + result.add(processFields(getType(obj[1]), jsonNode)) + else: + discard + of nnkTupleTy: + for identDefs in obj: + expectKind(identDefs, nnkIdentDefs) + let nodes = processObjField(identDefs[0], jsonNode) + result.add(nodes) else: - discard + doAssert false, "Unable to process field type: " & $obj.kind proc processType(typeName: NimNode, obj: NimNode, jsonNode: NimNode, isRef: bool): NimNode {.compileTime.} = @@ -1558,13 +1566,17 @@ proc processType(typeName: NimNode, obj: NimNode, ## RecList ## Sym "events" case obj.kind - of nnkObjectTy: + of nnkObjectTy, nnkTupleTy: # Create object constructor. - result = newNimNode(nnkObjConstr) - result.add(typeName) # Name of the type to construct. + result = + if obj.kind == nnkObjectTy: newNimNode(nnkObjConstr) + else: newNimNode(nnkPar) - # Process each object field and add it as an exprColonExpr - result.add(processObjFields(obj, jsonNode)) + if obj.kind == nnkObjectTy: + result.add(typeName) # Name of the type to construct. + + # Process each object/tuple field and add it as an exprColonExpr + result.add(processFields(obj, jsonNode)) # Object might be null. So we need to check for that. if isRef: @@ -1687,6 +1699,8 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = result = createConstructor(obj, jsonNode) else: result = processType(typeSym, obj, jsonNode, false) + of nnkTupleTy: + result = processType(typeSym, typeSym, jsonNode, false) else: doAssert false, "Unable to create constructor for: " & $typeSym.kind @@ -1818,6 +1832,7 @@ macro to*(node: JsonNode, T: typedesc): untyped = # TODO: Rename postProcessValue and move it (?) result = postProcessValue(result) + # echo(treeRepr(result)) # echo(toStrLit(result)) when false: diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 2d20063ab3..388d4d534e 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -259,4 +259,20 @@ when isMainModule: let data = %*{"name": "foo", "challenge": "bar"} let msg = data.to(MsgChallenge) doAssert msg.name == "foo" - doAssert msg.challenge == "bar" \ No newline at end of file + doAssert msg.challenge == "bar" + + block: + type + Color = enum Red, Brown + Thing = object + animal: tuple[fur: bool, legs: int] + color: Color + + var j = parseJson(""" + {"animal":{"fur":true,"legs":6},"color":"Red"} + """) + + let parsed = to(j, Thing) + doAssert parsed.animal.fur + doAssert parsed.animal.legs == 6 + doAssert parsed.color == Red \ No newline at end of file From d3c9b58c005e7cd537cbdf3dfd3f69e72fa40722 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 29 Nov 2017 15:56:46 +0000 Subject: [PATCH 4/9] Fixes #6604. Rejects unnamed tuples with error. --- lib/pure/json.nim | 15 +++++++++++++-- tests/stdlib/tjsonmacro.nim | 22 +++++++++++++++++++++- tests/stdlib/tjsonmacro_reject.nim | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/stdlib/tjsonmacro_reject.nim diff --git a/lib/pure/json.nim b/lib/pure/json.nim index b9f49f0bdc..90cf7b8c96 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1701,6 +1701,10 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = result = processType(typeSym, obj, jsonNode, false) of nnkTupleTy: result = processType(typeSym, typeSym, jsonNode, false) + of nnkPar: + # TODO: The fact that `jsonNode` here works to give a good line number + # is weird. Specifying typeSym should work but doesn't. + error("Use a named tuple instead of: " & $toStrLit(typeSym), jsonNode) else: doAssert false, "Unable to create constructor for: " & $typeSym.kind @@ -1828,9 +1832,16 @@ macro to*(node: JsonNode, T: typedesc): untyped = expectKind(typeNode, nnkBracketExpr) doAssert(($typeNode[0]).normalize == "typedesc") - result = createConstructor(typeNode[1], node) + # Create `temp` variable to store the result in case the user calls this + # on `parseJson` (see bug #6604). + result = newNimNode(nnkStmtListExpr) + let temp = genSym(nskLet, "temp") + result.add quote do: + let `temp` = `node` + + let constructor = createConstructor(typeNode[1], temp) # TODO: Rename postProcessValue and move it (?) - result = postProcessValue(result) + result.add(postProcessValue(constructor)) # echo(treeRepr(result)) # echo(toStrLit(result)) diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 388d4d534e..af9633e9ef 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -275,4 +275,24 @@ when isMainModule: let parsed = to(j, Thing) doAssert parsed.animal.fur doAssert parsed.animal.legs == 6 - doAssert parsed.color == Red \ No newline at end of file + doAssert parsed.color == Red + + block: + type + Car = object + engine: tuple[name: string, capacity: float] + model: string + + let j = """ + {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"} + """ + + var i = 0 + proc mulTest: JsonNode = + i.inc() + return parseJson(j) + + let parsed = mulTest().to(Car) + doAssert parsed.engine.name == "V8" + + doAssert i == 1 \ No newline at end of file diff --git a/tests/stdlib/tjsonmacro_reject.nim b/tests/stdlib/tjsonmacro_reject.nim new file mode 100644 index 0000000000..00506449f5 --- /dev/null +++ b/tests/stdlib/tjsonmacro_reject.nim @@ -0,0 +1,18 @@ +discard """ + file: "tjsonmacro_reject.nim" + line: 11 + errormsg: "Use a named tuple instead of: (string, float)" +""" + +import json + +type + Car = object + engine: (string, float) + model: string + +let j = """ + {"engine": {"name": "V8", "capacity": 5.5}, model: "Skyline"} +""" +let parsed = parseJson(j) +echo(to(parsed, Car)) \ No newline at end of file From 8ca41ce637106c734cd819a1f49606db880cf075 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 29 Nov 2017 19:15:25 +0000 Subject: [PATCH 5/9] Implement support for Option[T] in json.to macro. Fixes #5848. --- lib/pure/json.nim | 27 +++++++++++++++++++++++++++ tests/stdlib/tjsonmacro.nim | 25 +++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 90cf7b8c96..b057aa7c6e 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1346,6 +1346,16 @@ proc createJsonIndexer(jsonNode: NimNode, indexNode ) +proc transformJsonIndexer(jsonNode: NimNode): NimNode = + case jsonNode.kind + of nnkBracketExpr: + result = newNimNode(nnkCurlyExpr) + else: + result = jsonNode.copy() + + for child in jsonNode: + result.add(transformJsonIndexer(child)) + template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind], ast: string) = if node.kind notin kinds: @@ -1637,6 +1647,10 @@ proc processType(typeName: NimNode, obj: NimNode, doAssert(not result.isNil(), "processType not initialised.") +import options +proc workaroundMacroNone[T](): Option[T] = + none(T) + proc createConstructor(typeSym, jsonNode: NimNode): NimNode = ## Accepts a type description, i.e. "ref Type", "seq[Type]", "Type" etc. ## @@ -1650,6 +1664,19 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = of nnkBracketExpr: var bracketName = ($typeSym[0]).normalize case bracketName + of "option": + # TODO: Would be good to verify that this is Option[T] from + # options module I suppose. + let lenientJsonNode = transformJsonIndexer(jsonNode) + + let optionGeneric = typeSym[1] + let value = createConstructor(typeSym[1], jsonNode) + let workaround = bindSym("workaroundMacroNone") # TODO: Nim Bug: This shouldn't be necessary. + + result = quote do: + ( + if `lenientJsonNode`.isNil: `workaround`[`optionGeneric`]() else: some[`optionGeneric`](`value`) + ) of "ref": # Ref type. var typeName = $typeSym[1] diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index af9633e9ef..f9f94606cc 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -2,7 +2,7 @@ discard """ file: "tjsonmacro.nim" output: "" """ -import json, strutils +import json, strutils, options when isMainModule: # Tests inspired by own use case (with some additional tests). @@ -295,4 +295,25 @@ when isMainModule: let parsed = mulTest().to(Car) doAssert parsed.engine.name == "V8" - doAssert i == 1 \ No newline at end of file + doAssert i == 1 + + block: + # Option[T] support! + type + Car1 = object # TODO: Codegen bug when `Car` + engine: tuple[name: string, capacity: Option[float]] + model: string + year: Option[int] + + let noYear = """ + {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"} + """ + + let noYearParsed = parseJson(noYear) + let noYearDeser = to(noYearParsed, Car1) + doAssert noYearDeser.engine.capacity == some(5.5) + doAssert noYearDeser.year.isNone + doAssert noYearDeser.engine.name == "V8" + + # TODO: Table[T, Y] support. + # TODO: JsonNode support \ No newline at end of file From 8187e83645bbc9d536eebfab2af3b2437c3485fb Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 29 Nov 2017 20:30:40 +0000 Subject: [PATCH 6/9] Implement Table/OrderedTable support for json.to macro. --- lib/pure/json.nim | 24 ++++++++++++++++++++++++ tests/stdlib/tjsonmacro.nim | 27 +++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index b057aa7c6e..6153e2f03a 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1677,6 +1677,30 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = ( if `lenientJsonNode`.isNil: `workaround`[`optionGeneric`]() else: some[`optionGeneric`](`value`) ) + of "table", "orderedtable": + let tableKeyType = typeSym[1] + if ($tableKeyType).cmpIgnoreStyle("string") != 0: + error("JSON doesn't support keys of type " & $tableKeyType) + let tableValueType = typeSym[2] + + let forLoopKey = genSym(nskForVar, "key") + let indexerNode = createJsonIndexer(jsonNode, forLoopKey) + let constructorNode = createConstructor(tableValueType, indexerNode) + + let tableInit = + if bracketName == "table": + bindSym("initTable") + else: + bindSym("initOrderedTable") + + # Create a statement expression containing a for loop. + result = quote do: + ( + var map = `tableInit`[`tableKeyType`, `tableValueType`](); + verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`)); + for `forLoopKey` in keys(`jsonNode`.fields): map[`forLoopKey`] = `constructorNode`; + map + ) of "ref": # Ref type. var typeName = $typeSym[1] diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index f9f94606cc..01fa43aa7e 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -2,7 +2,7 @@ discard """ file: "tjsonmacro.nim" output: "" """ -import json, strutils, options +import json, strutils, options, tables when isMainModule: # Tests inspired by own use case (with some additional tests). @@ -315,5 +315,28 @@ when isMainModule: doAssert noYearDeser.year.isNone doAssert noYearDeser.engine.name == "V8" - # TODO: Table[T, Y] support. + # Table[T, Y] support. + block: + type + Friend = object + name: string + age: int + + Dynamic = object + name: string + friends: Table[string, Friend] + + let data = """ + {"friends": { + "John": {"name": "John", "age": 35}, + "Elizabeth": {"name": "Elizabeth", "age": 23} + }, "name": "Dominik"} + """ + + let dataParsed = parseJson(data) + let dataDeser = to(dataParsed, Dynamic) + doAssert dataDeser.name == "Dominik" + doAssert dataDeser.friends["John"].age == 35 + doAssert dataDeser.friends["Elizabeth"].age == 23 + # TODO: JsonNode support \ No newline at end of file From 8d6126237226a80ca4c78206c625009ce285c348 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 29 Nov 2017 20:47:56 +0000 Subject: [PATCH 7/9] Implement support for JsonNode in json.to. --- lib/pure/json.nim | 5 +++++ tests/stdlib/tjsonmacro.nim | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 6153e2f03a..1d2f480c4b 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1744,6 +1744,11 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = let obj = getType(typeSym) result = processType(typeSym, obj, jsonNode, false) of nnkSym: + # Handle JsonNode. + if ($typeSym).cmpIgnoreStyle("jsonnode") == 0: + return jsonNode + + # Handle all other types. let obj = getType(typeSym) if obj.kind == nnkBracketExpr: # When `Sym "Foo"` turns out to be a `ref object`. diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 01fa43aa7e..2baa7bed1f 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -339,4 +339,21 @@ when isMainModule: doAssert dataDeser.friends["John"].age == 35 doAssert dataDeser.friends["Elizabeth"].age == 23 - # TODO: JsonNode support \ No newline at end of file + # JsonNode support + block: + type + Test = object + name: string + fallback: JsonNode + + let data = """ + {"name": "FooBar", "fallback": 56.42} + """ + + let dataParsed = parseJson(data) + let dataDeser = to(dataParsed, Test) + doAssert dataDeser.name == "FooBar" + doAssert dataDeser.fallback.kind == JFloat + doAssert dataDeser.fallback.getFloat() == 56.42 + + # TODO: Cycles lead to infinite loops. \ No newline at end of file From 2bb2e6975e397bef1b320cd5dbafb6b3338fdaf0 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 30 Nov 2017 18:43:34 +0000 Subject: [PATCH 8/9] Fix infinite recursion when using json.to on ref with cycle. --- lib/pure/json.nim | 10 ++++++++++ tests/stdlib/tjsonmacro.nim | 4 +--- tests/stdlib/tjsonmacro_reject2.nim | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 tests/stdlib/tjsonmacro_reject2.nim diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 1d2f480c4b..9e7510e45e 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1651,6 +1651,13 @@ import options proc workaroundMacroNone[T](): Option[T] = none(T) +proc depth(n: NimNode, current = 0): int = + result = 1 + for child in n: + let d = 1 + child.depth(current + 1) + if d > result: + result = d + proc createConstructor(typeSym, jsonNode: NimNode): NimNode = ## Accepts a type description, i.e. "ref Type", "seq[Type]", "Type" etc. ## @@ -1660,6 +1667,9 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = # echo("--createConsuctor-- \n", treeRepr(typeSym)) # echo() + if depth(jsonNode) > 150: + error("The `to` macro does not support ref objects with cycles.", jsonNode) + case typeSym.kind of nnkBracketExpr: var bracketName = ($typeSym[0]).normalize diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 2baa7bed1f..e2d8c27cfc 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -354,6 +354,4 @@ when isMainModule: let dataDeser = to(dataParsed, Test) doAssert dataDeser.name == "FooBar" doAssert dataDeser.fallback.kind == JFloat - doAssert dataDeser.fallback.getFloat() == 56.42 - - # TODO: Cycles lead to infinite loops. \ No newline at end of file + doAssert dataDeser.fallback.getFloat() == 56.42 \ No newline at end of file diff --git a/tests/stdlib/tjsonmacro_reject2.nim b/tests/stdlib/tjsonmacro_reject2.nim new file mode 100644 index 0000000000..b01153553c --- /dev/null +++ b/tests/stdlib/tjsonmacro_reject2.nim @@ -0,0 +1,21 @@ +discard """ + file: "tjsonmacro_reject2.nim" + line: 10 + errormsg: "The `to` macro does not support ref objects with cycles." +""" +import json + +type + Misdirection = object + cycle: Cycle + + Cycle = ref object + foo: string + cycle: Misdirection + +let data = """ + {"cycle": null} +""" + +let dataParsed = parseJson(data) +let dataDeser = to(dataParsed, Cycle) \ No newline at end of file From 578ab935cbb1a9b53c0192d389c1a01c4e6e95ac Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 30 Nov 2017 18:56:34 +0000 Subject: [PATCH 9/9] Support all int, uint and float variants in json.to macro. --- lib/pure/json.nim | 30 ++++++++++++++++-------------- tests/stdlib/tjsonmacro.nim | 28 +++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 9e7510e45e..b5b84863ac 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1609,25 +1609,14 @@ proc processType(typeName: NimNode, obj: NimNode, `getEnumCall` ) of nnkSym: - case ($typeName).normalize - of "float": - result = quote do: - ( - verifyJsonKind(`jsonNode`, {JFloat, JInt}, astToStr(`jsonNode`)); - if `jsonNode`.kind == JFloat: `jsonNode`.fnum else: `jsonNode`.num.float - ) + let name = ($typeName).normalize + case name of "string": result = quote do: ( verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`)); if `jsonNode`.kind == JNull: nil else: `jsonNode`.str ) - of "int": - result = quote do: - ( - verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`)); - `jsonNode`.num.int - ) of "biggestint": result = quote do: ( @@ -1641,7 +1630,20 @@ proc processType(typeName: NimNode, obj: NimNode, `jsonNode`.bval ) else: - doAssert false, "Unable to process nnkSym " & $typeName + if name.startsWith("int") or name.startsWith("uint"): + result = quote do: + ( + verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`)); + `jsonNode`.num.`obj` + ) + elif name.startsWith("float"): + result = quote do: + ( + verifyJsonKind(`jsonNode`, {JInt, JFloat}, astToStr(`jsonNode`)); + if `jsonNode`.kind == JFloat: `jsonNode`.fnum.`obj` else: `jsonNode`.num.`obj` + ) + else: + doAssert false, "Unable to process nnkSym " & $typeName else: doAssert false, "Unable to process type: " & $obj.kind diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index e2d8c27cfc..2cdd823058 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -354,4 +354,30 @@ when isMainModule: let dataDeser = to(dataParsed, Test) doAssert dataDeser.name == "FooBar" doAssert dataDeser.fallback.kind == JFloat - doAssert dataDeser.fallback.getFloat() == 56.42 \ No newline at end of file + doAssert dataDeser.fallback.getFloat() == 56.42 + + # int64, float64 etc support. + block: + type + Test1 = object + a: int8 + b: int16 + c: int32 + d: int64 + e: uint8 + f: uint16 + g: uint32 + h: uint64 + i: float32 + j: float64 + + let data = """ + {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, + "h": 8, "i": 9.9, "j": 10.10} + """ + + let dataParsed = parseJson(data) + let dataDeser = to(dataParsed, Test1) + doAssert dataDeser.a == 1 + doAssert dataDeser.f == 6 + doAssert dataDeser.i == 9.9'f32 \ No newline at end of file