[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] JSON schema refactoring and adaptive code changes.
From: |
Mohammad-Reza Nabipoor |
Subject: |
Re: [PATCH] JSON schema refactoring and adaptive code changes. |
Date: |
Fri, 17 Sep 2021 20:58:18 +0430 |
Hello, Kostas.
On Mon, Sep 06, 2021 at 04:49:03PM +0200, Kostas Chasialis wrote:
> Hello Poke team!
>
> This is the patch which applies the whole refactoring process we’ve discussed
> about on previous threads and on IRC.
>
> I believe its way better than the previous schema.
>
> Since there are a lot of changes made, something might have slipped my
> attention. Please feel free to comment!
>
> Thanks.
>
Thanks for your work.
In general, the patch is good but there are a few details that I think can be
improved.
Some of them are actually improvements to my previous code, and IMHO they
should be fixed now.
0. As I told you over IRC, the `etc/pk-mi-json-schema.json` patch is broken and
doesn't apply to master.
Just FTR :)
1. Please use "type" and "value" instead of "Type" and "Value" to make fields
more consistent.
2. What about making error handling macros shorter?
Instead of having `RETURN_ON_JERR`, `RETURN_ERR_IF` and `GOTO_ON_JERR`,
we can only have two: `FAIL_IF` and `GOTO_IF`.
And I think putting the error handling on a separate line helps readability.
E.g., instead of
```c
GOTO_ON_JERR (jexpect (json, "kind", json_type_int, &obj, errmsg), failed,
errmsg, "invalid message");
RETURN_ERR_IF ((*j_int = json_object_new_int64 (val)) == NULL, errmsg,
"json_object_new_int64 () failed");
```
we can write like this:
```c
int ret;
ret = jexpect (json, "kind", json_type_int, &obj, errmsg);
GOTO_IF (ret == J_NOK, failed, errmsg, "invalid message);
*j_int = json_object_new_int64 (val);
FAIL_IF (j_int == NULL, errmsg, "json_object_new_int64 () failed");
```
It's shorter, simpler (because we only have two functions) and IMHO more
readable.
3. `jexpect_*` function names are not clear. You're actually generating JSON
from `pk_val`. Jose would suggest a name like this `pk_val_to_json_*`.
(I hate this long prefix, but he loves it && he's the commander :D)
I think you need to rename the functions and make them more consistent.
We can do it over a Jitsi meeting, too.
4. Inline comments:
diff --git a/testsuite/poke.mi-json/mi-json.c b/testsuite/poke.mi-json/mi-json.c
index 714771ed..8e148315 100644
--- a/testsuite/poke.mi-json/mi-json.c
+++ b/testsuite/poke.mi-json/mi-json.c
[...]
int
-test_val_to_json (const char *pk_obj_str, pk_val val)
+test_val_to_json (pk_compiler pkc, const char *j_obj_str, pk_val val)
{
- const char *pk_test_obj_str;
- json_object *pk_test_obj, *current;
+ const char *j_obj_str_test;
Names start with `j_` prefix are JSON objects (by our convention).
Maybe `test_obj_str` is better.
+ json_object *j_obj, *j_obj_test;
s/j_obj_test/j_test/
s/j_obj/j_value/
+ char *errmsg;
- if ((pk_test_obj_str = pk_mi_val_to_json (val, NULL)) == NULL)
- return FAIL;
+ /* Get the JSON object string representation from val_to_json. */
+ if ((j_obj_str_test = pk_mi_val_to_json (val, &errmsg)) == NULL)
+ {
+ printf ("pk_mi_val_to_json () failed\n");
Please report the `errmsg`.
+ return J_NOK;
+ }
+
+ /* Parse it to get the actual JSON object. */
+ if (parse_json_str_object (j_obj_str_test, &j_obj_test) == J_NOK)
+ {
+ printf ("failed to parse JSON object\n");
+ return J_NOK;
+ }
- if (parse_json_str_object (pk_test_obj_str, &pk_test_obj) == FAIL)
- return FAIL;
+ /* Compare this JSON object to the one in the .json file. */
+ if (parse_json_str_object (j_obj_str, &j_obj) == J_NOK)
+ {
+ printf ("failed to parse JSON object\n");
+ return J_NOK;
+ }
- if (json_object_object_get_ex (pk_test_obj, "PokeValue", ¤t) == 0)
- return FAIL;
+ if (!json_object_equal (j_obj, j_obj_test))
+ {
+ printf ("json_object_equal () failed\n");
+ printf ("\n");
+ printf ("test JSON object : %s",
+ json_object_to_json_string_ext (j_obj_test,
+ JSON_C_TO_STRING_PRETTY));
+ printf ("\n");
+ printf ("actual JSON object : %s",
Please don't put space before the colon (:) character :)
+ json_object_to_json_string_ext (j_obj, JSON_C_TO_STRING_PRETTY));
- if (test_json_pk_val (current, val) == FAIL)
- return FAIL;
+ printf ("%s\n", errmsg);
Please remove this line. `errmsg` is not valid here.
- if (json_object_put (pk_test_obj) != 1)
- return FAIL;
+ return J_NOK;
+ }
- return PASS;
+ return J_OK;
}
void
@@ -681,5 +340,6 @@ main (int argc, char *argv[])
test_json_to_msg ();
test_json_to_val_to_json ();
totals ();
+
Please add tests for invalid JSONs.
return 0;
}
diff --git a/poke/pk-mi-json.c b/poke/pk-mi-json.c
index 297de22b..be8d4a8f 100644
--- a/poke/pk-mi-json.c
+++ b/poke/pk-mi-json.c
@@ -32,20 +32,6 @@
#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 */
@@ -173,878 +159,1614 @@ jerror (int ok, char **out, const char *fmt, ...)
*/
-/* Functions to convert pk_val to JSON Poke Value. */
-static json_object *pk_mi_val_to_json_1 (pk_val val, char **errmsg);
+/* Functions to convert Poke value to JSON object. */
+static int jvalue (pk_val val, json_object **j_val, char **errmsg);
+static int jtype (pk_val type, json_object **j_type, char **errmsg);
-static json_object *
-pk_mi_int_to_json (pk_val pk_int, char **errmsg)
+json_object *
+pk_mi_val_to_json_1 (pk_val val, char **errmsg)
Please mark as `static`.
{
- json_object *int_object, *type_object, *value_object, *size_object;
- const char *type;
- int size;
-
- assert (pk_type_code (pk_typeof (pk_int)) == PK_INT);
+ json_object *j_obj = NULL, *j_val, *j_type;
- int_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, int_object != NULL, "json_object_new_object () failed");
+ j_obj = json_object_new_object ();
+ GOTO_ERR_IF (j_obj == NULL, error, errmsg,
+ "json_object_new_object () failed");
- value_object = json_object_new_int64 (pk_int_value (pk_int));
- PK_MI_CHECK (errmsg, value_object != NULL,
- "json_object_new_object () failed");
- size = pk_int_size (pk_int);
- type = "Integer";
+ GOTO_ON_JERR (jvalue (val, &j_val, errmsg), error, errmsg,
+ "failed to create JSON object from Poke value");
On error, we're leaking `value_object`.
Please fix other memory leaks in this function like this one.
- size_object = json_object_new_int (size);
- type_object = json_object_new_string (type);
- PK_MI_CHECK (errmsg, size_object != NULL, "json_object_new_object ()
failed");
- PK_MI_CHECK (errmsg, type_object != NULL, "json_object_new_object ()
failed");
+ GOTO_ON_JERR (jtype (pk_typeof (val), &j_type, errmsg), error,
+ errmsg, "failed to create JSON object from Poke type");
- /* OK, fill the properties of our object. */
- json_object_object_add (int_object, "type", type_object);
- json_object_object_add (int_object, "value", value_object);
- json_object_object_add (int_object, "size", size_object);
+ GOTO_ERR_IF (json_object_object_add (j_obj, "Type", j_type) != 0, error,
+ errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j_obj, "Value", j_val) != 0, error,
+ errmsg, "json_object_object_add () failed");
- return int_object;
+ return j_obj;
error:
+ if (j_obj) assert (json_object_put (j_obj) == 1);
+
Please de-indent the label and if statement.
And don't call functions with side-effects in `assert`; they'll be removed
in release mode compilation (technically with `-DNDEBUG` flag).
return NULL;
}
-static json_object *
-pk_mi_uint_to_json (pk_val pk_uint, char **errmsg)
+const char *
+pk_mi_val_to_json (pk_val val, char **errmsg)
{
- json_object *uint_object, *type_object, *value_object, *size_object;
- const char *type;
- int size;
+ return json_object_to_json_string_ext (pk_mi_val_to_json_1 (val, errmsg),
+ JSON_C_TO_STRING_PRETTY);
- Why `JSON_C_TO_STRING_PRETTY`?
- We're leaking memeory here. You have to `strdup` the string and release
the JSON object.
+}
+
+static int jexpect_type_integral (pk_val pk_type_int, json_object **j_type_int,
+ char **errmsg);
+static int jexpect_type_string (pk_val pk_type_str, json_object **j_type_str,
+ char **errmsg);
+static int jexpect_type_offset (pk_val pk_type_off, json_object **j_type_off,
+ char **errmsg);
+static int jexpect_type_struct (pk_val pk_type_sct, json_object **j_type_sct,
+ char **errmsg);
+static int jexpect_type_array (pk_val pk_type_arr, json_object **j_type_arr,
+ char **errmsg);
+static int jexpect_type_null (pk_val pk_type_null, json_object **j_type_null,
+ char **errmsg);
- assert (pk_type_code (pk_typeof (pk_uint)) == PK_UINT);
+static int
+jtype (pk_val ptype, json_object **j_type, char **errmsg)
+{
+#define JEXPECT_TYPE(type) \
+ RETURN_ON_JERR (jexpect_type_##type (ptype, j_type, errmsg), errmsg, \
+ "failed to create JSON Type object for " #type)
- uint_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, uint_object != NULL, "json_object_new_object ()
failed");
+ if (ptype == PK_NULL)
+ {
+ JEXPECT_TYPE (null);
+ return J_OK;
+ }
- /* Older versions of libjson-c (0.3.1 & under) do not support
- json_object_new_uint64.
+ switch (pk_type_code (ptype))
+ {
+ case PK_INT:
+ case PK_UINT:
+ JEXPECT_TYPE (integral);
+ break;
+ case PK_STRING:
+ JEXPECT_TYPE (string);
+ break;
+ case PK_OFFSET:
+ JEXPECT_TYPE (offset);
+ break;
+ case PK_STRUCT:
+ JEXPECT_TYPE (struct);
+ break;
+ case PK_ARRAY:
+ JEXPECT_TYPE (array);
+ break;
+ case PK_CLOSURE:
Please return `J_NOK` here.
+ case PK_ANY:
Please handle ANY. The type is `{"code":"Any"}. And value is a Poke value (
the JSON with "Type" and "Value" fields).
+ default:
+ assert (0);
+ }
- 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). */
- value_object = json_object_new_int64 ((int64_t) pk_uint_value (pk_uint));
- PK_MI_CHECK (errmsg, value_object != NULL,
- "json_object_new_object () failed");
- size = pk_uint_size (pk_uint);
- type = "UnsignedInteger";
+ return J_OK;
- size_object = json_object_new_int (size);
- type_object = json_object_new_string (type);
- PK_MI_CHECK (errmsg, size_object != NULL, "json_object_new_object ()
failed");
- PK_MI_CHECK (errmsg, type_object != NULL, "json_object_new_object ()
failed");
+#undef JEXPECT
Wrong #undef :)
#undef JEXPECT_TYPE
+}
- /* OK, fill the properties of our object. */
- json_object_object_add (uint_object, "type", type_object);
- json_object_object_add (uint_object, "value", value_object);
- json_object_object_add (uint_object, "size", size_object);
+static int
+jexpect_type_error (json_object *j[], const int LEN)
Please use a better name, like `jfree_all`. This is responsible to free
JSON objects.
+{
+ for (int i = 0; i < LEN; i++)
s/LEN/len/
+ if (j[i])
+ {
+ int free_p = json_object_put (j[i]);
- return uint_object;
+ assert (free_p == 1);
+ }
- error:
- return NULL;
+ return J_NOK;
}
-static json_object *
-pk_mi_string_to_json (pk_val pk_str, char **errmsg)
+static int
+jexpect_type_integral (pk_val pk_type_int, json_object **j_type_int,
+ char **errmsg)
{
- json_object *string_object, *string_type_object, *string_value_object;
+ enum
+ {
+ type_int,
+ code,
+ info,
+ size,
+ signed_p,
+ };
+ const int LEN = 5;
+ json_object *j[LEN];
+ pk_val tmp;
- assert (pk_type_code (pk_typeof (pk_str)) == PK_STRING);
+ memset (j, 0, sizeof (j));
- string_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, string_object != NULL,
- "json_object_new_object () failed");
+ j[type_int] = json_object_new_object ();
+ GOTO_ERR_IF (j[type_int] == NULL, error, errmsg,
+ "json_object_new_object () failed");
- string_type_object = json_object_new_string ("String");
- PK_MI_CHECK (errmsg, string_type_object != NULL,
- "json_object_new_object () failed");
+ j[code] = json_object_new_string ("Integral");
+ GOTO_ERR_IF (j[code] == NULL, error, errmsg,
+ "json_object_new_string () failed");
- string_value_object = json_object_new_string (pk_string_str (pk_str));
- PK_MI_CHECK (errmsg, string_value_object != NULL,
- "json_object_new_object () failed");
+ j[info] = json_object_new_object ();
+ GOTO_ERR_IF (j[info] == NULL, error, errmsg,
+ "json_object_new_object () failed");
- /* OK, fill the properties of our object. */
- json_object_object_add (string_object, "type", string_type_object);
- json_object_object_add (string_object, "value", string_value_object);
+ tmp = pk_integral_type_size (pk_type_int);
+ j[size] = json_object_new_int64 (pk_uint_value (tmp));
+ GOTO_ERR_IF (j[size] == NULL, error, errmsg, "json_object_new_int ()
failed");
- return string_object;
+ tmp = pk_integral_type_signed_p (pk_type_int);
+ j[signed_p] = json_object_new_boolean (pk_int_value (tmp));
+ GOTO_ERR_IF (j[signed_p] == NULL, error, errmsg,
+ "json_object_new_boolean () failed");
- error:
- return NULL;
-}
+ GOTO_ERR_IF (json_object_object_add (j[info], "size", j[size]) != 0, error,
+ errmsg, "json_object_object_add () failed");
Here, you gave the ownership of `j[size]` to the `j[info]` object, so you
have assign `j[size]` to `NULL`.
+ GOTO_ERR_IF (json_object_object_add (j[info], "signed_p", j[signed_p]) != 0,
+ error, errmsg, "json_object_object_add () failed");
Ditto for `j[signed_p]`.
-static json_object *
-pk_mi_offset_to_json (pk_val pk_offset, char **errmsg)
-{
- json_object *offset_object, *offset_type_object;
- json_object *magnitude_object;
- json_object *unit_object, *unit_type_object, *unit_size_object;
- json_object *unit_value_object;
- pk_val off_mag, off_unit;
+ GOTO_ERR_IF (json_object_object_add (j[type_int], "code", j[code]) != 0,
+ error, errmsg, "json_object_object_add () failed");
Ditto for `j[code]`.
+ GOTO_ERR_IF (json_object_object_add (j[type_int], "info", j[info]) != 0,
+ error, errmsg, "json_object_object_add () failed");
Ditto for `j[info]`.
- assert (pk_type_code (pk_typeof (pk_offset)) == PK_OFFSET);
+ *j_type_int = j[type_int];
- offset_type_object = json_object_new_string ("Offset");
- PK_MI_CHECK (errmsg, offset_type_object != NULL,
- "json_object_new_object () failed");
+ return J_OK;
- off_mag = pk_offset_magnitude (pk_offset);
- magnitude_object = pk_type_code (pk_typeof (off_mag)) == PK_INT
- ? pk_mi_int_to_json (off_mag, errmsg)
- : pk_mi_uint_to_json (off_mag, errmsg);
+error:
+ return jexpect_type_error (j, LEN);
+}
- unit_type_object = json_object_new_string ("UnsignedInteger");
- PK_MI_CHECK (errmsg, unit_type_object != NULL,
- "json_object_new_object () failed");
+static int
+jexpect_type_string (pk_val pk_type_str, json_object **j_type_str,
+ char **errmsg)
+{
+ enum
+ {
+ type_str,
+ code
+ };
+ const int LEN = 2;
+ json_object *j[LEN];
- unit_size_object = json_object_new_int (64);
- PK_MI_CHECK (errmsg, unit_size_object != NULL,
- "json_object_new_object () failed");
+ memset (j, 0, sizeof (j));
- off_unit = pk_offset_unit (pk_offset);
- unit_value_object = json_object_new_int64 ((int64_t) pk_uint_value
(off_unit));
- PK_MI_CHECK (errmsg, unit_value_object != NULL,
- "json_object_new_object () failed");
+ /* Not used explictly. */
Unnecessary comment.
+ (void) pk_type_str;
- unit_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, unit_object != NULL,
- "json_object_new_object () failed");
+ j[type_str] = json_object_new_object ();
+ GOTO_ERR_IF (j[type_str] == NULL, error, errmsg,
+ "json_object_new_object () failed");
- json_object_object_add (unit_object, "type", unit_type_object);
- json_object_object_add (unit_object, "value", unit_value_object);
- json_object_object_add (unit_object, "size", unit_size_object);
+ j[code] = json_object_new_string ("String");
+ GOTO_ERR_IF (j[code] == NULL, error, errmsg,
+ "json_object_new_string () failed");
- offset_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, offset_object != NULL, "json_object_new_object ()
failed");
+ GOTO_ERR_IF (json_object_object_add (j[type_str], "code", j[code]) != 0,
+ error, errmsg, "json_object_object_add () failed");
- /* Built sub-objects, add them to our offset_object. */
- json_object_object_add (offset_object, "type", offset_type_object);
- json_object_object_add (offset_object, "magnitude", magnitude_object);
- json_object_object_add (offset_object, "unit", unit_object);
+ *j_type_str = j[type_str];
- return offset_object;
+ return J_OK;
- error:
- return NULL;
+error:
+ return jexpect_type_error (j, LEN);
}
-static json_object *
-pk_mi_mapping_to_json (pk_val val, char **errmsg)
+static int
+jexpect_type_offset (pk_val pk_type_off, json_object **j_type_off,
+ char **errmsg)
{
enum
{
- mapping,
- mapped,
- strict,
- ios,
- offset
+ type_off,
+ code,
+ info,
+ magnitude,
+ unit
};
const int LEN = 5;
- /* Store all JSON objects in an array to make resource management easier */
json_object *j[LEN];
Please make sure, you're not leaking double-freeing these.
- int mapped_p;
+ pk_val tmp;
memset (j, 0, sizeof (j));
- j[mapping] = json_object_new_object ();
- PK_MI_CHECK (errmsg, j[mapping] != NULL, "json_object_new_object () failed");
+ j[type_off] = json_object_new_object ();
+ GOTO_ERR_IF (j[type_off] == NULL, error, errmsg,
+ "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");
+ j[code] = json_object_new_string ("Offset");
+ GOTO_ERR_IF (j[code] == NULL, error, errmsg,
+ "json_object_new_string () failed");
- if (!mapped_p)
- {
- json_object_object_add (j[mapping], "mapped", j[mapped]);
- return j[mapping];
- }
+ j[info] = json_object_new_object ();
+ GOTO_ERR_IF (j[info] == NULL, error, errmsg,
+ "json_object_new_object () failed");
- j[strict] = json_object_new_boolean (pk_val_strict_p (val));
- PK_MI_CHECK (errmsg, j[strict] != NULL, "json_object_new_boolean () failed");
+ tmp = pk_offset_type_base_type (pk_type_off);
+ GOTO_ON_JERR (jexpect_type_integral (tmp, &j[magnitude], errmsg), error,
+ errmsg, "failed to create magnitude value");
s/failed to create magnitude value/failed to create type for magnitude/
- j[offset] = pk_mi_offset_to_json (pk_val_offset (val), errmsg);
- if (j[offset] == NULL)
- goto error;
+ tmp = pk_offset_type_unit (pk_type_off);
+ j[unit] = json_object_new_int64 ((int64_t) pk_uint_value (tmp));
+ GOTO_ERR_IF(j[unit] == NULL, error, errmsg,
+ "json_object_new_int64 () failed");
- 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");
+ GOTO_ERR_IF (json_object_object_add (j[info], "magnitude", j[magnitude]) !=
0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[info], "unit", j[unit]) != 0,
+ error, errmsg, "json_object_object_add () 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]);
+ GOTO_ERR_IF (json_object_object_add (j[type_off], "code", j[code]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[type_off], "info", j[info]) != 0,
+ error, errmsg, "json_object_object_add () failed");
- return j[mapping];
+ *j_type_off = j[type_off];
-error:
- for (int i = 0; i < LEN; i++)
- if (j[i])
- {
- int free_p = json_object_put (j[i]);
+ return J_OK;
- assert (free_p == 1);
- }
- return NULL;
+error:
+ return jexpect_type_error (j, LEN);
}
-static json_object *
-pk_mi_sct_to_json (pk_val pk_sct, char **errmsg)
+static int
+jexpect_type_struct (pk_val pk_type_sct, json_object **j_type_sct,
+ char **errmsg)
{
- json_object *pk_sct_object, *pk_sct_type_object;
- json_object *pk_sct_fields_object, *pk_sct_field_object;
- json_object *pk_sct_mapping_object, *pk_sct_name_object;
- json_object *pk_sct_field_value_object;
- json_object *pk_sct_field_offset_object;
- json_object *pk_sct_field_name_object;
+ enum
+ {
+ type_sct,
+ code,
+ info,
+ name,
+ fname,
+ ftype,
+ field,
+ fields
+ };
+ const int LEN = 8;
+ json_object *j[LEN];
Ditto.
pk_val tmp;
- int err;
+ uint64_t nfields;
- assert (pk_type_code (pk_typeof (pk_sct)) == PK_STRUCT);
+ memset (j, 0, sizeof (j));
- pk_sct_type_object = json_object_new_string ("Struct");
- PK_MI_CHECK (errmsg, pk_sct_type_object != NULL,
+ j[type_sct] = json_object_new_object ();
+ GOTO_ERR_IF (j[type_sct] == NULL, error, errmsg,
"json_object_new_object () failed");
- pk_sct_fields_object = json_object_new_array ();
- PK_MI_CHECK (errmsg, pk_sct_fields_object != NULL,
- "json_object_new_object () failed");
+ j[code] = json_object_new_string ("Struct");
+ GOTO_ERR_IF (j[code] == NULL, error, errmsg,
+ "json_object_new_string () failed");
- /* Get the name of the struct type and convert it to JSON object. */
- tmp = pk_struct_type (pk_sct);
- pk_sct_name_object = pk_mi_string_to_json (pk_struct_type_name (tmp),
- errmsg);
- PK_MI_CHECK (errmsg, pk_sct_name_object != NULL,
+ j[info] = json_object_new_object ();
+ GOTO_ERR_IF (j[info] == NULL, error, errmsg,
"json_object_new_object () failed");
- /* Fill the array of struct fields. */
- for (ssize_t i = 0 ; i < pk_uint_value (pk_struct_nfields (pk_sct)) ; i++)
+ tmp = pk_struct_type_name (pk_type_sct);
+ if (tmp != PK_NULL)
{
- tmp = pk_struct_field_value (pk_sct, i);
- pk_sct_field_value_object = pk_mi_val_to_json_1 (tmp, errmsg);
- tmp = pk_struct_field_boffset (pk_sct, i);
- pk_sct_field_offset_object = pk_mi_uint_to_json (tmp, errmsg);
- tmp = pk_struct_field_name (pk_sct, i);
- pk_sct_field_name_object = pk_mi_string_to_json (tmp, errmsg);
+ j[name] = json_object_new_string (pk_string_str (tmp));
+ GOTO_ERR_IF (j[name] == NULL, error, errmsg,
+ "json_object_new_string () failed");
+ }
+ else
+ j[name] = NULL;
- if (pk_sct_field_value_object == NULL
- || pk_sct_field_offset_object == NULL
- || pk_sct_field_name_object == NULL)
- goto error;
+ j[fields] = json_object_new_array ();
+ GOTO_ERR_IF (j[fields] == NULL, error, errmsg,
+ "json_object_new_array () failed");
- pk_sct_field_object = json_object_new_object ();
+ tmp = pk_struct_type_nfields (pk_type_sct);
+ nfields = pk_uint_value (tmp);
+ for (size_t i = 0 ; i < nfields; i++)
+ {
+ tmp = pk_struct_type_fname (pk_type_sct, i);
+ if (tmp != PK_NULL)
+ {
+ j[fname] = json_object_new_string (pk_string_str (tmp));
+ GOTO_ERR_IF (j[fname] == NULL, error, errmsg,
+ "json_object_new_string/null () failed");
Please add the `i` to the `errmsg`.
+ }
+ else
+ j[fname] = NULL;
- json_object_object_add (pk_sct_field_object, "name",
- pk_sct_field_name_object);
+ tmp = pk_struct_type_ftype (pk_type_sct, i);
+ GOTO_ON_JERR (jtype (tmp, &j[ftype], errmsg), error, errmsg,
+ "failed to create struct field type");
Ditto.
- json_object_object_add (pk_sct_field_object, "value",
- pk_sct_field_value_object);
+ j[field] = json_object_new_object ();
+ GOTO_ERR_IF (j[field] == NULL, error, errmsg,
+ "json_object_new_object () failed");
Ditto.
- json_object_object_add (pk_sct_field_object, "boffset",
- pk_sct_field_offset_object);
+ GOTO_ERR_IF (json_object_object_add (j[field], "name", j[fname]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[field], "type", j[ftype]) != 0,
+ error, errmsg, "json_object_object_add () failed");
Ditto.
- err = json_object_array_add (pk_sct_fields_object,
- pk_sct_field_object);
- PK_MI_CHECK (errmsg, err != -1,
- "failed to add name object to struct field");
+ GOTO_ERR_IF (json_object_array_add (j[fields], j[field]) != 0, error,
+ errmsg, "json_object_array_add () failed");
Ditto.
}
- pk_sct_mapping_object = pk_mi_mapping_to_json (pk_sct, errmsg);
- if (pk_sct_mapping_object == NULL)
- goto error;
+ GOTO_ERR_IF (json_object_object_add (j[info], "name", j[name]) != 0, error,
+ errmsg, "json_ojbect_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[info], "fields", j[fields]) != 0,
+ error, errmsg, "json_object_object_add () failed");
- pk_sct_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, pk_sct_object != NULL,
- "json_object_new_object () failed");
+ GOTO_ERR_IF (json_object_object_add (j[type_sct], "code", j[code]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[type_sct], "info", j[info]) != 0,
+ error, errmsg, "json_object_object_add () failed");
- json_object_object_add (pk_sct_object, "type", pk_sct_type_object);
- json_object_object_add (pk_sct_object, "name", pk_sct_name_object);
- json_object_object_add (pk_sct_object, "fields", pk_sct_fields_object);
- json_object_object_add (pk_sct_object, "mapping", pk_sct_mapping_object);
+ *j_type_sct = j[type_sct];
- return pk_sct_object;
+ return J_OK;
- error:
- return NULL;
+error:
+ return jexpect_type_error (j, LEN);
}
-static json_object *
-pk_mi_array_to_json (pk_val pk_array, char **errmsg)
+static int
+jexpect_type_array (pk_val pk_type_arr, json_object **j_type_arr,
+ char **errmsg)
{
- json_object *pk_array_object, *pk_array_type_object;
- json_object *pk_array_mapping_object, *pk_array_elements_object;
- json_object *pk_array_element_object, *pk_array_element_value_object;
- json_object *pk_array_element_offset_object;
+ enum
+ {
+ type_arr,
+ code,
+ info,
+ bound,
+ b_value,
+ b_sizep,
+ etype
+ };
+ const int LEN = 7;
+ json_object *j[LEN];
Ditto.
pk_val tmp;
- int err;
+ int64_t bound_value;
+ int bound_size_p;
- assert (pk_type_code (pk_typeof (pk_array)) == PK_ARRAY);
+ memset (j, 0, sizeof (j));
- pk_array_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, pk_array_object != NULL,
+ j[type_arr] = json_object_new_object ();
+ GOTO_ERR_IF (j[type_arr] == NULL, error, errmsg,
"json_object_new_object () failed");
- const char *type = "Array";
- pk_array_type_object = json_object_new_string (type);
- PK_MI_CHECK (errmsg, pk_array_type_object != NULL,
- "json_object_new_object () failed");
+ j[code] = json_object_new_string ("Array");
+ GOTO_ERR_IF (j[code] == NULL, error, errmsg,
+ "json_object_new_string () failed");
- /* Initialize our array. */
- pk_array_elements_object = json_object_new_array ();
- PK_MI_CHECK (errmsg, pk_array_elements_object != NULL,
+ j[info] = json_object_new_object ();
+ GOTO_ERR_IF (j[info] == NULL, error, errmsg,
"json_object_new_object () failed");
- /* Fill elements object. */
- for (size_t i = 0 ; i < pk_uint_value (pk_array_nelem (pk_array)) ; i++)
+ tmp = pk_array_type_bound (pk_type_arr);
+ if (tmp == PK_NULL)
+ j[bound] = NULL;
+ else
{
- /* For every element on the array, get its value & offset and build
- the corresponding JSON objects. */
- tmp = pk_array_elem_val (pk_array, i);
- pk_array_element_value_object = pk_mi_val_to_json_1 (tmp, errmsg);
- tmp = pk_array_elem_boffset (pk_array, i);
- pk_array_element_offset_object = pk_mi_uint_to_json (tmp, errmsg);
-
- pk_array_element_object = json_object_new_object ();
+ pk_val p_bound, bound_type;
- json_object_object_add (pk_array_element_object, "value",
- pk_array_element_value_object);
+ p_bound = pk_array_type_bound (pk_type_arr);
+ bound_type = pk_typeof (p_bound);
- json_object_object_add (pk_array_element_object, "boffset",
- pk_array_element_offset_object);
+ switch (pk_type_code (bound_type))
+ {
+ case PK_UINT:
+ bound_value = pk_uint_value (p_bound);
+ bound_size_p = 0;
+ break;
+ case PK_OFFSET:
+ {
+ pk_val b_off_mag = pk_offset_magnitude (p_bound);
+
+ switch (pk_type_code (pk_typeof (b_off_mag)))
+ {
+ case PK_INT:
+ bound_value = pk_int_value (b_off_mag);
+ assert (bound_value > 0);
+ break;
+ case PK_UINT:
+ bound_value = pk_uint_value (b_off_mag);
+ break;
+ default:
+ assert (0);
+ }
+ bound_size_p = 1;
+ /* assert is a bit-offset. */
+ assert (pk_uint_value (pk_offset_unit (p_bound)) == 1);
+ break;
+ }
+ default:
+ GOTO_ERR_IF (1, error, errmsg, "invalid array bound\n");
Don't use `\n` in error message.
+ }
- err = json_object_array_add (pk_array_elements_object,
- pk_array_element_object);
- PK_MI_CHECK (errmsg, err != -1, "failed to add element to array");
+ j[bound] = json_object_new_object ();
+ GOTO_ERR_IF (j[bound] == NULL, error, errmsg,
+ "json_object_new_object () failed");
+ j[b_value] = json_object_new_int64 (bound_value);
+ GOTO_ERR_IF (j[b_value] == NULL, error, errmsg,
+ "json_object_new_int64 () failed");
+ j[b_sizep] = json_object_new_boolean (bound_size_p);
+ GOTO_ERR_IF (j[b_sizep] == NULL, error, errmsg,
+ "json_object_new_boolean () failed");
+ GOTO_ERR_IF (json_object_object_add (j[bound], "value", j[b_value]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[bound], "size_p", j[b_sizep]) !=
0,
+ error, errmsg, "json_object_object_add () failed");
}
- pk_array_mapping_object = pk_mi_mapping_to_json (pk_array, errmsg);
- if (pk_array_mapping_object == NULL)
- goto error;
+ tmp = pk_array_type_etype (pk_type_arr);
+ GOTO_ON_JERR (jtype (tmp, &j[etype], errmsg), error, errmsg,
+ "failed to create array etype");
- /* Everything is built on this point.
- Fill the properties of the array object. */
- json_object_object_add (pk_array_object, "type", pk_array_type_object);
- json_object_object_add (pk_array_object, "elements",
pk_array_elements_object);
- json_object_object_add (pk_array_object, "mapping", pk_array_mapping_object);
+ GOTO_ERR_IF (json_object_object_add (j[info], "bound", j[bound]) != 0, error,
+ errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[info], "etype", j[etype]) != 0, error,
+ errmsg, "json_object_object_add () failed");
- return pk_array_object;
+ GOTO_ERR_IF (json_object_object_add (j[type_arr], "code", j[code]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[type_arr], "info", j[info]) != 0,
+ error, errmsg, "json_object_object_add () failed");
- error:
- return NULL;
+ *j_type_arr = j[type_arr];
+
+ return J_OK;
+
+error:
+ return jexpect_type_error (j, LEN);
}
-static json_object *
-pk_mi_val_to_json_1 (pk_val val, char **errmsg)
+static int
+jexpect_type_null (pk_val pk_type_null, json_object **j_type_null,
+ char **errmsg)
{
- json_object *pk_val_object = NULL;
+ enum
+ {
+ type_null,
+ code
+ };
+ const int LEN = 2;
+ json_object *j[LEN];
+
+ memset (j, 0, sizeof (j));
+
+ /* Not used explictly. */
+ (void) pk_type_null;
+
+ j[type_null] = json_object_new_object ();
+ GOTO_ERR_IF (j[type_null] == NULL, error, errmsg,
+ "json_object_new_object () failed");
+ j[code] = json_object_new_string ("Null");
+ GOTO_ERR_IF (j[code] == NULL, error, errmsg,
+ "json_object_new_string () failed");
+
+ GOTO_ERR_IF (json_object_object_add (j[type_null], "code", j[code]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+
+ *j_type_null = j[type_null];
+
+ return J_OK;
+
+error:
+ return jexpect_type_error (j, LEN);
+}
+
+static int jexpect_int (pk_val pk_int, json_object **j_int, char **errmsg);
+static int jexpect_uint (pk_val pk_uint, json_object **j_uint, char **errmsg);
+static int jexpect_string (pk_val pk_str, json_object **j_str, char **errmsg);
+static int jexpect_offset (pk_val pk_off, json_object **j_off, char **errmsg);
+static int jexpect_struct (pk_val pk_sct, json_object **j_sct, char **errmsg);
+static int jexpect_array (pk_val pk_arr, json_object **j_arr, char **errmsg);
+
+static int
+jvalue (pk_val val, json_object **obj, char **errmsg)
+{
if (val == PK_NULL)
- return NULL;
+ {
+ *obj = NULL;
+ return J_OK;
+ }
+
+#define JEXPECT(type) \
+ RETURN_ON_JERR (jexpect_##type (val, obj, errmsg), errmsg, \
+ "failed to create JSON Value object for " #type)
+
switch (pk_type_code (pk_typeof (val)))
{
case PK_INT:
- pk_val_object = pk_mi_int_to_json (val, errmsg);
+ JEXPECT (int);
break;
case PK_UINT:
- pk_val_object = pk_mi_uint_to_json (val, errmsg);
+ JEXPECT (uint);
break;
case PK_STRING:
- pk_val_object = pk_mi_string_to_json (val, errmsg);
+ JEXPECT (string);
break;
case PK_OFFSET:
- pk_val_object = pk_mi_offset_to_json (val, errmsg);
+ JEXPECT (offset);
break;
case PK_STRUCT:
- pk_val_object = pk_mi_sct_to_json (val, errmsg);
+ JEXPECT (struct);
break;
case PK_ARRAY:
- pk_val_object = pk_mi_array_to_json (val, errmsg);
+ JEXPECT (array);
break;
case PK_CLOSURE:
case PK_ANY:
Please handle these too.
default:
assert (0);
}
- return pk_val_object;
+
+ return J_OK;
+
+#undef JEXPECT
}
-const char *
-pk_mi_val_to_json (pk_val val, char **errmsg)
+static int
+jexpect_int (pk_val pk_int, json_object **j_int, char **errmsg)
{
- json_object *pk_val_object, *pk_object;
+ int64_t val = pk_int_value (pk_int);
- pk_val_object = pk_mi_val_to_json_1 (val, errmsg);
+ RETURN_ERR_IF ((*j_int = json_object_new_int64 (val)) == NULL, errmsg,
+ "json_object_new_int64 () failed");
- pk_object = json_object_new_object ();
- PK_MI_CHECK (errmsg, pk_object != NULL,
- "failed to create new json_object");
+ return J_OK;
+}
- json_object_object_add (pk_object, "PokeValue", pk_val_object);
+static int
+jexpect_uint (const pk_val pk_uint, json_object **j_uint, char **errmsg)
+{
+ uint64_t val = pk_uint_value (pk_uint);
- return json_object_to_json_string_ext (pk_object, JSON_C_TO_STRING_PRETTY);
+ RETURN_ERR_IF ((*j_uint = json_object_new_int64 ((int64_t) val)) == NULL,
+ errmsg, "json_object_new_uint64 () failed");
- error:
- return NULL;
+ return J_OK;
}
-/* Functions to convert JSON object to Poke value. */
+static int
+jexpect_string (pk_val pk_str, json_object **j_str, char **errmsg)
+{
+ const char *val = pk_string_str (pk_str);
-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);
+ RETURN_ERR_IF ((*j_str = json_object_new_string (val)) == NULL, errmsg,
+ "json_object_new_string () failed");
-int
-pk_mi_json_to_val (pk_val *value, const char *json_str, char **errmsg)
+ return J_OK;
+}
+
+static int
+jexpect_offset (pk_val pk_off, json_object **j_off, char **errmsg)
{
- json_object *j_obj = NULL, *j_pokevalue;
- json_tokener *tok = NULL;
- enum json_tokener_error jerr;
- char *local_errmsg = NULL;
- int ret, free_p;
+ pk_val p_mag;
+ int64_t val;
- /* All internal functions assume `errmsg` is either NULL or valid pointer
- to a memory allocated by `malloc`. */
- if (errmsg)
- *errmsg = NULL; /* success */
+ *j_off = NULL;
+ GOTO_ERR_IF ((*j_off = json_object_new_object ()) == NULL, error, errmsg,
+ "json_object_new_object () failed");
Why do we need a `json_object_new_object()`?
You're assigning a another new JSON object to `j_off`, below.
- tok = json_tokener_new ();
- PK_MI_CHECK (errmsg, tok != NULL, "json_tokener_new () failed");
+ p_mag = pk_offset_magnitude (pk_off);
- 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));
+ switch (pk_type_code (pk_typeof (p_mag)))
+ {
+ case PK_INT:
+ val = pk_int_value (p_mag);
+ break;
+ case PK_UINT:
+ val = (int64_t) pk_uint_value (p_mag);
+ break;
+ default:
+ assert (0);
+ }
- 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);
+ GOTO_ERR_IF ((*j_off = json_object_new_int64 (val)) == NULL, error,
+ errmsg, "json_object_new_uint64 () failed");
- ret = 0;
- goto deinit; /* because of the `goto error` inside the PK_MI_CHECK macro */
+ return J_OK;
error:
- ret = -1;
-
-deinit:
- free (local_errmsg);
- if (j_obj)
+ if (*j_off)
{
- free_p = json_object_put (j_obj);
+ int free_p = json_object_put (*j_off);
assert (free_p == 1);
}
- if (tok)
- json_tokener_free (tok);
- return ret;
+ return J_NOK;
}
-/* 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)
+jexpect_map (pk_val val, json_object **j_map, char **errmsg)
{
- static const struct
+ enum
{
- 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\"" },
+ mapping,
+ mapped,
+ strict,
+ ios,
+ type,
+ value,
+ offset
};
- 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;
- }
+ const int LEN = 7;
+ /* Store all JSON objects in an array to make resource management easier */
+ json_object *j[LEN];
Ditto.
+ int mapped_p;
+ pk_val tmp, off_value, off_type;
+
+ memset (j, 0, sizeof (j));
- 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);
+ j[mapping] = json_object_new_object ();
+ GOTO_ERR_IF (j[mapping] == NULL, error, errmsg,
+ "json_object_new_object () failed");
- 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);
+ mapped_p = pk_val_mapped_p (val);
+ j[mapped] = json_object_new_boolean (mapped_p);
+ GOTO_ERR_IF (j[mapped] == NULL, error, errmsg,
+ "json_object_new_boolean () failed");
+
+ j[strict] = json_object_new_boolean (pk_val_strict_p (val));
+ GOTO_ERR_IF (j[strict] == NULL, error, errmsg,
+ "json_object_new_boolean () failed");
+
+ tmp = pk_val_ios (val);
+ if (tmp == PK_NULL)
+ j[ios] = NULL;
De-indent please.
+ else
+ {
+ j[ios] = json_object_new_int (pk_int_value (tmp));
+ GOTO_ERR_IF (j[ios] == NULL, error, errmsg,
+ "json_object_new_int () failed");
+ }
+
+ /* NOTE(kostas): pk_val_offset does not return PK_NULL even if mapped_p
+ is 0! Bug? */
+ if (!mapped_p)
+ j[offset] = NULL;
+ else
+ {
+ off_value = pk_val_offset (val);
+ off_type = pk_typeof (off_value);
+ GOTO_ON_JERR (jexpect_type_offset (off_type, &j[type], errmsg), error,
+ errmsg, "jexpect_type_offset () failed");
+ GOTO_ON_JERR (jexpect_offset (off_value, &j[value], errmsg), error,
+ errmsg, "jexpect offset () failed");
+
+ j[offset] = json_object_new_object ();
+ GOTO_ERR_IF (j[offset] == NULL, error, errmsg,
+ "json_object_new_object () failed");
+
+ GOTO_ERR_IF (json_object_object_add (j[offset], "type", j[type]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[offset], "value", j[value]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ }
+
+ GOTO_ERR_IF (json_object_object_add (j[mapping], "mapped", j[mapped]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[mapping], "strict", j[strict]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[mapping], "IOS", j[ios]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[mapping], "offset", j[offset]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+
+ *j_map = j[mapping];
+
+ return J_OK;
+
+error:
+ return jexpect_type_error (j, LEN);
+}
+
+static int
+jexpect_struct (pk_val pk_sct, json_object **j_sct, char **errmsg)
+{
+ enum
+ {
+ sct,
+ fields,
+ boffsets,
+ mapping
+ };
+ const int LEN = 4;
+ /* Store all JSON objects in an array to make resource management easier */
+ json_object *j[LEN];
+ pk_val nfields;
+
+ memset (j, 0, sizeof (j));
+
+ j[sct] = json_object_new_object ();
+ GOTO_ERR_IF (j[sct] == NULL, error, errmsg,
+ "json_object_new_object () failed");
+
+ j[fields] = json_object_new_array ();
+ GOTO_ERR_IF (j[fields] == NULL, error, errmsg,
+ "json_object_new_array () failed");
+
+ j[boffsets] = json_object_new_array ();
+ GOTO_ERR_IF (j[boffsets] == NULL, error, errmsg,
+ "json_object_new_array () failed");
+
+ nfields = pk_struct_nfields (pk_sct);
+ for (size_t i = 0 ; i < pk_uint_value (nfields) ; i++)
Please don't call `pk_uint_value` on every iteration.
+ {
+ json_object *j_field, *j_boffset;
+ pk_val fvalue, fname, fboffset;
+
+ fname = pk_struct_field_name (pk_sct, i);
+ fvalue = pk_struct_ref_field_value (pk_sct, pk_string_str (fname));
+ GOTO_ON_JERR (jvalue (fvalue, &j_field, errmsg), error, errmsg,
+ "failed to create JSON value");
+ GOTO_ERR_IF (json_object_array_add (j[fields], j_field) != 0, error,
+ errmsg, "json_object_array_add () failed");
+
+ fboffset = pk_struct_field_boffset (pk_sct, i);
+ j_boffset = json_object_new_int64 ((int64_t) pk_uint_value (fboffset));
+
+ GOTO_ERR_IF (json_object_array_add (j[boffsets], j_boffset) != 0, error,
+ errmsg, "json_object_array_add () failed");
+ }
+
+ GOTO_ON_JERR (jexpect_map (pk_sct, &j[mapping], errmsg), error, errmsg,
+ "failed to create JSON mapping");
+
+ GOTO_ERR_IF (json_object_object_add (j[sct], "fields", j[fields]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[sct], "boffsets", j[boffsets]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[sct], "mapping", j[mapping]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+
+ *j_sct = j[sct];
+
+ return J_OK;
+
+error:
+ return jexpect_type_error (j, LEN);
}
-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);
+static int
+jexpect_array (pk_val pk_arr, json_object **j_arr, char **errmsg)
+{
+ enum
+ {
+ arr,
+ elements,
+ boffsets,
+ mapping
+ };
+ const int LEN = 4;
+ /* Store all JSON objects in an array to make resource management easier */
+ json_object *j[LEN];
+ pk_val nelems;
+
+ memset (j, 0, sizeof (j));
+
+ j[arr] = json_object_new_object ();
+ GOTO_ERR_IF (j[arr] == NULL, error, errmsg,
+ "json_object_new_object () failed");
+
+ j[elements] = json_object_new_array ();
+ GOTO_ERR_IF (j[elements] == NULL, error, errmsg,
+ "json_object_new_array () failed");
-/* Expects a Poke value of type specified by TYPE_CODE in JSON object.
+ j[boffsets] = json_object_new_array ();
+ GOTO_ERR_IF (j[boffsets] == NULL, error, errmsg,
+ "json_object_new_array () failed");
+
+ nelems = pk_array_nelem (pk_arr);
+ for (size_t i = 0 ; i < pk_uint_value (nelems) ; i++)
+ {
+ json_object *j_elem, *j_boffset;
+ pk_val e_value, e_fboffset;
+
+ e_value = pk_array_elem_val (pk_arr, i);
+ GOTO_ON_JERR (jvalue (e_value, &j_elem, errmsg), error, errmsg,
+ "failed to create JSON object from Poke value");
+ GOTO_ERR_IF (json_object_array_add (j[elements], j_elem) != 0, error,
+ errmsg, "json_object_array_add () failed");
+
+ e_fboffset = pk_array_elem_boffset (pk_arr, i);
+ j_boffset = json_object_new_int64 ((int64_t) pk_uint_value (e_fboffset));
+ GOTO_ERR_IF (json_object_array_add (j[boffsets], j_boffset) != 0, error,
+ errmsg, "json_object_array_add () failed");
+ }
+
+ GOTO_ON_JERR (jexpect_map (pk_arr, &j[mapping], errmsg), error, errmsg,
+ "failed to create JSON mapping");
+
+ GOTO_ERR_IF (json_object_object_add (j[arr], "elements", j[elements]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[arr], "boffsets", j[boffsets]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+ GOTO_ERR_IF (json_object_object_add (j[arr], "mapping", j[mapping]) != 0,
+ error, errmsg, "json_object_object_add () failed");
+
+ *j_arr = j[arr];
+
+ return J_OK;
+
+error:
+ return jexpect_type_error (j, LEN);
+}
+
+/* Functions to convert JSON object to Poke value. */
+static int pvalue (json_object *obj, pk_val pk_type, pk_val *pk_value,
+ char **errmsg);
+static int ptype (json_object *j_type, pk_val *pk_type, char **errmsg);
+
+int
Mark this as `static`.
+pk_mi_json_to_val_1 (pk_val *value, json_object *j_obj, char **errmsg)
+{
+ json_object *j_poketype, *j_pokevalue;
+ pk_val type;
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_obj, "Type", &j_poketype),
+ errmsg, "expects \"Type\" field");
s/Type/type/
+ RETURN_ON_JERR (ptype (j_poketype, &type, errmsg), errmsg,
+ "invalid Type representation");
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_obj, "Value", &j_pokevalue),
+ errmsg, "expects \"Value\" field");
+ RETURN_ON_JERR (pvalue (j_pokevalue, type, value, errmsg), errmsg,
+ "invalid Value representation");
s/Value/value/
+
+ return J_OK;
+}
+
+int
+pk_mi_json_to_val (pk_val *value, const char *json_str, char **errmsg)
+{
+ json_object *j_obj = NULL;
+ json_tokener *tok = NULL;
+ enum json_tokener_error jerr;
+ int free_p;
+
+ /* 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 ();
+ GOTO_ERR_IF (tok == NULL, deinit, errmsg, "json_tokener_new () failed");
+
+ j_obj = json_tokener_parse_ex (tok, json_str, strlen (json_str) + 1);
+ jerr = json_tokener_get_error (tok);
+ GOTO_ERR_IF (j_obj == NULL, deinit, errmsg,
+ "json_tokener_parse_ex () failed: %s",
+ json_tokener_error_desc (jerr));
+ GOTO_ERR_IF (jerr != json_tokener_success, deinit, errmsg,
+ "json_tokener_parse_ex () failed %s",
+ json_tokener_error_desc (jerr));
+
+ return pk_mi_json_to_val_1 (value, j_obj, errmsg);
+
+ deinit:
De-indent.
+ if (j_obj)
+ {
+ free_p = json_object_put (j_obj);
+ assert (free_p == 1);
+ }
+ if (tok)
+ json_tokener_free (tok);
+ return J_NOK;
+}
+
+/* Expects field FIELD of type EXPECTED_TYPE 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
+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;
+}
+
+static int pexpect_type_integral (json_object *j_type_int, pk_val *pk_type_int,
+ char **errmsg);
+static int pexpect_type_offset (json_object *j_type_off, pk_val *pk_type_off,
+ char **errmsg);
+static int pexpect_type_struct (json_object *j_type_sct, pk_val *pk_type_sct,
+ char **errmsg);
+static int pexpect_type_array (json_object *j_type_arr, pk_val *pk_type_arr,
+ char **errmsg);
+
+/* Parses JSON object as a Poke type.
*
* Returns J_OK on success, J_NOK otherwise.
*/
static int
-pexpect (json_object *j, int type_code, pk_val *pval, char **errmsg)
+ptype (json_object *j_type, pk_val *pk_type, char **errmsg)
{
- json_object *j_tmp;
- const char *str;
+ const char *code;
+ json_object *j_code;
+
+#define STR(X) #X
+#define PEXPECT_TYPE(type) \
+ RETURN_ON_JERR (pexpect_type_##type (j_type, pk_type, errmsg), errmsg, \
+ "invalid " #type " type");
+
+ RETURN_ON_JERR (jexpect (j_type, "code", json_type_string, &j_code, errmsg),
+ errmsg, "expects \"code\" field in \"type\"");
+ RETURN_ERR_IF ((code = json_object_get_string (j_code)) == NULL, errmsg,
+ "invalid \"code\" field");
- switch (type_code)
+ if (STREQ (code, "Integral"))
{
- 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");
+ PEXPECT_TYPE (integral);
+ }
+ else if (STREQ (code, "String"))
+ {
+ *pk_type = pk_make_string_type ();
+ }
+ else if (STREQ (code, "Offset"))
+ {
+ PEXPECT_TYPE (offset);
+ }
+ else if (STREQ (code, "Struct"))
+ {
+ PEXPECT_TYPE (struct);
+ }
+ else if (STREQ (code, "Array"))
+ {
+ PEXPECT_TYPE (array);
+ }
+ else if (STREQ (code, "Closure"))
+ {
+ // NOTE(kostas-to-jemarch&mohammad): Such function does not exist in
libpoke.h
+ // *pk_type = pk_make_closure_type ();
This will be handled in future, when we add Reference type.
We can return `J_NOK` until then.
+ }
+ else if (STREQ (code, "Any"))
+ {
+ *pk_type = pk_make_any_type ();
+ }
+ else if (STREQ (code, "Void"))
+ {
+ // NOTE(kostas-to-jemarch&mohammad): What to do here?
+ // *pk_type = PK_NULL;
Void is simple. type: `{"code": "Void"}` and value: `null`.
That's it!
+ }
+ else
+ {
+ RETURN_ERR_IF (1, errmsg, "Code has an invalid value");
+ }
- return J_OK;
+ 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;
- }
+#undef STR
+#undef GET_INFO
+#undef PEXPECT_TYPE
+}
- 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;
- }
+/* Parses JSON object as a Poke integral type.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
- case PK_UINT:
- {
- uint64_t value;
- int size;
+static int
+pexpect_type_integral (json_object *j_type_int, pk_val *pk_type_int,
+ char **errmsg)
+{
+ pk_val size, signed_p;
+ int64_t val;
+ json_object *j_iinfo, *j_size, *j_signed_p;
- 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_type_int, "info", json_type_object, &j_iinfo,
+ errmsg), errmsg, "invalid integral type");
- RETURN_ON_JERR (jexpect (j, "value", json_type_int, &j_tmp, errmsg),
- errmsg, "invalid UnsignedInteger");
+ RETURN_ON_JERR (jexpect (j_iinfo, "size", json_type_int, &j_size, errmsg),
+ errmsg, "invalid \"info\"");
+ val = json_object_get_int64 (j_size);
+ RETURN_ERR_IF (val < 1 || val > 64, errmsg, "invalid size value %ld\n", val);
Please use `PRId64` instead of `%ld`.
- /* Older versions of libjson-c (0.3.1 & older) do not support
- json_object_get_uint64 (only json_object_get_int64).
+ /* SIZE is a uint<64> value. */
+ size = pk_make_uint ((uint64_t) val, 64);
- 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).
+ RETURN_ON_JERR (jexpect (j_iinfo, "signed_p", json_type_boolean, &j_signed_p,
+ errmsg), errmsg, "invalid \"info\"");
+ val = json_object_get_boolean (j_signed_p);
- However, users expect to get the unsigned integer they stored.
+ /* SIGNED_P is a int<32> value. */
+ signed_p = pk_make_int (val, 32);
- Thus, we have to convert it back to uint64_t. */
- value = (uint64_t)json_object_get_int64 (j_tmp);
+ *pk_type_int = pk_make_integral_type (size, signed_p);
- RETURN_ON_JERR (jexpect (j, "size", json_type_int, &j_tmp, errmsg),
- errmsg, "invalid UnsignedInteger");
- size = json_object_get_int (j_tmp);
+ return J_OK;
+}
- RETURN_ERR_IF ((*pval = pk_make_uint (value, size)) == PK_NULL, errmsg,
- "pk_make_uint () failed");
- return J_OK;
- }
+/* Parses JSON object as a Poke offset type.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_type_offset (json_object *j_type_off, pk_val *pk_type_off,
+ char **errmsg)
+{
+ pk_val base_type, unit;
+ int64_t val;
+ const char *code;
+ json_object *j_oinfo, *j_magnitude, *j_code, *j_unit;
- 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);
+ RETURN_ON_JERR (jexpect (j_type_off, "info", json_type_object, &j_oinfo,
+ errmsg), errmsg, "invalid offset type");
- 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);
+ RETURN_ON_JERR (jexpect (j_oinfo, "magnitude", json_type_object,
&j_magnitude,
+ errmsg), errmsg, "invalid \"info\"");
+ RETURN_ON_JERR (jexpect (j_magnitude, "code", json_type_string, &j_code,
+ errmsg),
+ errmsg, "expected \"code\" field in \"magnitude\"");
+
+ RETURN_ERR_IF ((code = json_object_get_string (j_code)) == NULL, errmsg,
+ "invalid \"code\" field");
+ RETURN_ERR_IF (STRNEQ (code, "Integral"), errmsg,
+ "\"magnitude\" in \"info\" should be of type integral");
+
+ RETURN_ON_JERR (pexpect_type_integral (j_magnitude, &base_type, errmsg),
+ errmsg, "invalid integral type");
+
+ RETURN_ON_JERR (jexpect (j_oinfo, "unit", json_type_int, &j_unit, errmsg),
+ errmsg, "invalid \"info\"");
+ val = json_object_get_int64 (j_unit);
+ RETURN_ERR_IF (val < 0, errmsg, "invalid value for unit %ld\n", val);
Ditto.
+ unit = pk_make_uint ((uint64_t) val, 64);
+
+ *pk_type_off = pk_make_offset_type (base_type, unit);
+
+ return J_OK;
+}
+
+/* Parses JSON object as a Poke struct type.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ *
+ */
+static int
+pexpect_type_struct (json_object *j_type_sct, pk_val *pk_type_sct,
+ char **errmsg)
+{
+ pk_val name, nfields, *fnames, *ftypes;
+ const char *name_str;
+ json_object *j_sinfo, *j_name, *j_fields;
+
+ RETURN_ON_JERR (jexpect (j_type_sct, "info", json_type_object, &j_sinfo,
+ errmsg), errmsg, "invalid struct type");
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_sinfo, "name", &j_name), errmsg,
+ "expects \"name\" in \"info\"");
+ switch (json_object_get_type (j_name))
+ {
+ case json_type_string:
+ name_str = json_object_get_string (j_name);
+ RETURN_ERR_IF (name_str == NULL, errmsg, "invalid \"name\" field");
+ name = pk_make_string (name_str);
+ break;
+ case json_type_null:
+ name = PK_NULL;
+ break;
+ default:
+ RETURN_ERR_IF (1, errmsg, "invalid \"info\"");
+ }
+
+ RETURN_ON_JERR (jexpect (j_sinfo, "fields", json_type_array, &j_fields,
+ errmsg), errmsg, "invalid \"info\"");
+ nfields = pk_make_uint (json_object_array_length (j_fields), 64);
+ pk_allocate_struct_attrs (nfields, &fnames, &ftypes);
+ *pk_type_sct = pk_make_struct_type (nfields, name, fnames, ftypes);
+ for (uint64_t i = 0 ; i < pk_uint_value (nfields) ; i++)
Please don't call `pk_uint_value` on each iteration.
+ {
+ json_object *j_field, *j_fname, *j_ftype;
+ pk_val fname, ftype;
+
+ j_field = json_object_array_get_idx (j_fields, i);
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_field, "name", &j_fname),
+ errmsg, "expects \"name\" in \"fields\"");
+ switch (json_object_get_type (j_fname))
+ {
+ case json_type_string:
+ name_str = json_object_get_string (j_fname);
+ RETURN_ERR_IF (name_str == NULL, errmsg, "invalid \"name\" field");
+ fname = pk_make_string (name_str);
+ break;
+ case json_type_null:
+ fname = PK_NULL;
+ break;
+ default:
+ RETURN_ERR_IF (1, errmsg, "invalid \"info\"");
+ }
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_field, "type", &j_ftype),
+ errmsg, "expects \"type\" in \"fields\"");
+ RETURN_ON_JERR (ptype (j_ftype, &ftype, errmsg), errmsg,
+ "failed to parse Poke type");
+
+ pk_struct_type_set_fname (*pk_type_sct, i, fname);
+ pk_struct_type_set_ftype (*pk_type_sct, i, ftype);
+ }
+
+ return J_OK;
+}
+
+/* Parses JSON object as a Poke array type.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ *
+ */
+static int
+pexpect_type_array (json_object *j_type_arr, pk_val *pk_type_arr,
+ char **errmsg)
+{
+ pk_val bound, etype;
+ int64_t val;
+ json_object *j_ainfo, *j_bound, *j_bound_val, *j_bound_size_p, *j_etype;
+
+ RETURN_ON_JERR (jexpect (j_type_arr, "info", json_type_object, &j_ainfo,
+ errmsg), errmsg, "invalid array type");
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_ainfo, "bound", &j_bound),
+ errmsg, "expects \"bound\" in \"type\"");
+ switch (json_object_get_type (j_bound))
+ {
+ case json_type_object:
+ RETURN_ON_JERR (jexpect (j_bound, "value", json_type_int, &j_bound_val,
+ errmsg),
+ errmsg, "expects \"value\" in \"bound\"");
+ RETURN_ON_JERR (jexpect (j_bound, "size_p", json_type_boolean,
+ &j_bound_size_p, errmsg),
+ errmsg, "expects \"size_p\" in \"bound\"");
+ if (json_object_get_boolean (j_bound_size_p))
+ {
+ /* size_p: "true" means that value is the magnitude of a
+ bit-offset. */
+ val = json_object_get_int64 (j_bound_val);
+ RETURN_ERR_IF (val < 0, errmsg, "invalid bound value %ld\n", val);
+ bound = pk_make_offset (pk_make_uint (val, 64),
+ pk_make_uint (1, 64));
+ RETURN_ERR_IF (bound == PK_NULL, errmsg,
+ "pk_make_offset () failed");
+ }
+ else
+ {
+ val = json_object_get_int64 (j_bound_val);
+ RETURN_ERR_IF (val < 0, errmsg, "invalid bound value %ld\n", val);
+ bound = pk_make_uint (val, 64);
+ }
+ break;
+ case json_type_null:
+ bound = PK_NULL;
+ break;
+ default:
+ RETURN_ERR_IF (1, errmsg, "invalid \"bound\" in \"info\"");
+ }
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_ainfo, "etype", &j_etype),
+ errmsg, "expected \"etype\" field in \"info\"");
+ RETURN_ON_JERR (ptype (j_etype, &etype, errmsg), errmsg,
+ "failed to parse Poke type");
+
+ *pk_type_arr = pk_make_array_type (etype, bound);
+
+ return J_OK;
+}
+
+static int pexpect_int (json_object *j_int, pk_val pk_int_type, pk_val *pk_int,
+ char **errmsg);
+static int pexpect_uint (json_object *j_uint, pk_val pk_uint_type,
+ pk_val *pk_uint, char **errmsg);
+static int pexpect_string (json_object *j_str, pk_val pk_str_type,
+ pk_val *pk_str, char **errmsg);
+static int pexpect_offset (json_object *j_off, pk_val pk_off_type,
+ pk_val *pk_off, char **errmsg);
+static int pexpect_struct (json_object *j_sct, pk_val pk_sct_type,
+ pk_val *pk_sct, char **errmsg);
+static int pexpect_array (json_object *j_arr, pk_val pk_arr_type,
+ pk_val *pk_arr, char **errmsg);
+
+/* Parses JSON object as a Poke value.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pvalue (json_object *obj, pk_val pk_type, pk_val *pk_value, char **errmsg)
+{
+ if (obj == NULL) {
+ *pk_value = PK_NULL;
+ return J_NOK;
+ }
To myself: GNU style please! :)
+
+#define PEXPECT(type) \
+ RETURN_ON_JERR(pexpect_##type (obj, pk_type, pk_value, errmsg), errmsg, \
+ "failed to parse Poke value (" #type ")")
+
+ switch (pk_type_code (pk_type))
+ {
+ case PK_INT:
+ PEXPECT (int);
+ return J_OK;
+ case PK_UINT:
+ PEXPECT (uint);
+ return J_OK;
+ case PK_STRING:
+ PEXPECT (string);
+ return J_OK;
+ case PK_OFFSET:
+ PEXPECT (offset);
+ return J_OK;
+ case PK_STRUCT:
+ PEXPECT (struct);
+ return J_OK;
+ case PK_ARRAY:
+ PEXPECT (array);
+ return J_OK;
case PK_ANY:
case PK_CLOSURE:
return jerror (J_NOK, errmsg, "unsupported Poke type (code:%d)",
- type_code);
-
+ pk_type_code (pk_type));
case PK_UNKNOWN:
default:
- return jerror (J_NOK, errmsg, "unknown Poke type (code:%d)", type_code);
+ return jerror (J_NOK, errmsg, "unknown Poke type (code:%d)",
+ pk_type_code (pk_type));
}
Why switch and macro, that loop was better :)
return J_NOK;
+
+#undef PEXPECT
}
+/* Expects a Poke int value in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
static int
-pexpect_map (json_object *j_map, pk_val p_val, char **errmsg)
+pexpect_int (json_object *j_int, pk_val pk_int_type, pk_val *pk_int,
+ char **errmsg)
{
- json_object *j_tmp;
- pk_val p_ios, p_off;
- int strict_p;
+ int64_t value;
+ int size;
-#define MAP_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Mapping")
+ /* libpoke says this number is uint<64>, which means we have to cast. */
+ size = (int) pk_uint_value (pk_integral_type_size (pk_int_type));
- 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;
+ RETURN_ON_JERR (json_object_is_type (j_int, json_type_int), errmsg,
+ "expects JSON item of type \"%s\" for field \"Value\"",
+ json_type_to_name (json_type_int));
Why `json_type_to_name (json_type_int)` instead of a simple `"int"`?!
https://github.com/json-c/json-c/blob/4fc44f32df9d59b3fbc1c09a29ca897318d3e610/json_util.c#L274
+ value = json_object_get_int64 (j_int);
- MAP_JERR (jexpect (j_map, "strict", json_type_boolean, &j_tmp, errmsg));
- strict_p = json_object_get_boolean (j_tmp);
+ /* pk_make_int () can't fail because size is already checked in ptype (). */
+ *pk_int = pk_make_int (value, size);
- 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");
+ return J_OK;
+}
- MAP_JERR (jexpect (j_map, "offset", json_type_object, &j_tmp, errmsg));
- MAP_JERR (pexpect (j_tmp, PK_OFFSET, &p_off, errmsg));
+/* Expects a Poke uint value in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_uint (json_object *j_uint, pk_val pk_uint_type, pk_val *pk_uint,
+ char **errmsg)
+{
+ uint64_t value;
+ int size;
- 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);
+ /* libpoke says this number is uint<64>, which means we have to cast. */
+ size = (int) pk_uint_value (pk_integral_type_size (pk_uint_type));
+
+ RETURN_ON_JERR (json_object_is_type (j_uint, json_type_int), errmsg,
+ "expects JSON item of type \"%s\" for field \"Value\"",
+ json_type_to_name (json_type_int));
+ /* 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_uint);
+
+ /* pk_make_uint () can't fail because size is already checked in ptype ().
*/
+ *pk_uint = pk_make_uint (value, size);
return J_OK;
}
-/* Expects a Poke struct value in JSON object.
+/* Expects a Poke string 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)
+pexpect_string (json_object *j_str, pk_val pk_str_type, pk_val *pk_str,
+ 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")
+ const char *str_value;
- 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));
+ /* Explicitly unused parameter. */
Unnecessary comment.
+ (void) pk_str_type;
+ RETURN_ON_JERR (json_object_is_type (j_str, json_type_string), errmsg,
+ "expects JSON item of type \"%s\" for field \"Value\"",
+ json_type_to_name (json_type_string));
Just use "string".
+ str_value = json_object_get_string (j_str);
+ RETURN_ERR_IF (str_value == NULL, errmsg, "invalid String value");
- fields_len = json_object_array_length (j_fields);
- p_nfields = pk_make_uint (fields_len, 64);
+ *pk_str = pk_make_string (str_value);
- SCT_JERR (pexpect (j_name, PK_STRING, &p_sct_name, errmsg));
+ return J_OK;
+}
- 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);
+/* Expects a Poke offset value in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_offset (json_object *j_off, pk_val pk_off_type, pk_val *pk_off,
+ char **errmsg)
+{
+ pk_val base_type, magnitude;
+ size_t size;
- for (size_t i = 0; i < fields_len; i++)
+ base_type = pk_offset_type_base_type (pk_off_type);
+ size = pk_uint_value (pk_integral_type_size (base_type));
+ switch (pk_type_code (base_type))
{
- json_object *j_elem, *j_name, *j_value, *j_boffset;
- pk_val p_sct_name, p_sct_value, p_sct_boffset;
+ case PK_INT:
+ magnitude = pk_make_int (json_object_get_int64 (j_off), size);
+ break;
+ case PK_UINT:
+ magnitude = pk_make_uint (json_object_get_int64 (j_off), size);
+ break;
+ default:
+ assert (0);
+ }
- j_elem = json_object_array_get_idx (j_fields, i);
+ *pk_off = pk_make_offset (magnitude, pk_offset_type_unit (pk_off_type));
+ RETURN_ERR_IF (*pk_off == PK_NULL, errmsg, "pk_make_offset () failed");
- 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));
+ return J_OK;
+}
- 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));
+/* Expects a Poke mapping value in JSON object.
+ *
+ * Returns J_OK on success, J_NOK otherwise.
+ */
+static int
+pexpect_map (json_object *j_map, pk_val p_val, char **errmsg)
+{
+ json_object *j_tmp, *j_ios, *j_off, *j_off_type, *j_off_val;
+ pk_val p_ios, p_off_type, p_off;
+ int strict_p, mapped_p;
- RETURN_ERR_IF (p_sct_value == PK_NULL, errmsg, "invalid Struct");
+#define MAP_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Mapping")
- 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);
+ MAP_JERR (jexpect (j_map, "mapped", json_type_boolean, &j_tmp, errmsg));
+ mapped_p = json_object_get_boolean (j_tmp);
+
+ MAP_JERR (jexpect (j_map, "strict", json_type_boolean, &j_tmp, errmsg));
+ strict_p = json_object_get_boolean (j_tmp);
+
+ RETURN_ON_JERR (json_object_object_get_ex (j_map, "IOS", &j_ios), errmsg,
+ "expects \"offset\" in \"mapping\"");
+ switch (json_object_get_type (j_ios))
+ {
+ case json_type_int:
+ p_ios = pk_make_int (json_object_get_int (j_ios), 32);
+ RETURN_ERR_IF (p_ios == PK_NULL, errmsg, "pk_make_int (, 32) failed");
+ break;
+ case json_type_null:
+ p_ios = PK_NULL;
+ break;
+ default:
+ RETURN_ERR_IF (1, errmsg, "invalid \"IOS\" in \"mapping\"");
}
- SCT_JERR (pexpect_map (j_mapping, p_sct, errmsg));
- *p_struct = p_sct;
+ RETURN_ON_JERR (json_object_object_get_ex (j_map, "offset", &j_off), errmsg,
+ "expects \"offset\" in \"mapping\"");
+ switch (json_object_get_type (j_off))
+ {
+ case json_type_object:
+ RETURN_ON_JERR (json_object_object_get_ex (j_off, "type", &j_off_type),
+ errmsg, "expects \"type\" in \"offset\"");
+ RETURN_ON_JERR (json_object_object_get_ex (j_off, "value", &j_off_val),
+ errmsg, "expects \"value\" in \"offset\"");
+ MAP_JERR (pexpect_type_offset (j_off_type, &p_off_type, errmsg));
+ MAP_JERR (pexpect_offset (j_off_val, p_off_type, &p_off, errmsg));
+ break;
+ case json_type_null:
+ p_off = PK_NULL;
+ break;
+ default:
+ RETURN_ERR_IF (1, errmsg, "invalid \"offset\" in \"mapping\"");
+ }
+
+ pk_val_set_mapped (p_val, mapped_p);
+ 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;
-#undef SCT_JERR
+#undef MAP_JERR
}
-/* Expects a Poke array elem in JSON object.
+/* Expects a Poke struct value 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)
+pexpect_struct (json_object *j_sct, pk_val pk_sct_type, pk_val *pk_sct,
+ char **errmsg)
{
- json_object *j_val, *j_boff;
+ pk_val pk_sct_tmp;
+ json_object *j_fields, *j_boffsets, *j_mapping;
+ size_t nfields;
-#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));
+#define SCT_JERR(cond) RETURN_ON_JERR ((cond), errmsg, "invalid Struct")
- AELEM_JERR (pvalue (j_val, p_elem_val, errmsg));
- AELEM_JERR (pexpect (j_boff, PK_UINT, p_elem_boff, errmsg));
+ SCT_JERR (jexpect (j_sct, "fields", json_type_array, &j_fields, errmsg));
+ nfields = json_object_array_length (j_fields);
+ RETURN_ERR_IF (nfields !=
+ pk_uint_value (pk_struct_type_nfields (pk_sct_type)), errmsg,
+ "invalid Struct (fields array length mismatch with type)");
+
+ SCT_JERR (jexpect (j_sct, "boffsets", json_type_array, &j_boffsets, errmsg));
+ RETURN_ERR_IF (json_object_array_length (j_boffsets) != nfields, errmsg,
+ "invalid Struct (boffsets array length mismatch with type");
+
+ pk_sct_tmp = pk_make_struct (pk_struct_type_nfields (pk_sct_type),
+ pk_sct_type);
+ for (size_t i = 0 ; i < nfields ; i++)
+ {
+ pk_val field, boffset;
+ json_object *j_field, *j_boffset;
+ int64_t boffset_val;
+
+ j_field = json_object_array_get_idx (j_fields, i);
+ SCT_JERR (pvalue (j_field, pk_struct_type_ftype (pk_sct_type, i), &field,
+ errmsg));
+
+ j_boffset = json_object_array_get_idx (j_boffsets, i);
+ RETURN_ON_JERR (json_object_is_type (j_boffset, json_type_int), errmsg,
+ "expects JSON item of type \"%s\" in \"boffsets\"",
+ json_type_to_name (json_type_int));
+ boffset_val = json_object_get_int64 (j_boffset);
+ RETURN_ERR_IF (boffset_val < 0, errmsg,
+ "boffset should be positive value");
+ boffset = pk_make_uint ((uint64_t) boffset_val, 64);
+
+ pk_struct_set_field_name (pk_sct_tmp, i,
+ pk_struct_type_fname (pk_sct_type, i));
+ pk_struct_set_field_value (pk_sct_tmp, i, field);
+ pk_struct_set_field_boffset (pk_sct_tmp, i, boffset);
+ }
- RETURN_ERR_IF (pk_integral_type_size (pk_typeof (*p_elem_boff)) == 64,
- errmsg, "boffset should be an uint<64>");
+ SCT_JERR (jexpect (j_sct, "mapping", json_type_object, &j_mapping, errmsg));
+ SCT_JERR (pexpect_map (j_mapping, pk_sct_tmp, errmsg));
+ *pk_sct = pk_sct_tmp;
return J_OK;
-#undef AELEM_JER
+#undef SCT_JERR
}
-/* Expects a Poke array in JSON object.
+/* Expects a Poke array value 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)
+pexpect_array (json_object *j_arr, pk_val pk_arr_type, pk_val *pk_arr,
+ 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;
+ pk_val pk_arr_tmp, pk_arr_bound;
+ json_object *j_elems, *j_boffsets, *j_mapping;
+ size_t nelems;
+ int64_t pk_arr_bound_value;
What's the purpose of `pk_arr_bound_value`?
I don't understand!
This function seems a little too complicated :)
#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));
+ nelems = json_object_array_length (j_elems);
+ pk_arr_bound = pk_array_type_bound (pk_arr_type);
+
+ ARR_JERR (jexpect (j_arr, "boffsets", json_type_array, &j_boffsets, errmsg));
+ RETURN_ERR_IF (json_object_array_length (j_boffsets) != nelems, errmsg,
+ "invalid Struct: boffsets array length mismatch with type");
- elems_len = json_object_array_length (j_elems);
+ if (pk_arr_bound != PK_NULL)
+ pk_arr_tmp = pk_make_array (pk_arr_bound, pk_arr_type);
`pk_make_array` expect first argument to be hint of #elems.
It's undefined for offset values.
Use the JSON to find the number of elements.
+ else
+ pk_arr_tmp = pk_make_array (pk_make_uint (0, 64), pk_arr_type);
- /* FIXME no empty array */
- if (elems_len == 0)
+ for (size_t i = 0 ; i < nelems ; i++)
{
- *p_array = PK_NULL;
- return J_OK;
- }
+ pk_val elem, boffset;
+ json_object *j_elem, *j_boffset;
+ int64_t boffset_val;
- /* assert (elems_len != 0); */
+ j_elem = json_object_array_get_idx (j_elems, i);
+ ARR_JERR (pvalue (j_elem, pk_array_type_etype (pk_arr_type), &elem,
+ errmsg));
+ pk_array_insert_elem (pk_arr_tmp, i, elem);
+
+ j_boffset = json_object_array_get_idx (j_boffsets, i);
+ RETURN_ON_JERR (json_object_is_type (j_boffset, json_type_int), errmsg,
+ "expects JSON item of type \"%s\" in \"boffsets\"",
+ json_type_to_name (json_type_int));
+ boffset_val = json_object_get_int64 (j_boffset);
+ RETURN_ERR_IF (boffset_val < 0, errmsg,
+ "boffset should be positive value");
+ boffset = pk_make_uint ((uint64_t) boffset_val, 64);
- /* Type of the array will be the type of first element */
- j_elem = json_object_array_get_idx (j_elems, 0);
+ RETURN_ERR_IF (
+ !pk_val_equal_p (pk_array_elem_boffset (pk_arr_tmp, i), boffset),
+ errmsg, "invalid Array: boffset mismatch at index %zu", i);
+ }
- /* FIXME no support for null items */
- assert (j_elem != NULL);
+ if (pk_arr_bound != PK_NULL)
+ {
+ /* Double check the size of the generated array and the bound. */
+ switch (pk_type_code (pk_typeof (pk_arr_bound)))
+ {
+ case PK_UINT:
+ pk_arr_bound_value = pk_uint_value (pk_arr_bound);
+ break;
+ case PK_OFFSET:
+ {
+ pk_val b_off_mag = pk_offset_magnitude (pk_arr_bound);
+
+ switch (pk_type_code (pk_typeof (b_off_mag)))
+ {
+ case PK_INT:
+ pk_arr_bound_value = pk_int_value (b_off_mag);
+ assert (pk_arr_bound_value > 0);
+ break;
+ case PK_UINT:
+ pk_arr_bound_value = pk_uint_value (b_off_mag);
+ break;
+ default:
+ assert (0);
+ }
+ /* NOTE(kostas): We need to discuss about this because
+ it is possible that some array elements won't be of the same
size!
+ */
+ if (nelems != 0)
+ pk_arr_bound_value /= pk_sizeof (pk_array_elem_val (pk_arr_tmp,
+ 0));
I don't know the reason, but this clearly is not a good idea :)
+ break;
+ }
+ default:
+ assert (0);
+ }
- 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);
+ RETURN_ERR_IF (nelems != (uint64_t) pk_arr_bound_value, errmsg,
+ "invalid Array: elements array length mismatch with type");
+ }
- 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");
+ ARR_JERR (jexpect (j_arr, "mapping", json_type_object, &j_mapping, errmsg));
- 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);
- }
+ ARR_JERR (pexpect_map (j_mapping, pk_arr_tmp, errmsg));
+ *pk_arr = pk_arr_tmp;
- ARR_JERR (pexpect_map (j_mapping, p_arr, errmsg));
- *p_array = p_arr;
return J_OK;
#undef ARR_JERR
@@ -1088,7 +1810,7 @@ collect_json_arg (const char *name, pk_val value /* Note
unused */,
if (!json_object_object_get_ex (args, name, &obj))
return 0;
- if (pvalue (obj, &val, NULL /* errmsg */) != J_OK)
+ if (pk_mi_json_to_val_1 (&val, obj, NULL) != J_OK)
return 0;
pk_mi_set_arg (msg, name, val);
Regards,
Mohammad-Reza