Commit 506d3843 authored by João Távora's avatar João Távora

Instead of a json-serialize-use-plists global, use function args

* src/json.c (syms_of_json): Don't defive
json-serialize-use-plists
(Fjson_insert, lisp_to_json, list_to_json_toplevel_1)
(list_to_json_toplevel, Fjson_serialize): Use and pass around
use_plists arg.

* doc/lispref/text.texi:
(Parsing JSON): json-serialize and json-insert now have a
USE-PLISTS arg.

* test/src/json-tests.el (json-serialize/object): Use
json-serialize's USE-PLISTS arg.
parent 224f8ea9
Pipeline #36 failed with stage
......@@ -5067,22 +5067,19 @@ either @code{hash-table} to parse JSON objects as hashtables with
string keys (the default), @code{alist} to parse them as alists or
@code{plist} to parse them as plists.
@vindex json-serialize-use-plists
@cindex serializing plists as json
For the serialization function, the variable
@var{json-serialize-use-plists} controls the converse process,
resolving the ambiguity when a list is found in the Lisp object to
serialize. If @code{nil}, its default, the list is interpreted as an
alist, otherwise it is interpreted as a plist.
@defun json-serialize object
This function returns a new Lisp string which contains the JSON
representation of @var{object}.
representation of @var{object}. The optional argument @var{use-plists}
resolves the ambiguity when a list is found in the Lisp object to
serialize: if it is @code{nil}, its default, the list is interpreted
as an alist, otherwise it is interpreted as a plist.
@end defun
@defun json-insert object
This function inserts the JSON representation of @var{object} into the
current buffer before point.
current buffer before point. The optional argument @var{use-plists} is
interpreted as in @dfn{json-serialize}.
@end defun
@defun json-parse-string string &key (object-type @code{hash-table})
......
......@@ -325,14 +325,14 @@ json_check_utf8 (Lisp_Object string)
CHECK_TYPE (utf8_string_p (string), Qutf_8_string_p, string);
}
static json_t *lisp_to_json (Lisp_Object);
static json_t *lisp_to_json (Lisp_Object, Lisp_Object);
/* Convert a Lisp object to a toplevel JSON object (array or object).
This returns Lisp_Object so we can use unbind_to. The return value
is always nil. */
static _GL_ARG_NONNULL ((2)) Lisp_Object
lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
lisp_to_json_toplevel_1 (Lisp_Object lisp, Lisp_Object use_plists, json_t **json)
{
if (VECTORP (lisp))
{
......@@ -343,7 +343,8 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
for (ptrdiff_t i = 0; i < size; ++i)
{
int status
= json_array_append_new (*json, lisp_to_json (AREF (lisp, i)));
= json_array_append_new (*json, lisp_to_json (AREF (lisp, i),
use_plists));
if (status == -1)
json_out_of_memory ();
}
......@@ -370,7 +371,8 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
if (json_object_get (*json, key_str) != NULL)
wrong_type_argument (Qjson_value_p, lisp);
int status = json_object_set_new (*json, key_str,
lisp_to_json (HASH_VALUE (h, i)));
lisp_to_json (HASH_VALUE (h, i),
use_plists));
if (status == -1)
{
/* A failure can be caused either by an invalid key or
......@@ -398,7 +400,7 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
const char *key_str;
Lisp_Object value;
Lisp_Object key_symbol;
if ( EQ (Vjson_serialize_use_plists, Qt) ) {
if ( EQ (use_plists, Qt) ) {
key_symbol = XCAR (tail);
tail = XCDR(tail);
CHECK_CONS (tail);
......@@ -417,14 +419,15 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
check_string_without_embedded_nulls (key);
key_str = SSDATA (key);
/* If using plists, maybe strip the ":" from symbol-name */
if (EQ (Vjson_serialize_use_plists, Qt) &&
if (EQ (use_plists, Qt) &&
':' == 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)
{
int status
= json_object_set_new (*json, key_str, lisp_to_json (value));
= json_object_set_new (*json, key_str,
lisp_to_json (value, use_plists));
if (status == -1)
json_out_of_memory ();
}
......@@ -441,12 +444,12 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
hashtable, or alist. */
static json_t *
lisp_to_json_toplevel (Lisp_Object lisp)
lisp_to_json_toplevel (Lisp_Object lisp, Lisp_Object use_plists)
{
if (++lisp_eval_depth > max_lisp_eval_depth)
xsignal0 (Qjson_object_too_deep);
json_t *json;
lisp_to_json_toplevel_1 (lisp, &json);
lisp_to_json_toplevel_1 (lisp, use_plists, &json);
--lisp_eval_depth;
return json;
}
......@@ -456,7 +459,7 @@ lisp_to_json_toplevel (Lisp_Object lisp)
JSON object. */
static json_t *
lisp_to_json (Lisp_Object lisp)
lisp_to_json (Lisp_Object lisp, Lisp_Object use_plists)
{
if (EQ (lisp, QCnull))
return json_check (json_null ());
......@@ -486,24 +489,26 @@ lisp_to_json (Lisp_Object lisp)
}
/* LISP now must be a vector, hashtable, or alist. */
return lisp_to_json_toplevel (lisp);
return lisp_to_json_toplevel (lisp, use_plists);
}
DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL,
DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 2, NULL,
doc: /* Return the JSON representation of OBJECT as a string.
OBJECT must be a vector of values or a key-value map. Hashtables,
alists and plists are accepted as maps, the variable
`json-serialize-use-plists' controlling which one of the latter two to
use. In any of these cases, values can be `:null', `:false', t,
numbers, strings, or, recursively, 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, and hashtables, alists and plists to JSON objects.
Hashtable keys must be strings without embedded null characters and
must be unique within each object. Alist or plist keys must be
symbols; if a key is duplicate, the first instance is used. */)
(Lisp_Object object)
alists and plists are accepted as maps. Since the latter two are both
lists and this function can't currently guess the format from the
variable, the optional argument USE-PLISTS is used to control which of
the two to use. In any of these cases, values can be `:null',
`:false', t, numbers, strings, or, recursively, 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, and hashtables, alists and plists to
JSON objects. Hashtable keys must be strings without embedded null
characters and must be unique within each object. Alist or plist keys
must be symbols; if a key is duplicate, the first instance is
used. */)
(Lisp_Object object, Lisp_Object use_plists)
{
ptrdiff_t count = SPECPDL_INDEX ();
......@@ -522,7 +527,7 @@ symbols; if a key is duplicate, the first instance is used. */)
}
#endif
json_t *json = lisp_to_json_toplevel (object);
json_t *json = lisp_to_json_toplevel (object, use_plists);
record_unwind_protect_ptr (json_release_object, json);
/* If desired, we might want to add the following flags:
......@@ -578,12 +583,12 @@ json_insert_callback (const char *buffer, size_t size, void *data)
return NILP (d->error) ? 0 : -1;
}
DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, 1, NULL,
DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, 2, NULL,
doc: /* Insert the JSON representation of OBJECT before point.
This is the same as (insert (json-serialize OBJECT)), but potentially
faster. See the function `json-serialize' for allowed values of
OBJECT. */)
(Lisp_Object object)
OBJECT and the meaning of USE-PLISTS */)
(Lisp_Object object, Lisp_Object use_plists)
{
ptrdiff_t count = SPECPDL_INDEX ();
......@@ -602,7 +607,7 @@ OBJECT. */)
}
#endif
json_t *json = lisp_to_json (object);
json_t *json = lisp_to_json (object, use_plists);
record_unwind_protect_ptr (json_release_object, json);
struct json_insert_data data;
......@@ -950,11 +955,6 @@ syms_of_json (void)
DEFSYM (Qpure, "pure");
DEFSYM (Qside_effect_free, "side-effect-free");
DEFVAR_LISP ("json-serialize-use-plists", Vjson_serialize_use_plists,
doc:
/* If non-nil use plists instead of alists in json-serialize.*/);
Vjson_serialize_use_plists = Qnil;
DEFSYM (Qjson_serialize, "json-serialize");
DEFSYM (Qjson_parse_string, "json-parse-string");
Fput (Qjson_serialize, Qpure, Qt);
......
......@@ -71,17 +71,16 @@
(should-error (json-serialize '#1=((a . 1) . #1#)) :type 'circular-list)
(should-error (json-serialize '(#1=(a #1#))))
(let ((json-serialize-use-plists t))
(should (equal (json-serialize '(:abc [1 2 t] :def :null))
"{\"abc\":[1,2,true],\"def\":null}"))
(should (equal (json-serialize '(abc [1 2 t] :def :null))
"{\"abc\":[1,2,true],\"def\":null}"))
(should-error (json-serialize '#1=(:a 1 . #1#)) :type 'circular-list)
(should-error (json-serialize '((abc . 1))) :type 'wrong-type-argument)
(should-error (json-serialize '(:foo bar (abc . 1)))
:type 'wrong-type-argument)
(should-error (json-serialize '(:foo bar :odd-numbered))
:type 'wrong-type-argument)))
(should (equal (json-serialize '(:abc [1 2 t] :def :null) t)
"{\"abc\":[1,2,true],\"def\":null}"))
(should (equal (json-serialize '(abc [1 2 t] :def :null) t)
"{\"abc\":[1,2,true],\"def\":null}"))
(should-error (json-serialize '#1=(:a 1 . #1#) t) :type 'circular-list)
(should-error (json-serialize '((abc . 1)) t) :type 'wrong-type-argument)
(should-error (json-serialize '(:foo bar (abc . 1)) t)
:type 'wrong-type-argument)
(should-error (json-serialize '(:foo bar :odd-numbered) t)
:type 'wrong-type-argument))
(ert-deftest json-serialize/object-with-duplicate-keys ()
(skip-unless (fboundp 'json-serialize))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment