diff options
author | João Távora <joaotavora@gmail.com> | 2018-06-02 00:23:38 +0100 |
---|---|---|
committer | João Távora <joaotavora@gmail.com> | 2018-06-07 12:30:39 +0100 |
commit | 3509aaaefe1996ea46b038850629b6d2f7a726fe (patch) | |
tree | 651fec98d47d8c77863f6f0b08c9b3c9c6ac2362 /src/json.c | |
parent | 2e2f61efa66b69fbd12c83bbd5370a4be2374f66 (diff) | |
download | emacs-3509aaaefe1996ea46b038850629b6d2f7a726fe.tar.gz emacs-3509aaaefe1996ea46b038850629b6d2f7a726fe.tar.bz2 emacs-3509aaaefe1996ea46b038850629b6d2f7a726fe.zip |
Accept plists when serializing and parsing JSON
* doc/lispref/text.texi (Parsing JSON): Mention plist support.
* src/json.c (lisp_to_json_toplevel_1): Serialize plists to json.
(Fjson_serialize): Mention plists in docstring.
(enum json_object_type): Add json_object_plist.
(json_to_lisp): Parse JSON into plists.
(json_parse_object_type): Consider plists.
(Fjson_parse_string): Mention plists in docstring.
(syms_of_json): New Qplist sym_of_json.
(lisp_to_json): Update comment.
* test/src/json-tests.el (json-serialize/object)
(json-parse-string/object): New plist tests.
Diffstat (limited to 'src/json.c')
-rw-r--r-- | src/json.c | 97 |
1 files changed, 73 insertions, 24 deletions
diff --git a/src/json.c b/src/json.c index b046d34f667..afb81587a47 100644 --- a/src/json.c +++ b/src/json.c @@ -393,18 +393,39 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) *json = json_check (json_object ()); ptrdiff_t count = SPECPDL_INDEX (); record_unwind_protect_ptr (json_release_object, *json); + bool is_plist = !CONSP (XCAR (tail)); FOR_EACH_TAIL (tail) { - Lisp_Object pair = XCAR (tail); - CHECK_CONS (pair); - Lisp_Object key_symbol = XCAR (pair); - Lisp_Object value = XCDR (pair); + const char *key_str; + Lisp_Object value; + Lisp_Object key_symbol; + if (is_plist) + { + key_symbol = XCAR (tail); + tail = XCDR (tail); + CHECK_CONS (tail); + value = XCAR (tail); + if (EQ (tail, li.tortoise)) circular_list (lisp); + } + else + { + Lisp_Object pair = XCAR (tail); + CHECK_CONS (pair); + key_symbol = XCAR (pair); + value = XCDR (pair); + } CHECK_SYMBOL (key_symbol); Lisp_Object key = SYMBOL_NAME (key_symbol); /* We can't specify the length, so the string must be null-terminated. */ check_string_without_embedded_nulls (key); - const char *key_str = SSDATA (key); + key_str = SSDATA (key); + /* In plists, ensure leading ":" in keys is stripped. It + will be reconstructed later in `json_to_lisp'.*/ + if (is_plist && ':' == key_str[0] && key_str[1]) + { + key_str = &key_str[1]; + } /* Only add element if key is not already present. */ if (json_object_get (*json, key_str) == NULL) { @@ -423,7 +444,7 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) /* Convert LISP to a toplevel JSON object (array or object). Signal an error of type `wrong-type-argument' if LISP is not a vector, - hashtable, or alist. */ + hashtable, alist, or plist. */ static json_t * lisp_to_json_toplevel (Lisp_Object lisp) @@ -470,20 +491,21 @@ lisp_to_json (Lisp_Object lisp) return json; } - /* LISP now must be a vector, hashtable, or alist. */ + /* LISP now must be a vector, hashtable, alist, or plist. */ return lisp_to_json_toplevel (lisp); } DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL, doc: /* Return the JSON representation of OBJECT as a string. -OBJECT must be a vector, hashtable, or alist, and its elements can -recursively contain `:null', `:false', t, numbers, strings, or other -vectors hashtables, and alist. `:null', `:false', and t will be -converted to JSON null, false, and true values, respectively. Vectors -will be converted to JSON arrays, and hashtables and alists to JSON -objects. Hashtable keys must be strings without embedded null -characters and must be unique within each object. Alist keys must be -symbols; if a key is duplicate, the first instance is used. */) +OBJECT must be a vector, hashtable, alist, or plist and its elements +can recursively contain `:null', `:false', t, numbers, strings, or +other vectors hashtables, alists or plists. `:null', `:false', and t +will be converted to JSON null, false, and true values, respectively. +Vectors will be converted to JSON arrays, whereas hashtables, alists +and plists are converted to JSON objects. Hashtable keys must be +strings without embedded null characters and must be unique within +each object. Alist and plist keys must be symbols; if a key is +duplicate, the first instance is used. */) (Lisp_Object object) { ptrdiff_t count = SPECPDL_INDEX (); @@ -605,6 +627,7 @@ OBJECT. */) enum json_object_type { json_object_hashtable, json_object_alist, + json_object_plist }; /* Convert a JSON object to a Lisp object. */ @@ -692,6 +715,28 @@ json_to_lisp (json_t *json, enum json_object_type object_type) result = Fnreverse (result); break; } + case json_object_plist: + { + result = Qnil; + const char *key_str; + json_t *value; + json_object_foreach (json, key_str, value) + { + USE_SAFE_ALLOCA; + ptrdiff_t key_str_len = strlen (key_str); + char *keyword_key_str = SAFE_ALLOCA (1 + key_str_len + 1); + keyword_key_str[0] = ':'; + strcpy (&keyword_key_str[1], key_str); + Lisp_Object key = intern_1 (keyword_key_str, key_str_len + 1); + /* Build the plist as value-key since we're going to + reverse it in the end.*/ + result = Fcons (key, result); + result = Fcons (json_to_lisp (value, object_type), result); + SAFE_FREE (); + } + result = Fnreverse (result); + break; + } default: /* Can't get here. */ emacs_abort (); @@ -721,8 +766,10 @@ json_parse_object_type (ptrdiff_t nargs, Lisp_Object *args) return json_object_hashtable; else if (EQ (value, Qalist)) return json_object_alist; + else if (EQ (value, Qplist)) + return json_object_plist; else - wrong_choice (list2 (Qhash_table, Qalist), value); + wrong_choice (list3 (Qhash_table, Qalist, Qplist), value); } default: wrong_type_argument (Qplistp, Flist (nargs, args)); @@ -733,14 +780,15 @@ DEFUN ("json-parse-string", Fjson_parse_string, Sjson_parse_string, 1, MANY, NULL, doc: /* Parse the JSON STRING into a Lisp object. This is essentially the reverse operation of `json-serialize', which -see. The returned object will be a vector, hashtable, or alist. Its -elements will be `:null', `:false', t, numbers, strings, or further -vectors, hashtables, and alists. If there are duplicate keys in an -object, all but the last one are ignored. If STRING doesn't contain a -valid JSON object, an error of type `json-parse-error' is signaled. -The keyword argument `:object-type' specifies which Lisp type is used -to represent objects; it can be `hash-table' or `alist'. -usage: (json-parse-string STRING &key (OBJECT-TYPE \\='hash-table)) */) +see. The returned object will be a vector, hashtable, alist, or +plist. Its elements will be `:null', `:false', t, numbers, strings, +or further vectors, hashtables, alists, or plists. If there are +duplicate keys in an object, all but the last one are ignored. If +STRING doesn't contain a valid JSON object, an error of type +`json-parse-error' is signaled. The keyword argument `:object-type' +specifies which Lisp type is used to represent objects; it can be +`hash-table', `alist' or `plist'. +usage: (json-parse-string STRING &key (OBJECT-TYPE \\='hash-table)) */) (ptrdiff_t nargs, Lisp_Object *args) { ptrdiff_t count = SPECPDL_INDEX (); @@ -912,6 +960,7 @@ syms_of_json (void) DEFSYM (QCobject_type, ":object-type"); DEFSYM (Qalist, "alist"); + DEFSYM (Qplist, "plist"); defsubr (&Sjson_serialize); defsubr (&Sjson_insert); |