summary refs log tree commit diff stats
path: root/lib/pure/json.nim
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-05-04 16:02:50 +0200
committerAndreas Rumpf <rumpf_a@web.de>2017-05-04 16:02:50 +0200
commit764cc0217735454c166cb7dd490db58f5fa6fe26 (patch)
tree63633b39ae24815e8b677ccbc9bac2cb01c39d3b /lib/pure/json.nim
parentafa80092d378a6dbc116c0aa3ed3964fd8c599d6 (diff)
parentc1aa973758a60d7ef0e698c94861b74132612de5 (diff)
downloadNim-764cc0217735454c166cb7dd490db58f5fa6fe26.tar.gz
Merge branch 'devel' into araq
Diffstat (limited to 'lib/pure/json.nim')
-rw-r--r--lib/pure/json.nim51
1 files changed, 38 insertions, 13 deletions
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index b3fc47749..564f952d3 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1213,22 +1213,22 @@ when not defined(js):
   proc parseJson*(s: Stream, filename: string): JsonNode =
     ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed
     ## for nice error messages.
-    ## If `s` contains extra data, it will raising `JsonParsingError`.
+    ## If `s` contains extra data, it will raise `JsonParsingError`.
     var p: JsonParser
     p.open(s, filename)
     defer: p.close()
     discard getTok(p) # read first token
     result = p.parseJson()
-    eat(p, tkEof) # check there are no exstra data
+    eat(p, tkEof) # check if there is no extra data
 
   proc parseJson*(buffer: string): JsonNode =
     ## Parses JSON from `buffer`.
-    ## If `buffer` contains extra data, it will raising `JsonParsingError`.
+    ## If `buffer` contains extra data, it will raise `JsonParsingError`.
     result = parseJson(newStringStream(buffer), "input")
 
   proc parseFile*(filename: string): JsonNode =
     ## Parses `file` into a `JsonNode`.
-    ## If `file` contains extra data, it will raising `JsonParsingError`.
+    ## If `file` contains extra data, it will raise `JsonParsingError`.
     var stream = newFileStream(filename, fmRead)
     if stream == nil:
       raise newException(IOError, "cannot read from file: " & filename)
@@ -1502,7 +1502,7 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] =
   doAssert result.len > 0
 
 proc processType(typeName: NimNode, obj: NimNode,
-                 jsonNode: NimNode): NimNode {.compileTime.} =
+                 jsonNode: NimNode, isRef: bool): NimNode {.compileTime.} =
   ## Process a type such as ``Sym "float"`` or ``ObjectTy ...``.
   ##
   ## Sample ``ObjectTy``:
@@ -1524,6 +1524,20 @@ proc processType(typeName: NimNode, obj: NimNode,
     for field in obj[2]:
       let nodes = processObjField(field, jsonNode)
       result.add(nodes)
+
+    # Object might be null. So we need to check for that.
+    if isRef:
+      result = quote do:
+        verifyJsonKind(`jsonNode`, {JObject, JNull}, astToStr(`jsonNode`))
+        if `jsonNode`.kind == JNull:
+          nil
+        else:
+          `result`
+    else:
+      result = quote do:
+        verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`));
+        `result`
+
   of nnkEnumTy:
     let instType = toIdentNode(getTypeInst(typeName))
     let getEnumCall = createGetEnumCall(jsonNode, instType)
@@ -1536,8 +1550,8 @@ proc processType(typeName: NimNode, obj: NimNode,
     of "float":
       result = quote do:
         (
-          verifyJsonKind(`jsonNode`, {JFloat}, astToStr(`jsonNode`));
-          `jsonNode`.fnum
+          verifyJsonKind(`jsonNode`, {JFloat, JInt}, astToStr(`jsonNode`));
+          if `jsonNode`.kind == JFloat: `jsonNode`.fnum else: `jsonNode`.num.float
         )
     of "string":
       result = quote do:
@@ -1551,6 +1565,12 @@ proc processType(typeName: NimNode, obj: NimNode,
           verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`));
           `jsonNode`.num.int
         )
+    of "biggestint":
+      result = quote do:
+        (
+          verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`));
+          `jsonNode`.num
+        )
     of "bool":
       result = quote do:
         (
@@ -1585,7 +1605,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
         typeName = typeName[0 .. ^12]
 
       let obj = getType(typeSym[1])
-      result = processType(newIdentNode(typeName), obj, jsonNode)
+      result = processType(newIdentNode(typeName), obj, jsonNode, true)
     of "seq":
       let seqT = typeSym[1]
       let forLoopI = newIdentNode("i")
@@ -1605,17 +1625,21 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
     else:
       # Generic type.
       let obj = getType(typeSym)
-      result = processType(typeSym, obj, jsonNode)
+      result = processType(typeSym, obj, jsonNode, false)
   of nnkSym:
     let obj = getType(typeSym)
-    result = processType(typeSym, obj, jsonNode)
+    if obj.kind == nnkBracketExpr:
+      # When `Sym "Foo"` turns out to be a `ref object`.
+      result = createConstructor(obj, jsonNode)
+    else:
+      result = processType(typeSym, obj, jsonNode, false)
   else:
     doAssert false, "Unable to create constructor for: " & $typeSym.kind
 
   doAssert(not result.isNil(), "Constructor not initialised.")
 
 proc postProcess(node: NimNode): NimNode
-proc postProcessValue(value: NimNode, depth=0): NimNode =
+proc postProcessValue(value: NimNode): NimNode =
   ## Looks for object constructors and calls the ``postProcess`` procedure
   ## on them. Otherwise it just returns the node as-is.
   case value.kind
@@ -1736,9 +1760,10 @@ macro to*(node: JsonNode, T: typedesc): untyped =
   doAssert(($typeNode[0]).normalize == "typedesc")
 
   result = createConstructor(typeNode[1], node)
-  result = postProcess(result)
+  # TODO: Rename postProcessValue and move it (?)
+  result = postProcessValue(result)
 
-  #echo(toStrLit(result))
+  # echo(toStrLit(result))
 
 when false:
   import os