summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@gmail.com>2017-04-08 22:06:57 +0200
committerDominik Picheta <dominikpicheta@gmail.com>2017-04-08 22:06:57 +0200
commit658467a31f34110006fde3bd0ef949dd819a5601 (patch)
tree02caeb44b89dffab2d0b379dd9ed4ed4388ab7b0 /lib/pure
parentcc223ff7d89a1f56d4cc0ff5b266a4e7d5d15a4d (diff)
downloadNim-658467a31f34110006fde3bd0ef949dd819a5601.tar.gz
Improve error messages and add tests for the JSON macro.
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/json.nim35
1 files changed, 25 insertions, 10 deletions
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index eca708bb7..752501465 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -124,6 +124,9 @@ type
     state: seq[ParserState]
     filename: string
 
+  JsonKindError* = object of ValueError ## raised by the ``to`` macro if the
+                                        ## JSON kind is incorrect.
+
 {.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
   TJsonParser: JsonParser, TTokKind: TokKind].}
 
@@ -1289,14 +1292,24 @@ proc createJsonIndexer(jsonNode: NimNode,
     indexNode
   )
 
-proc getEnum(node: JsonNode, T: typedesc): T =
-  # TODO: Exceptions.
+template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind],
+                        ast: string) =
+  if node.kind notin kinds:
+    let msg = "Incorrect JSON kind. Wanted '$1' in '$2' but got '$3'." % [
+      $kinds,
+      ast,
+      $node.kind
+    ]
+    raise newException(JsonKindError, msg)
+
+proc getEnum(node: JsonNode, ast: string, T: typedesc): T =
+  verifyJsonKind(node, {JString}, ast)
   return parseEnum[T](node.getStr())
 
 proc toIdentNode(typeNode: NimNode): NimNode =
   ## Converts a Sym type node (returned by getType et al.) into an
-  ## Ident node. Placing Sym type nodes is unsound (according to @Araq)
-  ## so this is necessary.
+  ## Ident node. Placing Sym type nodes inside the resulting code AST is
+  ## unsound (according to @Araq) so this is necessary.
   case typeNode.kind
   of nnkSym:
     return newIdentNode($typeNode)
@@ -1317,7 +1330,8 @@ proc createIfStmtForOf(ofBranch, jsonNode, kindType,
 
   # -> getEnum(`jsonNode`, `kindType`)
   let getEnumSym = bindSym("getEnum")
-  let getEnumCall = newCall(getEnumSym, jsonNode, kindType)
+  let astStrLit = toStrLit(jsonNode)
+  let getEnumCall = newCall(getEnumSym, jsonNode, astStrLit, kindType)
 
   var cond = newEmptyNode()
   for ofCond in ofBranch:
@@ -1398,7 +1412,8 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] =
     # Add the "case" field's value.
     let kindType = toIdentNode(getTypeInst(field[0]))
     let getEnumSym = bindSym("getEnum")
-    let getEnumCall = newCall(getEnumSym, kindJsonNode, kindType)
+    let astStrLit = toStrLit(kindJsonNode)
+    let getEnumCall = newCall(getEnumSym, kindJsonNode, astStrLit, kindType)
     exprColonExpr.add(getEnumCall)
 
     # Iterate through each `of` branch.
@@ -1439,25 +1454,25 @@ proc processType(typeName: NimNode, obj: NimNode,
     of "float":
       result = quote do:
         (
-          assert `jsonNode`.kind == JFloat;
+          verifyJsonKind(`jsonNode`, {JFloat}, astToStr(`jsonNode`));
           `jsonNode`.fnum
         )
     of "string":
       result = quote do:
         (
-          assert `jsonNode`.kind in {JString, JNull};
+          verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`));
           if `jsonNode`.kind == JNull: nil else: `jsonNode`.str
         )
     of "int":
       result = quote do:
         (
-          assert `jsonNode`.kind == JInt;
+          verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`));
           `jsonNode`.num.int
         )
     of "bool":
       result = quote do:
         (
-          assert `jsonNode`.kind == JBool;
+          verifyJsonKind(`jsonNode`, {JBool}, astToStr(`jsonNode`));
           `jsonNode`.bval
         )
     else: