poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 2/2] pk-mi-json: Improve JSON schema & rewrite pk_val parser


From: Mohammad-Reza Nabipoor
Subject: [PATCH v2 2/2] pk-mi-json: Improve JSON schema & rewrite pk_val parser
Date: Sun, 28 Mar 2021 22:37:16 +0430

Improved areas:
  - More declarative JSON to pk_val conversion
  - Improved error handling (error messages are now stacked)
  - Reduced assertions on user inputs (There's one case in `pexpect_arr`
    that will be removed in future when we change the array schema to
    support types).

This commit removed `Null` object and replaced them by JSON `null` value
whenever possible. And changed `Mapping` accordingly.

2021-03-28  Mohammad-Reza Nabipoor  <m.nabipoor@yahoo.com>

        * etc/pk-mi-json-schema.json: Re-order fields. Remove `Null` object.
        Change `Mapping` to accept one required field `mapped` and three
        optional fields: `strict`, `IOS` and `offset`.
        * poke/pk-mi-json.c: Re-write the JSON to pk_val conversion.
        (jerror): New function.
        (jexpect): Likewise.
        (pvalue): Likewise.
        (pexpect): Likewise.
        (pexpect_sct): Likewise.
        (pexpect_aelem): Likewise.
        (pexpect_arr): Likewise.
        (pexpect_map): Likewise.
        (pk_mi_jsonobj_to_val): Likewise.
        (pk_mi_null_to_json): Removed.
        (pk_mi_json_to_val_1): Likewise.
        (pk_mi_json_poke_value_type): Likewise.
        (pk_mi_json_to_int): Likewise.
        (pk_mi_json_to_uint): Likewise.
        (pk_mi_json_to_string): Likewise.
        (pk_mi_json_to_offset): Likewise.
        (pk_mi_json_to_mapping): Likewise.
        (pk_mi_json_to_sct): Likewise.
        (pk_mi_json_array_element_pair): Likewise.
        (pk_mi_json_to_array): Likewise.
        (collect_json_arg): Use `pk_mi_jsonobj_to_val` function.
        (pk_mi_json_to_val): Re-write.
        (RETURN_ON_JERR): New macro.
        (RETURN_ERR_IF): Likewise.
        * testsuite/poke.mi-json/mi-json.c (JFIELD_IMPL): New macro.
        (JFIELD): Likewise.
        (CHK_IMPL): Likewise.
        (CHK): Likewise.
        (STREQ_LIT): Likewise.
        (test_json_pk_int): Re-write.
        (test_json_pk_uint): Likewise.
        (test_json_pk_string): Likewise.
        (test_json_pk_offset): Likewise.
        (test_json_pk_null): Likewise.
        (test_json_pk_sct): Likewise.
        (test_json_pk_array): Likewise.
        (test_json_to_val): Report more info to the `stdout`.
        * testsuite/poke.mi-json/pk_offset_uint.json: New sample file.
        * testsuite/poke.mi-json/pk_sct_empty.json: Likewise.
        * testsuite/poke.mi-json/pk_sct_empty_mapped.json: Likewise.
        * testsuite/poke.mi-json/pk_array.json: Change `mapping`.
        * testsuite/poke.mi-json/pk_sct.json: Likewise.
        * testsuite/Makefile.am (EXTRA_DIST): Updated.
---


Hi, Jose and Kostas.

As before, this is a full rewrite of JSON->pk_val conversion and tests.
Still don't support `null` for array items and empty arrays, which requires
adding types to JSON schema.

Changes from v1:

- I changed the JSON Schema and removed the `Null` object to make everything
  more consistent. I chose the `null` value of JSON itself to represent null.
  (Also re-wrote the `pk_mi_null_to_json` to support this).
- `Mapping` now only has one required field: `mapped`.
  If it is `true`, parser expects the three other fields:
    `strict`, `IOS` and `offset`.
  (See `testsuite/poke.mi-json/pk_sct_empty.json` and
  `testsuite/poke.mi-json/pk_sct_empty_mapped.json` as examples)
- Error handling macros now explicitly uses `errmsg`.

Comments are welcome!


Regards,
Mohammad-Reza

P.S. I used `--patience` this time for diff generation, so diffs are
more readable now.


 ChangeLog                                     |   50 +
 etc/pk-mi-json-schema.json                    |   54 +-
 poke/pk-mi-json.c                             | 1136 +++++++++--------
 testsuite/Makefile.am                         |    3 +
 testsuite/poke.mi-json/Makefile.am            |    3 +-
 testsuite/poke.mi-json/mi-json.c              |  461 ++++---
 testsuite/poke.mi-json/pk_array.json          |    2 +-
 testsuite/poke.mi-json/pk_offset_uint.json    |   18 +
 testsuite/poke.mi-json/pk_sct.json            |    3 +-
 testsuite/poke.mi-json/pk_sct_empty.json      |   17 +
 .../poke.mi-json/pk_sct_empty_mapped.json     |   33 +
 11 files changed, 1004 insertions(+), 776 deletions(-)
 create mode 100644 testsuite/poke.mi-json/pk_offset_uint.json
 create mode 100644 testsuite/poke.mi-json/pk_sct_empty.json
 create mode 100644 testsuite/poke.mi-json/pk_sct_empty_mapped.json

diff --git a/ChangeLog b/ChangeLog
index ff49f4fd..964ab5ae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2021-03-28  Mohammad-Reza Nabipoor  <m.nabipoor@yahoo.com>
+
+       * etc/pk-mi-json-schema.json: Re-order fields. Remove `Null` object.
+       Change `Mapping` to accept one required field `mapped` and three
+       optional fields: `strict`, `IOS` and `offset`.
+       * poke/pk-mi-json.c: Re-write the JSON to pk_val conversion.
+       (jerror): New function.
+       (jexpect): Likewise.
+       (pvalue): Likewise.
+       (pexpect): Likewise.
+       (pexpect_sct): Likewise.
+       (pexpect_aelem): Likewise.
+       (pexpect_arr): Likewise.
+       (pexpect_map): Likewise.
+       (pk_mi_jsonobj_to_val): Likewise.
+       (pk_mi_null_to_json): Removed.
+       (pk_mi_json_to_val_1): Likewise.
+       (pk_mi_json_poke_value_type): Likewise.
+       (pk_mi_json_to_int): Likewise.
+       (pk_mi_json_to_uint): Likewise.
+       (pk_mi_json_to_string): Likewise.
+       (pk_mi_json_to_offset): Likewise.
+       (pk_mi_json_to_mapping): Likewise.
+       (pk_mi_json_to_sct): Likewise.
+       (pk_mi_json_array_element_pair): Likewise.
+       (pk_mi_json_to_array): Likewise.
+       (collect_json_arg): Use `pk_mi_jsonobj_to_val` function.
+       (pk_mi_json_to_val): Re-write.
+       (RETURN_ON_JERR): New macro.
+       (RETURN_ERR_IF): Likewise.
+       * testsuite/poke.mi-json/mi-json.c (JFIELD_IMPL): New macro.
+       (JFIELD): Likewise.
+       (CHK_IMPL): Likewise.
+       (CHK): Likewise.
+       (STREQ_LIT): Likewise.
+       (test_json_pk_int): Re-write.
+       (test_json_pk_uint): Likewise.
+       (test_json_pk_string): Likewise.
+       (test_json_pk_offset): Likewise.
+       (test_json_pk_null): Likewise.
+       (test_json_pk_sct): Likewise.
+       (test_json_pk_array): Likewise.
+       (test_json_to_val): Report more info to the `stdout`.
+       * testsuite/poke.mi-json/pk_offset_uint.json: New sample file.
+       * testsuite/poke.mi-json/pk_sct_empty.json: Likewise.
+       * testsuite/poke.mi-json/pk_sct_empty_mapped.json: Likewise.
+       * testsuite/poke.mi-json/pk_array.json: Change `mapping`.
+       * testsuite/poke.mi-json/pk_sct.json: Likewise.
+       * testsuite/Makefile.am (EXTRA_DIST): Updated.
+
 2021-03-28  Mohammad-Reza Nabipoor  <m.nabipoor@yahoo.com>
 
        * libpoke/libpoke.h (pk_val_mappable_p): New function declaration.
diff --git a/etc/pk-mi-json-schema.json b/etc/pk-mi-json-schema.json
index 5b0a980c..827e083a 100644
--- a/etc/pk-mi-json-schema.json
+++ b/etc/pk-mi-json-schema.json
@@ -105,9 +105,9 @@
             },
             "maxProperties" : 3,
             "required": [
+                "type"
                 "magnitude",
-                "base",
-                "type"
+                "unit",
             ],
             "title": "Offset"
         },
@@ -168,24 +168,28 @@
                 },
                 "mapping" : {
                     "type" : "object",
-                    "oneOf" : [
-                        { "$ref" : "#/definitions/Mapping" },
-                        { "$ref" : "#/definitions/Null" }
+                    "$ref" : "#/definitions/Mapping"
                     ]
                 }
             },
             "maxProperties" : 4,
             "required": [
+                "type",
+                "name",
                 "fields",
-                "type",
-                "mapping",
-                "name"
+                "mapping"
             ],
             "title": "Struct"
         },
         "Mapping": {
             "type": "object",
             "properties": {
+                "mapped": {
+                    "type": "boolean",
+                },
+                "strict": {
+                    "type": "boolean",
+                },
                 "IOS": {
                     "type": "integer",
                     "minimum" : -2147483648,
@@ -196,10 +200,9 @@
                     "$ref": "#/definitions/Offset"
                 }
             },
-            "maxProperties": 2,
+            "maxProperties": 4,
             "required": [
-                "IOS",
-                "offset"
+                "mapped"
             ],
             "title": "Mapping"
         },
@@ -211,7 +214,7 @@
                     "const" : "Array"
                 },
                 "elements" : {
-                "type": "array",
+                    "type": "array",
                     "items": {
                         "type": "object",
                         "properties" : {
@@ -224,7 +227,7 @@
                                     { "$ref": "#/definitions/Struct" },
                                     { "$ref": "#/definitions/Array" },
                                     { "$ref": "#/definitions/Offset" },
-                                    { "$ref": "#/definitions/Null" }
+                                    { "type": null }
                                 ]
                             },
                             "boffset" : {
@@ -248,10 +251,7 @@
                 },
                 "mapping" : {
                     "type" : "object",
-                        "oneOf" : [
-                            { "$ref" : "#/definitions/Mapping" },
-                            { "$ref" : "#/definitions/Null" }
-                        ]
+                    "$ref" : "#/definitions/Mapping"
                 }
             },
             "maxProperties" : 3,
@@ -260,24 +260,6 @@
                 "type",
                 "mapping"
             ]
-        },
-        "Null": {
-            "type": "object",
-            "properties" : {
-            "type" : {
-                    "type" : "string",
-                    "const" : "Null"
-                },
-                    "value" : {
-                    "type" : "null"
-                }
-            },
-            "maxProperties" : 2,
-            "required" : [
-                "type",
-                "value"
-            ],
-            "title": "Null"
         }
     },
     "type": "object",
@@ -291,7 +273,7 @@
             { "$ref": "#/definitions/Struct" },
             { "$ref": "#/definitions/Array" },
             { "$ref": "#/definitions/Offset" },
-            { "$ref": "#/definitions/Null" }
+            { "type": "null" }
           ]
       }
     },
diff --git a/poke/pk-mi-json.c b/poke/pk-mi-json.c
index bc2f4daa..d6ab81d8 100644
--- a/poke/pk-mi-json.c
+++ b/poke/pk-mi-json.c
@@ -19,29 +19,94 @@
 #include <config.h>
 
 #include <assert.h>
+#include <stdio.h>
 #include <string.h>
 #include <json.h>
 
-#include "pk-term.h"
 #include "pk-mi.h"
 #include "pk-mi-json.h"
 #include "pk-mi-msg.h"
 #include "libpoke.h"
+#include "pk-utils.h"
 
-#define PK_MI_CHECK(errmsg, A, M, ...)    \
-    do                                     \
-     {                                     \
-       int r;                              \
-       if (A)                              \
-         break;                            \
-       if (errmsg != NULL &&               \
-           (r = asprintf (errmsg, "[ERROR] " M , ##__VA_ARGS__)) == -1) { \
-         *errmsg = NULL;                   \
-         assert (0 && "asprintf () failed"); \
-       }                                   \
-       goto error;                         \
-     }                                     \
-     while (0)
+#define J_OK 1
+#define J_NOK 0 /* Not OK */
+
+#define PK_MI_CHECK(errmsg, A, ...)                                           \
+  do                                                                          \
+    {                                                                         \
+      if (A)                                                                  \
+        break;                                                                \
+      if (errmsg != NULL && asprintf (errmsg, "[ERROR] " __VA_ARGS__) == -1)  \
+        {                                                                     \
+          *errmsg = NULL;                                                     \
+          assert (0 && "asprintf () failed");                                 \
+        }                                                                     \
+      goto error;                                                             \
+    }                                                                         \
+  while (0)
+
+/* Error message handling */
+
+/* Prepend the error message to OUT */
+static int __attribute__ ((format (printf, 3, 4)))
+jerror (int ok, char **out, const char *fmt, ...)
+{
+#define BUFSZ 512 /* FIXME use dynamic mem */
+
+  char buf[BUFSZ];
+  va_list ap;
+
+  if (ok == J_OK || out == NULL)
+    return ok;
+
+  if (*out == NULL)
+    {
+      va_start (ap, fmt);
+      vsnprintf (buf, BUFSZ, fmt, ap);
+      va_end (ap);
+    }
+  else
+    {
+      int n;
+
+      /* prepend the new error message */
+      va_start (ap, fmt);
+      n = vsnprintf (buf, BUFSZ, fmt, ap);
+      va_end (ap);
+
+      /* append the old error message (if there's enough space)  */
+      if (0 <= n && n < BUFSZ)
+        snprintf (buf + n, BUFSZ - n, ": %s", *out);
+      free (*out);
+    }
+
+  *out = strdup (buf);
+  return ok;
+
+#undef BUFSZ
+}
+
+#define RETURN_ON_JERR(cond, errmsg, ...)                                     \
+  do                                                                          \
+    {                                                                         \
+      int _cond = (cond);                                                     \
+                                                                              \
+      if (_cond != J_OK)                                                      \
+        return jerror (_cond, errmsg, __VA_ARGS__);                           \
+    }                                                                         \
+  while (0)
+
+#define RETURN_ERR_IF(cond, errmsg, ...)                                      \
+  do                                                                          \
+    {                                                                         \
+      if ((cond))                                                             \
+        return jerror (J_NOK, errmsg, __VA_ARGS__);                           \
+    }                                                                         \
+  while (0)
+
+
+/* MI Messages */
 
 /* Message::
    {
@@ -250,42 +315,60 @@ pk_mi_offset_to_json (pk_val pk_offset, char **errmsg)
 static json_object *
 pk_mi_mapping_to_json (pk_val val, char **errmsg)
 {
-  json_object *mapping_object, *ios_object, *offset_object;
-
-  offset_object = pk_mi_offset_to_json (pk_val_offset (val), errmsg);
-
-  ios_object = json_object_new_int64 (pk_int_value (pk_val_ios (val)));
-  PK_MI_CHECK (errmsg, ios_object != NULL, "json_object_new_object () failed");
-
-  mapping_object = json_object_new_object ();
-  PK_MI_CHECK (errmsg, mapping_object != NULL, "json_object_new_object () 
failed");
-
-  json_object_object_add (mapping_object, "IOS", ios_object);
-  json_object_object_add (mapping_object, "offset", offset_object);
-
-  return mapping_object;
-
-  error:
-    return NULL;
-}
-
-static json_object *
-pk_mi_null_to_json (char **errmsg)
-{
-  json_object *pk_null_object;
-
-  pk_null_object = json_object_new_object ();
-  PK_MI_CHECK (errmsg, pk_null_object != NULL,
-               "json_object_new_object () failed");
-
-  json_object_object_add (pk_null_object, "type",
-                          json_object_new_string ("Null"));
-  json_object_object_add (pk_null_object, "value", NULL);
-
-  return pk_null_object;
-
-  error:
-    return NULL;
+  enum
+  {
+    mapping,
+    mapped,
+    strict,
+    ios,
+    offset
+  };
+  const int LEN = 5;
+  /* Store all JSON objects in an array to make resource management easier */
+  json_object *j[LEN];
+  int mapped_p;
+
+  memset (j, 0, sizeof (j));
+
+  j[mapping] = json_object_new_object ();
+  PK_MI_CHECK (errmsg, j[mapping] != NULL, "json_object_new_object () failed");
+
+  mapped_p = pk_val_mapped_p (val);
+  j[mapped] = json_object_new_boolean (mapped_p);
+  PK_MI_CHECK (errmsg, j[mapped] != NULL, "json_object_new_boolean () failed");
+
+  if (!mapped_p)
+    {
+      json_object_object_add (j[mapping], "mapped", j[mapped]);
+      return j[mapping];
+    }
+
+  j[strict] = json_object_new_boolean (pk_val_strict_p (val));
+  PK_MI_CHECK (errmsg, j[strict] != NULL, "json_object_new_boolean () failed");
+
+  j[offset] = pk_mi_offset_to_json (pk_val_offset (val), errmsg);
+  if (j[offset] == NULL)
+    goto error;
+
+  j[ios] = json_object_new_int64 (pk_int_value (pk_val_ios (val)));
+  PK_MI_CHECK (errmsg, j[ios] != NULL, "json_object_new_object () failed");
+
+  json_object_object_add (j[mapping], "mapped", j[mapped]);
+  json_object_object_add (j[mapping], "strict", j[strict]);
+  json_object_object_add (j[mapping], "IOS", j[ios]);
+  json_object_object_add (j[mapping], "offset", j[offset]);
+
+  return j[mapping];
+
+error:
+  for (int i = 0; i < LEN; i++)
+    if (j[i])
+      {
+        int free_p = json_object_put (j[i]);
+
+        assert (free_p == 1);
+      }
+  return NULL;
 }
 
 static json_object *
@@ -349,10 +432,9 @@ pk_mi_sct_to_json (pk_val pk_sct, char **errmsg)
                    "failed to add name object to struct field");
     }
 
-  /* Optionally, add a mapping.  */
-  pk_sct_mapping_object = pk_val_mapped_p (pk_sct) ?
-                            pk_mi_mapping_to_json (pk_sct, errmsg) :
-                            pk_mi_null_to_json (errmsg);
+  pk_sct_mapping_object = pk_mi_mapping_to_json (pk_sct, errmsg);
+  if (pk_sct_mapping_object == NULL)
+    goto error;
 
   pk_sct_object = json_object_new_object ();
   PK_MI_CHECK (errmsg, pk_sct_object != NULL,
@@ -418,11 +500,7 @@ pk_mi_array_to_json (pk_val pk_array, char **errmsg)
       PK_MI_CHECK (errmsg, err != -1, "failed to add element to array");
     }
 
-  /* Optionally, add a mapping.  */
-  pk_array_mapping_object = pk_val_mapped_p (pk_array) ?
-                            pk_mi_mapping_to_json (pk_array, errmsg) :
-                            pk_mi_null_to_json (errmsg);
-
+  pk_array_mapping_object = pk_mi_mapping_to_json (pk_array, errmsg);
   if (pk_array_mapping_object == NULL)
     goto error;
 
@@ -443,39 +521,33 @@ pk_mi_val_to_json_1 (pk_val val, char **errmsg)
 {
   json_object *pk_val_object = NULL;
 
-  if (val == PK_NULL) {
-    pk_val_object = pk_mi_null_to_json (errmsg);
-  }
-  else {
-    switch (pk_type_code (pk_typeof (val)))
-      {
-        case PK_INT:
-          pk_val_object = pk_mi_int_to_json (val, errmsg);
-          break;
-        case PK_UINT:
-          pk_val_object = pk_mi_uint_to_json (val, errmsg);
-          break;
-        case PK_STRING:
-          pk_val_object = pk_mi_string_to_json (val, errmsg);
-          break;
-        case PK_OFFSET:
-          pk_val_object = pk_mi_offset_to_json (val, errmsg);
-          break;
-        case PK_STRUCT:
-          pk_val_object = pk_mi_sct_to_json (val, errmsg);
-          break;
-        case PK_ARRAY:
-          pk_val_object = pk_mi_array_to_json (val, errmsg);
-          break;
-        case PK_CLOSURE:
-        case PK_ANY:
-        default:
-          assert (0);
-      }
-    if (!pk_val_object)
-      return NULL;
-  }
-
+  if (val == PK_NULL)
+    return NULL;
+  switch (pk_type_code (pk_typeof (val)))
+    {
+      case PK_INT:
+        pk_val_object = pk_mi_int_to_json (val, errmsg);
+        break;
+      case PK_UINT:
+        pk_val_object = pk_mi_uint_to_json (val, errmsg);
+        break;
+      case PK_STRING:
+        pk_val_object = pk_mi_string_to_json (val, errmsg);
+        break;
+      case PK_OFFSET:
+        pk_val_object = pk_mi_offset_to_json (val, errmsg);
+        break;
+      case PK_STRUCT:
+        pk_val_object = pk_mi_sct_to_json (val, errmsg);
+        break;
+      case PK_ARRAY:
+        pk_val_object = pk_mi_array_to_json (val, errmsg);
+        break;
+      case PK_CLOSURE:
+      case PK_ANY:
+      default:
+        assert (0);
+    }
   return pk_val_object;
 }
 
@@ -492,463 +564,475 @@ pk_mi_val_to_json (pk_val val, char **errmsg)
 
   json_object_object_add (pk_object, "PokeValue", pk_val_object);
 
-  return pk_object != NULL ?
-         json_object_to_json_string_ext (pk_object, JSON_C_TO_STRING_PRETTY)
-         : NULL;
+  return json_object_to_json_string_ext (pk_object, JSON_C_TO_STRING_PRETTY);
 
   error:
     return NULL;
 }
 
 /* Functions to convert JSON object to Poke value.  */
-static int pk_mi_json_to_val_1 (pk_val *poke_value, json_object *obj,
-                                char **errmsg);
 
-static const char *
-pk_mi_json_poke_value_type (json_object *obj)
-{
-  json_object *search_object;
-
-  /* Get the Poke value type.  */
-  if (json_object_object_get_ex (obj, "type", &search_object) == 0)
-    return NULL;
-
-  return json_object_to_json_string (search_object);
-}
-
-static int
-pk_mi_json_to_int (pk_val *pk_int, json_object *int_obj, char **errmsg)
-{
-  json_object *value_object, *size_object;
-  int64_t value;
-  int size, err;
-
-  err = json_object_object_get_ex (int_obj, "value", &value_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"value\"",
-               pk_mi_json_poke_value_type (int_obj));
-  value = json_object_get_int64 (value_object);
-
-  err = json_object_object_get_ex (int_obj, "size", &size_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"size\"",
-               pk_mi_json_poke_value_type (int_obj));
-  size = json_object_get_int (size_object);
-
-  *pk_int = pk_make_int (value, size);
-  PK_MI_CHECK (errmsg, *pk_int != PK_NULL, "pk_make_int failed");
-
-  return 0;
-
-  error:
-    return -1;
-}
-
-static int
-pk_mi_json_to_uint (pk_val *pk_uint, json_object *uint_obj,
-                    char **errmsg)
-{
-  json_object *value_object, *size_object;
-  uint64_t value;
-  int size, err;
-
-  err = json_object_object_get_ex (uint_obj, "value", &value_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"value\"",
-               pk_mi_json_poke_value_type (uint_obj));
-
-  /* Older versions of libjson-c (0.3.1 & under) do not support
-     json_object_get_uint64 (only json_object_get_int64).
-
-    In order to support previous versions, we store unsigned integers
-    as signed integers despite them being too large to represent as
-    signed. (i.e. they are stored as negative).
-
-    However, users expect to get the unsigned integer they stored.
-
-    Thus, we have to convert it back to uint64_t.  */
-  value = (uint64_t) json_object_get_int64 (value_object);
-
-  err = json_object_object_get_ex (uint_obj, "size", &size_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"size\"",
-               pk_mi_json_poke_value_type (uint_obj));
-  size = json_object_get_int (size_object);
-
-  *pk_uint = pk_make_uint (value, size);
-  PK_MI_CHECK (errmsg, *pk_uint != PK_NULL, "pk_make_uint failed");
-
-  return 0;
-
-  error:
-    return -1;
-}
-
-static int
-pk_mi_json_to_string (pk_val *pk_string, json_object *str_obj,
-                      char **errmsg)
-{
-  json_object *value_object;
-  const char *value_str;
-  int err;
-
-  err = json_object_object_get_ex (str_obj, "value", &value_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"value\"",
-               pk_mi_json_poke_value_type (str_obj));
-  value_str = json_object_get_string (value_object);
-
-  *pk_string = pk_make_string (value_str);
-  PK_MI_CHECK (errmsg, *pk_string != PK_NULL, "pk_make_string failed");
-
-  return 0;
-
-  error:
-    return -1;
-}
-
-static int
-pk_mi_json_to_offset (pk_val *pk_offset, json_object *offset_obj,
-                      char **errmsg)
-{
-  /* To build a pk_offset, we need its magnitude and its unit.  */
-  pk_val magnitude, unit;
-  json_object *magnitude_object, *unit_object;
-  int err;
-
-  err = json_object_object_get_ex (offset_obj, "magnitude", &magnitude_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"magnitude\"",
-               pk_mi_json_poke_value_type (offset_obj));
-
-  if (pk_mi_json_to_val_1 (&magnitude, magnitude_object, errmsg) == -1)
-    goto error;
-
-  err = json_object_object_get_ex (offset_obj, "unit", &unit_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"unit\"",
-               pk_mi_json_poke_value_type (offset_obj));
-
-  assert (json_object_get_type (unit_object) == json_type_object);
-
-  err = pk_mi_json_to_uint (&unit, unit_object, errmsg);
-  PK_MI_CHECK (errmsg, err != -1,
-               "unable to convert offset unit to pk_uint");
-  assert (pk_uint_size (unit) == 64);
-
-  *pk_offset = pk_make_offset (magnitude, unit);
-  PK_MI_CHECK(errmsg, *pk_offset != PK_NULL, "pk_make_offset failed");
-
-  return 0;
-
-  error:
-    return -1;
-}
-
-static int
-pk_mi_json_to_mapping (pk_val *poke_value, json_object *obj,
-                       char **errmsg)
-{
-  /* TODO: write me.  */
-  return 0;
-}
-
-static int
-pk_mi_json_to_sct (pk_val *pk_sct, json_object *sct_obj,
-                      char **errmsg)
-{
-  /* To build a pk_struct, we need its fields, its name and its mapping.  */
-  json_object *array_object, *fields_object, *search_object;
-  pk_val mapping, sct_type, sct_field_name, sct_field_value, sct_field_boffset;
-  pk_val sct, *fnames, *ftypes, nfields, name;
-  size_t fields_len;
-  int err;
-
-  err = json_object_object_get_ex (sct_obj, "fields", &search_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does does not contain key \"fields\"",
-               pk_mi_json_poke_value_type (sct_obj));
-
-  fields_object = search_object;
-  assert (json_object_get_type (fields_object) == json_type_array);
-
-  fields_len = json_object_array_length (fields_object);
-
-  if (fields_len > 0)
-    {
-      err = json_object_object_get_ex (sct_obj, "name", &search_object);
-      PK_MI_CHECK (errmsg, err != 0,
-                   "json type %s does does not contain key \"name\"",
-                   pk_mi_json_poke_value_type (sct_obj));
-      nfields = pk_make_uint (fields_len, 64);
-
-      /* Here, we don't use PK_MI_CHECK because
-        it would reallocate & refill errmsg.
-
-        TODO (kostas): check if there is a bug anywhere in the code
-        if asprintf () gets called more than once.  */
-      if (pk_mi_json_to_val_1 (&name, search_object, errmsg) == -1)
-        goto error;
-
-      pk_allocate_struct_attrs (nfields, &fnames, &ftypes);
-
-      sct_type = pk_make_struct_type (nfields, name, fnames, ftypes);
-      sct = pk_make_struct (nfields, sct_type);
-      for (size_t i = 0 ; i < fields_len ; i++)
-        {
-          array_object = json_object_array_get_idx (fields_object, i);
-
-          err = json_object_object_get_ex (array_object, "name",
-                                           &search_object);
-          PK_MI_CHECK (errmsg, err != 0,
-                       "json type %s does not contain key \"name\"",
-                       pk_mi_json_poke_value_type (array_object));
-
-          if (pk_mi_json_to_val_1 (&sct_field_name, search_object, errmsg) == 
-1)
-            goto error;
-
-          err = json_object_object_get_ex (array_object, "value",
-                                           &search_object);
-          PK_MI_CHECK (errmsg, err != 0,
-                       "json type %s does not contain key \"value\"",
-                       pk_mi_json_poke_value_type (array_object));
-
-          if (pk_mi_json_to_val_1 (&sct_field_value, search_object, errmsg) == 
-1)
-            goto error;
-
-          err = json_object_object_get_ex (array_object, "boffset",
-                                           &search_object);
-          PK_MI_CHECK (errmsg, err != 0,
-                       "json type %s does not contain key \"boffset\"",
-                       pk_mi_json_poke_value_type (array_object));
-
-          if (pk_mi_json_to_val_1 (&sct_field_boffset, search_object, errmsg) 
== -1)
-            goto error;
-
-          assert (pk_type_code (pk_typeof (sct_field_name)) == PK_STRING);
-          assert (pk_type_code (pk_typeof (sct_field_boffset)) == PK_UINT);
-
-          pk_struct_type_set_fname (sct_type, i, sct_field_name);
-          pk_struct_type_set_ftype (sct_type, i, pk_typeof (sct_field_value));
-          pk_struct_set_field_boffset (sct, i, sct_field_boffset);
-          pk_struct_set_field_name (sct, i, sct_field_name);
-          pk_struct_set_field_value (sct, i, sct_field_value);
-      }
-
-    err = json_object_object_get_ex (sct_obj, "mapping", &search_object);
-    PK_MI_CHECK (errmsg, err != 0,
-                 "json type %s does not contain key \"mapping\"",
-                 pk_mi_json_poke_value_type (sct_obj));
-    PK_MI_CHECK (errmsg,
-                 pk_mi_json_to_mapping (&mapping, search_object, errmsg) != -1,
-                 "failed to create mapping for struct");
-  }
-  else
-  {
-    sct = PK_NULL;
-  }
-
-  *pk_sct = sct;
-
-  return 0;
-
-  error:
-    return -1;
-}
-
-static pk_val *
-pk_mi_json_array_element_pair (json_object *elements_object, size_t idx,
-                               char **errmsg)
-{
-  json_object *element_object, *search_object;
-  int err;
-
-  /* value-offset pair.  */
-  pk_val *pair = (pk_val *) malloc (sizeof (pk_val) * 2);
-
-  element_object = json_object_array_get_idx (elements_object, idx);
-
-  err = json_object_object_get_ex (element_object, "value", &search_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"value\"",
-               pk_mi_json_poke_value_type (element_object));
-  if (pk_mi_json_to_val_1 (&(pair[0]), search_object, errmsg) == -1)
-    goto error;
-
-  err = json_object_object_get_ex (element_object, "boffset", &search_object);
-  PK_MI_CHECK (errmsg, err != 0,
-              "json type %s does not contain key \"boffset\"",
-              pk_mi_json_poke_value_type (element_object));
-
-  if (pk_mi_json_to_val_1 (&(pair[1]), search_object, errmsg) == -1)
-    goto error;
-
-  return pair;
-
-  error:
-    return NULL;
-}
+static int pvalue (json_object *j, pk_val *pval, char **errmsg);
+static int pexpect (json_object *j, int type_code, pk_val *pval,
+                    char **errmsg);
 
+/* Adapter function */
 static int
-pk_mi_json_to_array (pk_val *pk_array, json_object *array_obj,
-                     char **errmsg)
+pk_mi_jsonobj_to_val (pk_val *value, json_object *obj, char **errmsg)
 {
-  /* To build a pk_array, we need its elements and its mapping.  */
-  json_object *elements_object, *search_object;
-  pk_val array_type, mapping, array_etype, array, *element_pair;
-  size_t elements_len;
-  int err;
-
-  err = json_object_object_get_ex (array_obj, "elements", &search_object);
-  PK_MI_CHECK (errmsg, err != 0,
-               "json type %s does not contain key \"elements\"",
-               pk_mi_json_poke_value_type (array_obj));
-
-  elements_object = search_object;
-  assert (json_object_get_type (elements_object) == json_type_array);
-
-  elements_len = json_object_array_length (elements_object);
-
-  if (elements_len > 0)
-    {
-      /* We need to get the type of array elements first.  */
-      element_pair = pk_mi_json_array_element_pair (elements_object, 0, 
errmsg);
-      if (element_pair == NULL)
-        goto error;
-
-      array_etype = pk_typeof (element_pair[0]);
-      array_type = pk_make_array_type (array_etype, PK_NULL);
-      array = pk_make_array (pk_make_uint (elements_len, 64), array_type);
-
-      assert (pk_type_code (pk_typeof (element_pair[1])) == PK_UINT);
-
-      pk_array_insert_elem (array, 0, element_pair[0]);
-      free (element_pair);
-
-      for (size_t i = 1 ; i < elements_len ; i++)
-        {
-          element_pair = pk_mi_json_array_element_pair (elements_object, i,
-                                                        errmsg);
-          if (element_pair == NULL)
-            goto error;
-
-          assert (pk_type_code (pk_typeof (element_pair[0]))
-                                           == pk_type_code (array_etype));
-          assert (pk_type_code (pk_typeof (element_pair[1])) == PK_UINT);
-
-          pk_array_insert_elem (array, i, element_pair[0]);
-          free (element_pair);
-        }
-
-      err = json_object_object_get_ex (array_obj, "mapping", &search_object);
-      PK_MI_CHECK (errmsg, err != 0,
-                  "json type %s does not contain key \"mapping\"",
-                  pk_mi_json_poke_value_type (array_obj));
-
-      PK_MI_CHECK(errmsg,
-                pk_mi_json_to_mapping (&mapping, search_object, errmsg) != -1,
-                "failed to create mapping for struct");
-    }
-  else
-    {
-      array = PK_NULL;
-    }
-
-  *pk_array = array;
-
-  return 0;
-
-  error:
-    return -1;
+  return pvalue (obj, value, errmsg) == J_OK ? 0 : -1;
 }
 
-static int
-pk_mi_json_to_val_1 (pk_val *poke_value, json_object *obj,
-                     char **errmsg)
-{
-  const char *poke_object_type;
-
-  poke_object_type = pk_mi_json_poke_value_type (obj);
-  if (poke_object_type == NULL)
-    goto error;
-
-  if (!strncmp (poke_object_type, "\"Integer\"", strlen ("\"Integer\"")))
-    {
-      if (pk_mi_json_to_int (poke_value, obj, errmsg) == -1)
-        goto error;
-    }
-  else if (!strncmp (poke_object_type, "\"UnsignedInteger\"",
-            strlen ("\"UnsignedInteger\"")))
-    {
-      if (pk_mi_json_to_uint (poke_value, obj, errmsg) == -1)
-        goto error;
-    }
-  else if (!strncmp (poke_object_type, "\"String\"", strlen ("\"String\"")))
-    {
-      if (pk_mi_json_to_string (poke_value, obj, errmsg) == -1)
-        goto error;
-    }
-  else if (!strncmp (poke_object_type, "\"Offset\"", strlen ("\"Offset\"")))
-    {
-      if (pk_mi_json_to_offset (poke_value, obj, errmsg) == -1)
-        goto error;
-    }
-  else if (!strncmp (poke_object_type, "\"Array\"", strlen ("Array")))
-    {
-      if (pk_mi_json_to_array (poke_value, obj, errmsg) == -1)
-        goto error;
-    }
-  else if (!strncmp (poke_object_type, "\"Struct\"", strlen ("\"Struct\"")))
-    {
-      if (pk_mi_json_to_sct (poke_value, obj, errmsg) == -1)
-        goto error;
-    }
-  else if (!strncmp (poke_object_type, "\"Null\"", strlen ("\"Null\"")))
-      *poke_value = PK_NULL;
-  else
-    {
-      asprintf (errmsg, "An unexpected error happened, this is a bug.");
-      return -1;
-    }
-
-  return 0;
-
-  error:
-    return -1;
-}
-
-
 int
 pk_mi_json_to_val (pk_val *value, const char *json_str, char **errmsg)
 {
-  json_object *search_object, *poke_object = NULL;
-  json_tokener *tok = json_tokener_new ();
+  json_object *j_obj = NULL, *j_pokevalue;
+  json_tokener *tok = NULL;
   enum json_tokener_error jerr;
-  int err;
+  char *local_errmsg = NULL;
+  int ret, free_p;
 
-  /* Parse the current object and get its PK_TYPE.  */
-  do
+  /* All internal functions assume `errmsg` is either NULL or valid pointer
+     to a memory allocated by `malloc`.  */
+  if (errmsg)
+    *errmsg = NULL; /* success */
+
+  tok = json_tokener_new ();
+  PK_MI_CHECK (errmsg, tok != NULL, "json_tokener_new () failed");
+
+  j_obj = json_tokener_parse_ex (tok, json_str, strlen (json_str) + 1);
+  jerr = json_tokener_get_error (tok);
+  PK_MI_CHECK (errmsg, j_obj != NULL, "json_tokener_parse_ex () failed: %s",
+               json_tokener_error_desc (jerr));
+  PK_MI_CHECK (errmsg, jerr == json_tokener_success,
+               "json_tokener_parse_ex () failed: %s",
+               json_tokener_error_desc (jerr));
+
+  PK_MI_CHECK (errmsg,
+               json_object_object_get_ex (j_obj, "PokeValue", &j_pokevalue)
+                   == J_OK,
+               "expects \"PokeValue\" field");
+  PK_MI_CHECK (errmsg, pvalue (j_pokevalue, value, &local_errmsg) == J_OK,
+               "Invalid PokeValue object: %s", local_errmsg);
+
+  ret = 0;
+  goto deinit; /* because of the `goto error` inside the PK_MI_CHECK macro */
+
+error:
+  ret = -1;
+
+deinit:
+  free (local_errmsg);
+  if (j_obj)
+    {
+      free_p = json_object_put (j_obj);
+      assert (free_p == 1);
+    }
+  if (tok)
+    json_tokener_free (tok);
+  return ret;
+}
+
+/* Expects field FIELD of type EXPECTED_TYPE in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+jexpect (json_object *obj, const char *field, json_type expected_type,
+         json_object **j_val, char **errmsg)
+{
+  json_object *j_field;
+
+  RETURN_ON_JERR (json_object_object_get_ex (obj, field, &j_field), errmsg,
+                  "expects key \"%s\"", field);
+  RETURN_ON_JERR (json_object_is_type (j_field, expected_type), errmsg,
+                  "expects JSON item of type \"%s\" for field \"%s\"",
+                  json_type_to_name (expected_type), field);
+  *j_val = j_field;
+  return J_OK;
+}
+
+/* Parses JSON object as a Poke value.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static inline int
+pvalue (json_object *obj, pk_val *pval, char **errmsg)
+{
+  static const struct
+  {
+    int type_code;
+    const char *name;
+  } TYPES[] = {
+    { PK_UNKNOWN, "\"Unknown\"" },
+    { PK_INT, "\"Integer\"" },
+    { PK_UINT, "\"UnsignedInteger\"" },
+    { PK_STRING, "\"String\"" },
+    { PK_OFFSET, "\"Offset\"" },
+    { PK_ARRAY, "\"Array\"" },
+    { PK_STRUCT, "\"Struct\"" },
+    { PK_CLOSURE, "\"Closure\"" },
+    { PK_ANY, "\"Any\"" },
+  };
+  static const int TYPES_LEN = sizeof (TYPES) / sizeof (TYPES[0]);
+  int type_code;
+  const char *type_str;
+  json_object *j_type;
+
+  if (obj == NULL) {
+    *pval = PK_NULL;
+    return J_OK;
+  }
+
+  RETURN_ON_JERR (json_object_object_get_ex (obj, "type", &j_type), errmsg,
+                  "expects \"type\" key");
+  type_str = json_object_to_json_string (j_type);
+
+  type_code = PK_UNKNOWN;
+  for (int i = 0; i < TYPES_LEN; ++i)
+    if (STREQ (type_str, TYPES[i].name))
+      {
+        type_code = TYPES[i].type_code;
+        break;
+      }
+  return pexpect (obj, type_code, pval, errmsg);
+}
+
+static int pexpect_sct (json_object *j_sct, pk_val *pk_sct, char **errmsg);
+static int pexpect_arr (json_object *j_arr, pk_val *p_array, char **errmsg);
+
+/* Expects a Poke value of type specified by TYPE_CODE in JSON object.
+ *
+ * Valid values for TYPE_CODE:
+ *   PK_UNKNOWN, PK_INT, PK_UINT, PK_STRING, PK_OFFSET, PK_ARRAY, PK_STRUCT,
+ *   PK_CLOSURE, PK_ANY.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect (json_object *j, int type_code, pk_val *pval, char **errmsg)
+{
+  json_object *j_tmp;
+  const char *str;
+
+  switch (type_code)
+    {
+    case PK_STRING:
+      RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+                      errmsg, "invalid String");
+      str = json_object_get_string (j_tmp);
+      RETURN_ERR_IF (STRNEQ (str, "String"), errmsg,
+                     "expects \"String\" in field \"type\" but got \"%s\"",
+                     str);
+
+      RETURN_ON_JERR (jexpect (j, "value", json_type_string, &j_tmp, errmsg),
+                      errmsg, "invalid String");
+      str = json_object_get_string (j_tmp);
+      RETURN_ERR_IF ((*pval = pk_make_string (str)) == PK_NULL, errmsg,
+                     "pk_make_string () failed");
+
+      return J_OK;
+
+    case PK_OFFSET:
+      {
+        pk_val mag, unit;
+        int code;
+
+        RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+                        errmsg, "invalid Offset");
+        str = json_object_get_string (j_tmp);
+        RETURN_ERR_IF (STRNEQ (str, "Offset"), errmsg,
+                       "expects \"Offset\" in field \"type\" but got \"%s\"",
+                       str);
+
+        RETURN_ON_JERR (
+            jexpect (j, "magnitude", json_type_object, &j_tmp, errmsg), errmsg,
+            "invalid Offset");
+        RETURN_ON_JERR (pvalue (j_tmp, &mag, errmsg), errmsg,
+                        "invalid Offset");
+        code = pk_type_code (pk_typeof (mag));
+        RETURN_ERR_IF (code != PK_INT && code != PK_UINT, errmsg,
+                       "invalid Offset magnitude");
+
+        RETURN_ON_JERR (jexpect (j, "unit", json_type_object, &j_tmp, errmsg),
+                        errmsg, "invalid Offset");
+        RETURN_ON_JERR (pexpect (j_tmp, PK_UINT, &unit, errmsg), errmsg,
+                        "invalid Offset unit");
+
+        RETURN_ERR_IF ((*pval = pk_make_offset (mag, unit)) == PK_NULL, errmsg,
+                       "pk_make_offset () failed");
+        return J_OK;
+      }
+
+    case PK_INT:
+      {
+        int64_t value;
+        int size;
+
+        RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+                        errmsg, "invalid Integer");
+        str = json_object_get_string (j_tmp);
+        RETURN_ERR_IF (STRNEQ (str, "Integer"), errmsg,
+                       "expects \"Integer\" in field \"type\" but got \"%s\"",
+                       str);
+
+        RETURN_ON_JERR (jexpect (j, "value", json_type_int, &j_tmp, errmsg),
+                        errmsg, "invalid Integer");
+        value = json_object_get_int64 (j_tmp);
+        RETURN_ON_JERR (jexpect (j, "size", json_type_int, &j_tmp, errmsg),
+                        errmsg, "invalid Integer");
+        size = json_object_get_int (j_tmp);
+
+        RETURN_ERR_IF ((*pval = pk_make_int (value, size)) == PK_NULL, errmsg,
+                       "pk_make_int () failed");
+        return J_OK;
+      }
+
+    case PK_UINT:
+      {
+        uint64_t value;
+        int size;
+
+        RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+                        errmsg, "invalid UnsignedInteger");
+        str = json_object_get_string (j_tmp);
+        RETURN_ERR_IF (
+            STRNEQ (str, "UnsignedInteger"), errmsg,
+            "expects \"UnsignedInteger\" in field \"type\" but got \"%s\"",
+            str);
+
+        RETURN_ON_JERR (jexpect (j, "value", json_type_int, &j_tmp, errmsg),
+                        errmsg, "invalid UnsignedInteger");
+
+        /* Older versions of libjson-c (0.3.1 & older) do not support
+           json_object_get_uint64 (only json_object_get_int64).
+
+           In order to support previous versions, we store unsigned integers
+           as signed integers despite them being too large to represent as
+           signed. (i.e. they are stored as negative).
+
+           However, users expect to get the unsigned integer they stored.
+
+           Thus, we have to convert it back to uint64_t.  */
+        value = (uint64_t)json_object_get_int64 (j_tmp);
+
+        RETURN_ON_JERR (jexpect (j, "size", json_type_int, &j_tmp, errmsg),
+                        errmsg, "invalid UnsignedInteger");
+        size = json_object_get_int (j_tmp);
+
+        RETURN_ERR_IF ((*pval = pk_make_uint (value, size)) == PK_NULL, errmsg,
+                       "pk_make_uint () failed");
+        return J_OK;
+      }
+
+    case PK_STRUCT:
+      RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+                      errmsg, "invalid Struct");
+      str = json_object_get_string (j_tmp);
+      RETURN_ERR_IF (STRNEQ (str, "Struct"), errmsg,
+                     "expects \"Struct\" in field \"type\" but got \"%s\"",
+                     str);
+      return pexpect_sct (j, pval, errmsg);
+
+    case PK_ARRAY:
+      RETURN_ON_JERR (jexpect (j, "type", json_type_string, &j_tmp, errmsg),
+                      errmsg, "invalid Array");
+      str = json_object_get_string (j_tmp);
+      RETURN_ERR_IF (STRNEQ (str, "Array"), errmsg,
+                     "expects \"Array\" in field \"type\" but got \"%s\"",
+                     str);
+      return pexpect_arr (j, pval, errmsg);
+
+    case PK_ANY:
+    case PK_CLOSURE:
+      return jerror (J_NOK, errmsg, "unsupported Poke type (code:%d)",
+                     type_code);
+
+    case PK_UNKNOWN:
+    default:
+      return jerror (J_NOK, errmsg, "unknown Poke type (code:%d)", type_code);
+    }
+
+  return J_NOK;
+}
+
+static int
+pexpect_map (json_object *j_map, pk_val p_val, char **errmsg)
+{
+  json_object *j_tmp;
+  pk_val p_ios, p_off;
+  int strict_p;
+
+#define MAP_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Mapping")
+
+  MAP_JERR (jexpect (j_map, "mapped", json_type_boolean, &j_tmp, errmsg));
+  if (!json_object_get_boolean (j_tmp)) /* The value is not mapped */
+    return J_OK;
+
+  MAP_JERR (jexpect (j_map, "strict", json_type_boolean, &j_tmp, errmsg));
+  strict_p = json_object_get_boolean (j_tmp);
+
+  MAP_JERR (jexpect (j_map, "IOS", json_type_int, &j_tmp, errmsg));
+  RETURN_ERR_IF ((p_ios = pk_make_int (json_object_get_int (j_tmp), 32))
+                     == PK_NULL,
+                 errmsg, "pk_make_int (, 32) failed");
+
+  MAP_JERR (jexpect (j_map, "offset", json_type_object, &j_tmp, errmsg));
+  MAP_JERR (pexpect (j_tmp, PK_OFFSET, &p_off, errmsg));
+
+  pk_val_set_mapped (p_val, 1);
+  pk_val_set_strict (p_val, strict_p);
+  pk_val_set_ios (p_val, p_ios);
+  pk_val_set_offset (p_val, p_off);
+
+  return J_OK;
+}
+
+/* Expects a Poke struct value in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_sct (json_object *j_sct, pk_val *p_struct, char **errmsg)
+{
+  json_object *j_fields, *j_mapping, *j_name;
+  pk_val p_sct_name, p_nfields, p_sct_type, p_sct;
+  pk_val *p_fnames, *p_ftypes;
+  size_t fields_len;
+
+#define SCT_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Struct")
+
+  SCT_JERR (jexpect (j_sct, "name", json_type_object, &j_name, errmsg));
+  SCT_JERR (jexpect (j_sct, "fields", json_type_array, &j_fields, errmsg));
+  SCT_JERR (jexpect (j_sct, "mapping", json_type_object, &j_mapping, errmsg));
+
+  fields_len = json_object_array_length (j_fields);
+  p_nfields = pk_make_uint (fields_len, 64);
+
+  SCT_JERR (pexpect (j_name, PK_STRING, &p_sct_name, errmsg));
+
+  pk_allocate_struct_attrs (p_nfields, &p_fnames, &p_ftypes);
+  p_sct_type = pk_make_struct_type (p_nfields, p_sct_name, p_fnames, p_ftypes);
+  p_sct = pk_make_struct (p_nfields, p_sct_type);
+
+  for (size_t i = 0; i < fields_len; i++)
+    {
+      json_object *j_elem, *j_name, *j_value, *j_boffset;
+      pk_val p_sct_name, p_sct_value, p_sct_boffset;
+
+      j_elem = json_object_array_get_idx (j_fields, i);
+
+      SCT_JERR (jexpect (j_elem, "name", json_type_object, &j_name, errmsg));
+      SCT_JERR (jexpect (j_elem, "value", json_type_object, &j_value, errmsg));
+      SCT_JERR (
+          jexpect (j_elem, "boffset", json_type_object, &j_boffset, errmsg));
+
+      SCT_JERR (pexpect (j_name, PK_STRING, &p_sct_name, errmsg));
+      SCT_JERR (pvalue (j_value, &p_sct_value, errmsg));
+      SCT_JERR (pexpect (j_boffset, PK_UINT, &p_sct_boffset, errmsg));
+
+      RETURN_ERR_IF (p_sct_value == PK_NULL, errmsg, "invalid Struct");
+
+      pk_struct_type_set_fname (p_sct_type, i, p_sct_name);
+      pk_struct_type_set_ftype (p_sct_type, i, pk_typeof (p_sct_value));
+      pk_struct_set_field_name (p_sct, i, p_sct_name);
+      pk_struct_set_field_value (p_sct, i, p_sct_value);
+      pk_struct_set_field_boffset (p_sct, i, p_sct_boffset);
+    }
+
+  SCT_JERR (pexpect_map (j_mapping, p_sct, errmsg));
+  *p_struct = p_sct;
+  return J_OK;
+
+#undef SCT_JERR
+}
+
+/* Expects a Poke array elem in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_aelem (json_object *j_elem, pk_val *p_elem_val, pk_val *p_elem_boff,
+               char **errmsg)
+{
+  json_object *j_val, *j_boff;
+
+#define AELEM_JERR(cond)                                                      \
+  RETURN_ON_JERR ((cond), errmsg, "invalid Array element")
+
+  AELEM_JERR (jexpect (j_elem, "value", json_type_object, &j_val, errmsg));
+  AELEM_JERR (jexpect (j_elem, "boffset", json_type_object, &j_boff, errmsg));
+
+  AELEM_JERR (pvalue (j_val, p_elem_val, errmsg));
+  AELEM_JERR (pexpect (j_boff, PK_UINT, p_elem_boff, errmsg));
+
+  RETURN_ERR_IF (pk_integral_type_size (pk_typeof (*p_elem_boff)) == 64,
+                 errmsg, "boffset should be an uint<64>");
+
+  return J_OK;
+
+#undef AELEM_JER
+}
+
+/* Expects a Poke array in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_arr (json_object *j_arr, pk_val *p_array, char **errmsg)
+{
+  json_object *j_elems, *j_elem, *j_mapping;
+  pk_val p_arr, p_value, p_boffset, p_aelem_type /*array element type*/,
+      p_arr_type;
+  size_t elems_len;
+
+#define ARR_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Array")
+
+  ARR_JERR (jexpect (j_arr, "elements", json_type_array, &j_elems, errmsg));
+  ARR_JERR (jexpect (j_arr, "mapping", json_type_object, &j_mapping, errmsg));
+
+  elems_len = json_object_array_length (j_elems);
+
+  /* FIXME no empty array */
+  if (elems_len == 0)
     {
-      poke_object = json_tokener_parse_ex (tok, json_str,
-                                           strlen (json_str));
+      *p_array = PK_NULL;
+      return J_OK;
     }
-  while ((jerr = json_tokener_get_error (tok)) == json_tokener_continue);
 
-  PK_MI_CHECK(errmsg, jerr == json_tokener_success, "%s",
-              json_tokener_error_desc (jerr));
+  /* assert (elems_len != 0); */
+
+  /* Type of the array will be the type of first element */
+  j_elem = json_object_array_get_idx (j_elems, 0);
+
+  /* FIXME no support for null items */
+  assert (j_elem != NULL);
 
-  err = json_object_object_get_ex (poke_object, "PokeValue", &search_object);
-  PK_MI_CHECK(errmsg, err != 0, "Not a valid PokeValue object");
+  ARR_JERR (pexpect_aelem (j_elem, &p_value, &p_boffset, errmsg));
+  p_aelem_type = pk_typeof (p_value);
+  p_arr_type = pk_make_array_type (p_aelem_type, PK_NULL);
+  p_arr = pk_make_array (pk_make_uint (elems_len, 64), p_arr_type);
 
-  if (pk_mi_json_to_val_1 (value, search_object, errmsg) == -1)
-    goto error;
+  pk_array_insert_elem (p_arr, 0, p_value);
+  RETURN_ERR_IF (!pk_val_equal_p (pk_array_elem_boffset (p_arr, 0), p_boffset),
+                 errmsg, "invalid Array: boffset mismatch at index 0");
 
-  json_tokener_free (tok);
+  for (size_t i = 1; i < elems_len; ++i)
+    {
+      j_elem = json_object_array_get_idx (j_elems, i);
+      assert (j_elem != NULL);
+      ARR_JERR (pexpect_aelem (j_elem, &p_value, &p_boffset, errmsg));
+      pk_array_insert_elem (p_arr, i, p_value);
+      RETURN_ERR_IF (
+          !pk_val_equal_p (pk_array_elem_boffset (p_arr, i), p_boffset),
+          errmsg, "invalid Array: boffset mismatch at index %zu", i);
+    }
 
-  return 0;
+  ARR_JERR (pexpect_map (j_mapping, p_arr, errmsg));
+  *p_array = p_arr;
+  return J_OK;
 
-  error:
-    return -1;
+#undef ARR_JERR
 }
 
 static int
@@ -989,7 +1073,7 @@ collect_json_arg (const char *name, pk_val value /* Note 
unused */,
 
   if (!json_object_object_get_ex (args, name, &obj))
     return 0;
-  if (!pk_mi_json_to_val_1 (&val, obj, NULL))
+  if (!pk_mi_jsonobj_to_val (&val, obj, NULL))
     return 0;
 
   pk_mi_set_arg (msg, name, val);
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 8653249d..f71f2f56 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -1917,5 +1917,8 @@ EXTRA_DIST = \
   poke.mi-json/pk_uint.json \
   poke.mi-json/pk_string.json \
   poke.mi-json/pk_offset.json \
+  poke.mi-json/pk_offset_uint.json \
   poke.mi-json/pk_array.json \
+  poke.mi-json/pk_sct_empty.json \
+  poke.mi-json/pk_sct_empty_mapped.json \
   poke.mi-json/pk_sct.json
diff --git a/testsuite/poke.mi-json/Makefile.am 
b/testsuite/poke.mi-json/Makefile.am
index 80e466f0..ac56beb1 100644
--- a/testsuite/poke.mi-json/Makefile.am
+++ b/testsuite/poke.mi-json/Makefile.am
@@ -34,7 +34,8 @@ mi_json_CPPFLAGS = -I$(top_builddir)/gl -I$(top_srcdir)/gl \
                    -I$(top_srcdir)/common \
                    -DTESTDIR=\"$(abs_srcdir)\" \
                    -DPKGDATADIR=\"$(pkgdatadir)\" \
-                   -I$(top_srcdir)/libpoke -I$(top_builddir)/libpoke
+                   -I$(top_srcdir)/libpoke -I$(top_builddir)/libpoke \
+                   -I$(top_srcdir)/common
 
 # Old DejaGnu versions need a specific old interpretation of 'inline'.
 mi_json_CFLAGS = -fgnu89-inline $(JSON_C_CFLAGS)
diff --git a/testsuite/poke.mi-json/mi-json.c b/testsuite/poke.mi-json/mi-json.c
index 2ea077f7..0940dc6a 100644
--- a/testsuite/poke.mi-json/mi-json.c
+++ b/testsuite/poke.mi-json/mi-json.c
@@ -18,6 +18,7 @@
 
 #include <config.h>
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -33,6 +34,7 @@
 #include "pk-mi-json.h"
 #include "libpoke.h"
 #include "../poke.libpoke/term-if.h"
+#include "pk-utils.h"
 
 #define PASS 1
 #define FAIL 0
@@ -83,276 +85,310 @@ parse_json_str_object (const char *json_str, json_object 
**pk_obj)
 
 int test_json_pk_val (json_object *obj, pk_val val);
 
+#define J_OK 1
+#define J_NOK 0 /* Not OK */
+
+#define JFIELD_IMPL(funcname, line, jobj, field, jval, ...)                   \
+  do                                                                          \
+    {                                                                         \
+      if (json_object_object_get_ex ((jobj), (field), (jval)) != J_OK)        \
+        {                                                                     \
+          fprintf (stderr, "%s:%d ", (funcname), (line));                     \
+          fprintf (stderr, __VA_ARGS__);                                      \
+          fputs ("\n", stderr);                                               \
+          return FAIL;                                                        \
+        }                                                                     \
+    }                                                                         \
+  while (0)
+#define JFIELD(...) JFIELD_IMPL (__func__, __LINE__, __VA_ARGS__)
+
+#define CHK_IMPL(funcname, line, cond, ...)                                   \
+  do                                                                          \
+    {                                                                         \
+      if (!(cond))                                                            \
+        {                                                                     \
+          fprintf (stderr, "%s:%d ", (funcname), (line));                     \
+          fprintf (stderr, __VA_ARGS__);                                      \
+          fputs ("\n", stderr);                                               \
+          return FAIL;                                                        \
+        }                                                                     \
+    }                                                                         \
+  while (0)
+#define CHK(...) CHK_IMPL (__func__, __LINE__, __VA_ARGS__)
+
+#define STREQ_LIT(str, string_literal)                                        \
+  (strncmp (str, string_literal, strlen (string_literal)) == 0)
+
 int
-test_json_pk_int (json_object *pk_int_obj, pk_val pk_int)
+test_json_pk_int (json_object *j_int, pk_val p_int)
 {
-  json_object *current;
-  const char *typename;
+  json_object *j_type, *j_value, *j_size;
 
-  /* Poke integers properties are : "type", "value" and "size".  */
-  if (json_object_object_length (pk_int_obj) != 3)
-    return FAIL;
+  CHK (json_object_object_length (j_int) == 3,
+       "Integer expects 3 fields: type, value, size");
 
-  if (!json_object_object_get_ex (pk_int_obj, "type", &current))
-    return FAIL;
+  JFIELD (j_int, "type", &j_type, "Integer expects `type` field");
+  JFIELD (j_int, "value", &j_value, "Integer expects `value` field");
+  JFIELD (j_int, "size", &j_size, "Integer expects `size` field");
 
-  typename = json_object_get_string (current);
-  if (strncmp (typename, "Integer", strlen ("Integer")))
-    return FAIL;
+  {
+    const char *str = json_object_get_string (j_type);
 
-  if (!json_object_object_get_ex (pk_int_obj, "value", &current))
-    return FAIL;
+    CHK (STREQ_LIT (str, "Integer"),
+         "Integer type: expects `Integer`, got `%s`", str);
+  }
+  {
+    int64_t value = pk_int_value (p_int);
+    int64_t v = json_object_get_int64 (j_value);
 
-  if (json_object_get_int64 (current) != pk_int_value (pk_int))
-    return FAIL;
+    CHK (value == v, "Integer value: expects %" PRIi64 ", got %" PRIi64, value,
+         v);
+  }
+  {
+    int size = pk_int_size (p_int);
+    int s = json_object_get_int (j_size);
 
-  if (!json_object_object_get_ex (pk_int_obj, "size", &current))
-    return FAIL;
+    CHK (size == s, "Integer size: expects %d, got %d", size, s);
+  }
 
-  if (json_object_get_int (current) != pk_int_size (pk_int))
-    return FAIL;
   return PASS;
 }
 
 int
-test_json_pk_uint (json_object *pk_uint_obj, pk_val pk_uint)
+test_json_pk_uint (json_object *j_uint, pk_val p_uint)
 {
-  json_object *current;
-  const char *typename;
-
-  /* Poke unsigned integers properties are : "type", "value" and "size".  */
-  if (json_object_object_length (pk_uint_obj) != 3)
-    return FAIL;
-
-  if (!json_object_object_get_ex (pk_uint_obj, "type", &current))
-    return FAIL;
-
-  typename = json_object_get_string (current);
-  if (strncmp (typename, "UnsignedInteger",
-               strlen ("UnsignedInteger")))
-    return FAIL;
-
-  if (!json_object_object_get_ex (pk_uint_obj, "value", &current))
-    return FAIL;
-
-  /* NOTE: This version of libjson-c does not support *_get_uint64 so we use
-     the int64 version and always cast to the unsigned type.  */
-  if ((uint64_t) json_object_get_int64 (current) != pk_uint_value (pk_uint))
-    return FAIL;
-
-  if (!json_object_object_get_ex (pk_uint_obj, "size", &current))
-    return FAIL;
-
-  if (json_object_get_int (current) != pk_uint_size (pk_uint))
-    return FAIL;
+  json_object *j_type, *j_value, *j_size;
+
+  CHK (json_object_object_length (j_uint) == 3,
+       "UnsignedInteger expects 3 fields: type, value, size");
+
+  JFIELD (j_uint, "type", &j_type, "UnsignedInteger expects `type` field");
+  JFIELD (j_uint, "value", &j_value,
+          "UnsignedInteger expects `value` field");
+  JFIELD (j_uint, "size", &j_size, "UnsignedInteger expects `size` field");
+
+  {
+    const char *str = json_object_get_string (j_type);
+
+    CHK (STREQ_LIT (str, "UnsignedInteger"),
+         "UnsignedInteger type: expects `UnsignedInteger`, got `%s`", str);
+  }
+  {
+    /* Older versions of libjson-c (0.3.1 & older) do not support
+     * `json_object_get_uint64` (only `json_object_get_int64`).
+     */
+    uint64_t v = (uint64_t)json_object_get_int64 (j_value);
+    uint64_t value = pk_uint_value (p_uint);
+
+    CHK (value == v,
+         "UnsignedInteger value: expects %" PRIi64 ", got %" PRIi64, value, v);
+  }
+  {
+    int s = json_object_get_int (j_size);
+    int size = pk_uint_size (p_uint);
+
+    CHK (size == s, "UnsignedInteger size: expects %d, got %d", size, s);
+  }
 
   return PASS;
 }
 
 int
-test_json_pk_string (json_object *pk_string_obj, pk_val pk_string)
+test_json_pk_string (json_object *j_string, pk_val p_string)
 {
-  json_object *current;
-  const char *typename, *json_str_value, *pk_string_value;
+  json_object *j_type, *j_value;
 
-  /* Poke string properties are : "type" and "value".  */
-  if (json_object_object_length (pk_string_obj) != 2)
-    return FAIL;
+  CHK (json_object_object_length (j_string) == 2,
+       "String expects 2 fields: type, value");
 
-  if (!json_object_object_get_ex (pk_string_obj, "type", &current))
-    return FAIL;
+  JFIELD (j_string, "type", &j_type, "String expects `type` field");
+  JFIELD (j_string, "value", &j_value, "String expects `value` field");
 
-  typename = json_object_get_string (current);
-  if (strncmp (typename, "String", strlen ("String")))
-    return FAIL;
+  {
+    const char *str = json_object_get_string (j_type);
 
-  if (!json_object_object_get_ex (pk_string_obj, "value", &current))
-    return FAIL;
+    CHK (STREQ_LIT (str, "String"),
+         "String type: expects `String`, got `%s`", str);
+  }
+  {
+    const char* str = pk_string_str (p_string);
+    const char* s = json_object_get_string (j_value);
 
-  json_str_value = json_object_get_string (current);
-  pk_string_value = pk_string_str (pk_string);
-  if (strncmp (json_str_value, pk_string_value, strlen (pk_string_value)))
-    return FAIL;
+    CHK (STREQ (str, s), "String value: expects \"%s\", got \"%s\"",
+         str, s);
+  }
 
   return PASS;
 }
 
 int
-test_json_pk_offset (json_object *pk_offset_obj, pk_val pk_offset)
+test_json_pk_offset (json_object *j_offset, pk_val p_offset)
 {
-  json_object *current;
-  pk_val pk_magnitude, pk_unit;
-  const char *typename;
-  int signed_p;
+  json_object *j_type, *j_magnitude, *j_unit;
+
+  CHK (json_object_object_length (j_offset) == 3,
+       "Offset expects 3 fields: type, magnitude, unit");
 
   /* Poke offset properties are : "type", "magnitude" and "unit".  */
-  if (json_object_object_length (pk_offset_obj) != 3)
-    return FAIL;
-
-  if (!json_object_object_get_ex (pk_offset_obj, "type", &current))
-    return FAIL;
-
-  typename = json_object_get_string (current);
-  if (strncmp (typename, "Offset", strlen ("Offset")))
-    return FAIL;
-
-  if (!json_object_object_get_ex (pk_offset_obj, "magnitude", &current))
-    return FAIL;
-
-  /* "magnitude" is either an UnsignedInteger or an Integer.
-      Check if its UnsignedInteger or Integer.  */
-  pk_magnitude = pk_offset_magnitude (pk_offset);
-  signed_p = pk_int_value (pk_integral_type_signed_p (pk_typeof 
(pk_magnitude)));
-  if (signed_p && test_json_pk_int (current, pk_magnitude) == FAIL)
-    return FAIL;
-
-  if (!signed_p && test_json_pk_uint (current, pk_magnitude) == FAIL)
-    return FAIL;
-
-  /* "unit" is an UnsignedInteger.  */
-  if (!json_object_object_get_ex (pk_offset_obj, "unit", &current))
-    return FAIL;
-
-  pk_unit = pk_offset_unit (pk_offset);
-  if (test_json_pk_uint (current, pk_unit) == FAIL)
-    return FAIL;
+  JFIELD (j_offset, "type", &j_type, "Offset expects `type` field");
+  JFIELD (j_offset, "magnitude", &j_magnitude,
+          "Offset expects `magnitude` field");
+  JFIELD (j_offset, "unit", &j_unit, "Offset expects `unit` field");
+
+  {
+    const char *str = json_object_get_string (j_type);
+
+    CHK (STREQ_LIT (str, "Offset"), "Offset type: expects `Offset`, got `%s`",
+         str);
+  }
+  {
+    pk_val p_mag, p_unit;
+    int signed_p;
+    uint64_t size;
+
+    p_mag = pk_offset_magnitude (p_offset);
+    signed_p = pk_int_value (pk_integral_type_signed_p (pk_typeof (p_mag)));
+
+    if (signed_p)
+      CHK (test_json_pk_int (j_magnitude, p_mag) == PASS,
+           "Invalid Offset magnitude");
+    else
+      CHK (test_json_pk_uint (j_magnitude, p_mag) == PASS,
+           "Invalid Offset magnitude");
+
+    p_unit = pk_offset_unit (p_offset);
+    signed_p = pk_int_value (pk_integral_type_signed_p (pk_typeof (p_unit)));
+
+    /* `unit` is a uint<64> */
+    CHK (!signed_p, "Offset unit: expects to be unsigned");
+    CHK (test_json_pk_uint (j_unit, p_unit) == PASS, "Invalid Offset unit");
+    CHK ((size = pk_uint_value (pk_integral_type_size (pk_typeof (p_unit))))
+             == 64,
+         "Offset unit: expects uint<64>, got uint<%d>", size);
+  }
 
   return PASS;
 }
 
 int
-test_json_pk_null (json_object *pk_null_obj, pk_val pk_null)
+test_json_pk_null (json_object *j_null, pk_val p_null)
 {
-  json_object *current;
-  const char *typename;
-
-  /* Poke null properties are : "type" and "value".  */
-  if (json_object_object_length (pk_null_obj) != 2)
-    return FAIL;
+  json_object *j_type, *j_value;
+  const char *str = json_object_get_string (j_type);
 
-  if (!json_object_object_get_ex (pk_null_obj, "type", &current))
-    return FAIL;
+  CHK (json_object_object_length (j_null) == 2,
+       "Null expects 2 fields: type, value");
 
-  typename = json_object_get_string (current);
-  if (strncmp (typename, "Null", strlen ("Null")))
-    return FAIL;
+  JFIELD (j_null, "type", &j_type, "Null expects `type` field");
+  JFIELD (j_null, "value", &j_value, "Null expects `value` field");
 
-  if (!json_object_object_get_ex (pk_null_obj, "value", &current))
-    return FAIL;
-
-  if (current != NULL)
-    return FAIL;
+  CHK (STREQ_LIT (str, "Null"), "Null type: expects `Null`, got `%s`", str);
+  CHK (json_object_is_type (j_value, json_type_null),
+       "Null value: expects `null`, got `%s`",
+       json_type_to_name (json_object_get_type (j_value)));
 
   return PASS;
 }
 
 int
-test_json_pk_sct (json_object *pk_sct_obj, pk_val pk_sct)
+test_json_pk_sct (json_object *j_sct, pk_val p_sct)
 {
-  json_object *current, *pk_sct_fields_obj, *pk_sct_field_obj;
-  pk_val pk_sct_name, pk_sct_fname, pk_sct_fboffset, pk_sct_fvalue;
-  const char *typename;
-
-  /* Poke struct properties are : "type", "name", "fields" and "mapping".  */
-  if (json_object_object_length (pk_sct_obj) != 4)
-    return FAIL;
-
-  if (!json_object_object_get_ex (pk_sct_obj, "type", &current))
-    return FAIL;
-
-  typename = json_object_get_string (current);
-  if (strncmp (typename, "Struct", strlen ("Struct")))
-    return FAIL;
-
-  if (!json_object_object_get_ex (pk_sct_obj, "name", &current))
-    return FAIL;
-
-  pk_sct_name = pk_struct_type_name (pk_struct_type (pk_sct));
-
-  if (test_json_pk_string (current, pk_sct_name) == FAIL)
-    return FAIL;
-
-  /* Get the fields of a struct and check them.  */
-  if (!json_object_object_get_ex (pk_sct_obj, "fields", &pk_sct_fields_obj))
-    return FAIL;
-
-  for (size_t i = 0 ; i < pk_uint_value (pk_struct_nfields (pk_sct)) ; i++)
-      pk_sct_fboffset = pk_struct_field_boffset (pk_sct, i);
-
-  for (size_t i = 0 ; i < pk_uint_value (pk_struct_nfields (pk_sct)) ; i++)
+  json_object *j_type, *j_name, *j_fields, *j_mapping;
+  uint64_t nfields;
+
+  CHK (json_object_object_length (j_sct) == 4,
+       "Struct expects 4 fields: type, name, fields, mapping");
+
+  JFIELD (j_sct, "type", &j_type, "Struct expects `type` field");
+  JFIELD (j_sct, "name", &j_name, "Struct expects `name` field");
+  JFIELD (j_sct, "fields", &j_fields, "Struct expects `fields` field");
+  JFIELD (j_sct, "mapping", &j_mapping, "Struct expects `fields` field");
+
+  {
+    const char *str = json_object_get_string (j_type);
+
+    CHK (STREQ_LIT (str, "Struct"), "Struct type: expects `Struct`, got `%s`",
+         str);
+  }
+  CHK (test_json_pk_string (j_name,
+                            pk_struct_type_name (pk_struct_type (p_sct))),
+       "Struct name: name mismatch");
+
+  nfields = pk_uint_value (pk_struct_nfields (p_sct));
+  CHK (nfields == json_object_array_length (j_fields),
+       "Struct fields: length mismatch");
+  for (uint64_t i = 0; i < nfields; i++)
     {
-      pk_sct_fname = pk_struct_field_name (pk_sct, i);
-      pk_sct_fboffset = pk_struct_field_boffset (pk_sct, i);
-      pk_sct_fvalue = pk_struct_field_value (pk_sct, i);
-
-      pk_sct_field_obj = json_object_array_get_idx (pk_sct_fields_obj, i);
-
-      if (!json_object_object_get_ex (pk_sct_field_obj, "name", &current))
-        return FAIL;
-
-      if (test_json_pk_string (current, pk_sct_fname) == FAIL)
-        return FAIL;
-
-      if (!json_object_object_get_ex (pk_sct_field_obj, "boffset", &current))
-        return FAIL;
-
-      if (test_json_pk_uint (current, pk_sct_fboffset) == FAIL)
-        return FAIL;
-
-      if (!json_object_object_get_ex (pk_sct_field_obj, "value", &current))
-        return FAIL;
-
-      if (test_json_pk_val (current, pk_sct_fvalue) == FAIL)
-        return FAIL;
+      json_object *j_field, *j_fname, *j_fvalue, *j_fboffset;
+
+      j_field = json_object_array_get_idx (j_fields, i);
+      assert (j_field != NULL);
+
+      JFIELD (j_field, "name", &j_fname,
+              "Struct field at index %zu expects `name` field", i);
+      JFIELD (j_field, "value", &j_fvalue,
+              "Struct field at index %zu expects `value` field", i);
+      JFIELD (j_field, "boffset", &j_fboffset,
+              "Struct field at index %zu expects `boffset` field", i);
+
+      CHK (test_json_pk_string (j_fname, pk_struct_field_name (p_sct, i))
+               == PASS,
+           "Struct field at index %zu: invalid name", i);
+      CHK (test_json_pk_val (j_fvalue, pk_struct_field_value (p_sct, i))
+               == PASS,
+           "Struct field at index %zu: invalid value", i);
+      CHK (test_json_pk_uint (j_fboffset, pk_struct_field_boffset (p_sct, i))
+               == PASS,
+           "Struct field at index %zu: invalid boffset", i);
     }
+  /* TODO: add test for mapping */
 
-  /* TODO: add test for mapping when its added on pk-mi-json.c.  */
   return PASS;
 }
 
 int
-test_json_pk_array (json_object *pk_array_obj, pk_val pk_array)
+test_json_pk_array (json_object *j_array, pk_val p_array)
 {
-  json_object *current, *pk_array_elems_obj, *pk_array_elem_obj;
-  pk_val pk_array_elem_value, pk_array_elem_boff;
-  const char *typename;
+  json_object *j_type, *j_elems, *j_boffset, *j_mapping, *j_elem, *j_elem_boff,
+      *j_elem_value;
+  pk_val p_elem_value, p_elem_boff;
+  uint64_t nelems;
 
-  /* Poke array properties are : "type", "elements" and "mapping".  */
-  if (json_object_object_length (pk_array_obj) != 3)
-    return FAIL;
+  CHK (json_object_object_length (j_array) == 3,
+       "Array expects 3 fields: type, elements, mapping (got %d keys)",
+       json_object_object_length (j_array));
 
-  if (!json_object_object_get_ex (pk_array_obj, "type", &current))
-    return FAIL;
+  JFIELD (j_array, "type", &j_type, "Array expects `type` field");
+  JFIELD (j_array, "elements", &j_elems, "Array expects `elements` field");
+  JFIELD (j_array, "mapping", &j_mapping, "Array expects `mapping` field");
 
-  typename = json_object_get_string (current);
-  if (strncmp (typename, "Array", strlen ("Array")))
-    return FAIL;
+  {
+    const char *str = json_object_get_string (j_type);
 
-  if (!json_object_object_get_ex (pk_array_obj, "elements", 
&pk_array_elems_obj))
-    return FAIL;
+    CHK (STREQ_LIT (str, "Array"), "Array type: expects `Array`, got `%s`",
+         str);
+  }
 
-  /* Access every element of the array and check it.  */
-  for (size_t i = 0 ; i < pk_uint_value (pk_array_nelem (pk_array)) ; i++)
+  nelems = pk_uint_value (pk_array_nelem (p_array));
+  for (uint64_t i = 0; i < nelems; i++)
     {
-      pk_array_elem_value = pk_array_elem_val (pk_array, i);
-      pk_array_elem_boff = pk_array_elem_boffset (pk_array, i);
-
-      pk_array_elem_obj = json_object_array_get_idx (pk_array_elems_obj, i);
-
-      if (!json_object_object_get_ex (pk_array_elem_obj, "boffset", &current))
-        return FAIL;
-
-      if (test_json_pk_uint (current, pk_array_elem_boff) == FAIL)
-        return FAIL;
-
-      if (!json_object_object_get_ex (pk_array_elem_obj, "value", &current))
-        return FAIL;
-
-      if (test_json_pk_val (current, pk_array_elem_value) == FAIL)
-        return FAIL;
+      j_elem = json_object_array_get_idx (j_elems, i);
+      JFIELD (j_elem, "boffset", &j_elem_boff,
+              "Array type: expects `boffset` field for element at index %zu",
+              i);
+      JFIELD (j_elem, "value", &j_elem_value,
+              "Array type: expects `value` field for element at index %zu", i);
+
+      p_elem_value = pk_array_elem_val (p_array, i);
+      p_elem_boff = pk_array_elem_boffset (p_array, i);
+
+      CHK (test_json_pk_uint (j_elem_boff, p_elem_boff) == PASS,
+           "Array type: invalid `boffset` for element at index %zu", i);
+      CHK (test_json_pk_val (j_elem_value, p_elem_value) == PASS,
+           "Array type: invalid `value` for element at index %zu", i);
     }
+  /* TODO: add test for mapping */
 
-  /* TODO: add test for mapping when its added on pk-mi-json.c.  */
   return PASS;
 }
 
@@ -498,18 +534,23 @@ test_json_to_val (pk_compiler pk, const char *pk_obj_str, 
pk_val val)
   json_object *pk_obj, *current;
   char *errmsg;
 
-  if (pk_mi_json_to_val (&pk_test_val, pk_obj_str, &errmsg) == -1)
+  if (pk_mi_json_to_val (&pk_test_val, pk_obj_str, &errmsg) == -1) {
+    fprintf (stderr, "pk_mi_json_to_val () failed: %s\n", errmsg);
     return FAIL;
+  }
+
+  printf ("\nParsed value:\n  ");
+  pk_print_val_with_params (pk, pk_test_val, 0, 0, 16, 2, 0, PK_PRINT_F_MAPS);
+  puts ("");
 
   /* Check if the pk_val returned from pk_mi_json_to_val
      is the same as the pk_val that we read from the test file.  */
 
   if (!pk_val_equal_p (pk_test_val, val))
     {
-      printf ("Expected value:\n");
+      printf ("Equality failure:\n  Expected value:\n    ");
       pk_print_val_with_params (pk, val, 0, 0, 16, 2, 0, PK_PRINT_F_MAPS);
-      printf ("\n");
-      printf ("Parsed value:\n");
+      printf ("\n  Parsed value:\n    ");
       pk_print_val_with_params (pk, pk_test_val, 0, 0, 16, 2, 0, 
PK_PRINT_F_MAPS);
       printf ("\n");
       return FAIL;
diff --git a/testsuite/poke.mi-json/pk_array.json 
b/testsuite/poke.mi-json/pk_array.json
index 1a42c5be..b473b7e8 100644
--- a/testsuite/poke.mi-json/pk_array.json
+++ b/testsuite/poke.mi-json/pk_array.json
@@ -103,7 +103,7 @@
             }
         ],
         "mapping" : {
-            "type" : "Null", "value" : null
+            "mapped": false
         }
     }
 }
diff --git a/testsuite/poke.mi-json/pk_offset_uint.json 
b/testsuite/poke.mi-json/pk_offset_uint.json
new file mode 100644
index 00000000..d03a9aa8
--- /dev/null
+++ b/testsuite/poke.mi-json/pk_offset_uint.json
@@ -0,0 +1,18 @@
+##
+23U#B
+##
+{
+    "PokeValue" : {
+        "type" : "Offset",
+        "magnitude" : {
+            "type" : "UnsignedInteger",
+            "value" : 23,
+            "size" : 32
+        },
+        "unit" : {
+            "type" : "UnsignedInteger",
+            "value" : 8,
+            "size" : 64
+        }
+    }
+}
diff --git a/testsuite/poke.mi-json/pk_sct.json 
b/testsuite/poke.mi-json/pk_sct.json
index 6efac2d7..e17b374a 100644
--- a/testsuite/poke.mi-json/pk_sct.json
+++ b/testsuite/poke.mi-json/pk_sct.json
@@ -44,8 +44,7 @@ Packet { i = 1, j = 2}
             }
         ],
         "mapping" : {
-            "type" : "Null",
-            "value" : null
+            "mapped": false
         }
     }
 }
diff --git a/testsuite/poke.mi-json/pk_sct_empty.json 
b/testsuite/poke.mi-json/pk_sct_empty.json
new file mode 100644
index 00000000..9535140d
--- /dev/null
+++ b/testsuite/poke.mi-json/pk_sct_empty.json
@@ -0,0 +1,17 @@
+type Empty = struct {};
+##
+Empty { }
+##
+{
+    "PokeValue" : {
+        "type" : "Struct",
+        "name" : {
+            "type" : "String",
+            "value" : "Empty"
+        },
+        "fields" : [],
+        "mapping" : {
+            "mapped": false
+        }
+    }
+}
diff --git a/testsuite/poke.mi-json/pk_sct_empty_mapped.json 
b/testsuite/poke.mi-json/pk_sct_empty_mapped.json
new file mode 100644
index 00000000..2b2169df
--- /dev/null
+++ b/testsuite/poke.mi-json/pk_sct_empty_mapped.json
@@ -0,0 +1,33 @@
+var fd = open ("*mem*");
+type Empty = struct {};
+##
+Empty @ fd : 1#B
+##
+{
+    "PokeValue" : {
+        "type" : "Struct",
+        "name" : {
+            "type" : "String",
+            "value" : "Empty"
+        },
+        "fields" : [],
+        "mapping" : {
+            "mapped": true,
+            "strict": true,
+            "IOS": 0,
+            "offset": {
+                "type": "Offset",
+                "magnitude" : {
+                    "type" : "Integer",
+                    "value" : 1,
+                    "size" : 32
+                },
+                "unit" : {
+                    "type" : "UnsignedInteger",
+                    "value" : 8,
+                    "size" : 64
+                }
+            },
+        }
+    }
+}
-- 
2.31.0



reply via email to

[Prev in Thread] Current Thread [Next in Thread]