Implement support for Option[T] in json.to macro. Fixes #5848.

This commit is contained in:
Dominik Picheta
2017-11-29 19:15:25 +00:00
committed by Dominik Picheta
parent d3c9b58c00
commit 8ca41ce637
2 changed files with 50 additions and 2 deletions

View File

@@ -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]

View File

@@ -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
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