poke-devel
[Top][All Lists]
Advanced

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

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


From: Jose E. Marchesi
Subject: Re: [PATCH v2 2/2] pk-mi-json: Improve JSON schema & rewrite pk_val parser
Date: Sun, 28 Mar 2021 22:04:40 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

Hi Mohammad.
Thanks for the patch.

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

Awesome.  This is OK for both master and maint/poke-1.
Salud!


>
> 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
> +                }
> +            },
> +        }
> +    }
> +}



reply via email to

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