aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Távora2018-05-30 02:48:31 +0100
committerJoão Távora2018-05-30 02:53:19 +0100
commit506d38434b54a3999163a78c91fb06a524a5cad2 (patch)
treedfd7846f020cc41c5863b2af567856107b90cc9d
parent224f8ea95f00cc60ee77aeaad6585bb2ef845f70 (diff)
downloademacs-scratch/support-plists-in-jsonc.tar.gz
emacs-scratch/support-plists-in-jsonc.zip
Instead of a json-serialize-use-plists global, use function argsscratch/support-plists-in-jsonc
* 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.
-rw-r--r--doc/lispref/text.texi15
-rw-r--r--src/json.c66
-rw-r--r--test/src/json-tests.el21
3 files changed, 49 insertions, 53 deletions
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 3995102237a..d2371d61811 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -5067,22 +5067,19 @@ either @code{hash-table} to parse JSON objects as hashtables with
5067string keys (the default), @code{alist} to parse them as alists or 5067string keys (the default), @code{alist} to parse them as alists or
5068@code{plist} to parse them as plists. 5068@code{plist} to parse them as plists.
5069 5069
5070@vindex json-serialize-use-plists
5071@cindex serializing plists as json 5070@cindex serializing plists as json
5072 For the serialization function, the variable
5073@var{json-serialize-use-plists} controls the converse process,
5074resolving the ambiguity when a list is found in the Lisp object to
5075serialize. If @code{nil}, its default, the list is interpreted as an
5076alist, otherwise it is interpreted as a plist.
5077
5078@defun json-serialize object 5071@defun json-serialize object
5079This function returns a new Lisp string which contains the JSON 5072This function returns a new Lisp string which contains the JSON
5080representation of @var{object}. 5073representation of @var{object}. The optional argument @var{use-plists}
5074resolves the ambiguity when a list is found in the Lisp object to
5075serialize: if it is @code{nil}, its default, the list is interpreted
5076as an alist, otherwise it is interpreted as a plist.
5081@end defun 5077@end defun
5082 5078
5083@defun json-insert object 5079@defun json-insert object
5084This function inserts the JSON representation of @var{object} into the 5080This function inserts the JSON representation of @var{object} into the
5085current buffer before point. 5081current buffer before point. The optional argument @var{use-plists} is
5082interpreted as in @dfn{json-serialize}.
5086@end defun 5083@end defun
5087 5084
5088@defun json-parse-string string &key (object-type @code{hash-table}) 5085@defun json-parse-string string &key (object-type @code{hash-table})
diff --git a/src/json.c b/src/json.c
index ccd58c047e5..8318b637e05 100644
--- a/src/json.c
+++ b/src/json.c
@@ -325,14 +325,14 @@ json_check_utf8 (Lisp_Object string)
325 CHECK_TYPE (utf8_string_p (string), Qutf_8_string_p, string); 325 CHECK_TYPE (utf8_string_p (string), Qutf_8_string_p, string);
326} 326}
327 327
328static json_t *lisp_to_json (Lisp_Object); 328static json_t *lisp_to_json (Lisp_Object, Lisp_Object);
329 329
330/* Convert a Lisp object to a toplevel JSON object (array or object). 330/* Convert a Lisp object to a toplevel JSON object (array or object).
331 This returns Lisp_Object so we can use unbind_to. The return value 331 This returns Lisp_Object so we can use unbind_to. The return value
332 is always nil. */ 332 is always nil. */
333 333
334static _GL_ARG_NONNULL ((2)) Lisp_Object 334static _GL_ARG_NONNULL ((2)) Lisp_Object
335lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) 335lisp_to_json_toplevel_1 (Lisp_Object lisp, Lisp_Object use_plists, json_t **json)
336{ 336{
337 if (VECTORP (lisp)) 337 if (VECTORP (lisp))
338 { 338 {
@@ -343,7 +343,8 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
343 for (ptrdiff_t i = 0; i < size; ++i) 343 for (ptrdiff_t i = 0; i < size; ++i)
344 { 344 {
345 int status 345 int status
346 = json_array_append_new (*json, lisp_to_json (AREF (lisp, i))); 346 = json_array_append_new (*json, lisp_to_json (AREF (lisp, i),
347 use_plists));
347 if (status == -1) 348 if (status == -1)
348 json_out_of_memory (); 349 json_out_of_memory ();
349 } 350 }
@@ -370,7 +371,8 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
370 if (json_object_get (*json, key_str) != NULL) 371 if (json_object_get (*json, key_str) != NULL)
371 wrong_type_argument (Qjson_value_p, lisp); 372 wrong_type_argument (Qjson_value_p, lisp);
372 int status = json_object_set_new (*json, key_str, 373 int status = json_object_set_new (*json, key_str,
373 lisp_to_json (HASH_VALUE (h, i))); 374 lisp_to_json (HASH_VALUE (h, i),
375 use_plists));
374 if (status == -1) 376 if (status == -1)
375 { 377 {
376 /* A failure can be caused either by an invalid key or 378 /* 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)
398 const char *key_str; 400 const char *key_str;
399 Lisp_Object value; 401 Lisp_Object value;
400 Lisp_Object key_symbol; 402 Lisp_Object key_symbol;
401 if ( EQ (Vjson_serialize_use_plists, Qt) ) { 403 if ( EQ (use_plists, Qt) ) {
402 key_symbol = XCAR (tail); 404 key_symbol = XCAR (tail);
403 tail = XCDR(tail); 405 tail = XCDR(tail);
404 CHECK_CONS (tail); 406 CHECK_CONS (tail);
@@ -417,14 +419,15 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
417 check_string_without_embedded_nulls (key); 419 check_string_without_embedded_nulls (key);
418 key_str = SSDATA (key); 420 key_str = SSDATA (key);
419 /* If using plists, maybe strip the ":" from symbol-name */ 421 /* If using plists, maybe strip the ":" from symbol-name */
420 if (EQ (Vjson_serialize_use_plists, Qt) && 422 if (EQ (use_plists, Qt) &&
421 ':' == key_str[0] && 423 ':' == key_str[0] &&
422 key_str[1] ) key_str = &key_str[1]; 424 key_str[1] ) key_str = &key_str[1];
423 /* Only add element if key is not already present. */ 425 /* Only add element if key is not already present. */
424 if (json_object_get (*json, key_str) == NULL) 426 if (json_object_get (*json, key_str) == NULL)
425 { 427 {
426 int status 428 int status
427 = json_object_set_new (*json, key_str, lisp_to_json (value)); 429 = json_object_set_new (*json, key_str,
430 lisp_to_json (value, use_plists));
428 if (status == -1) 431 if (status == -1)
429 json_out_of_memory (); 432 json_out_of_memory ();
430 } 433 }
@@ -441,12 +444,12 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
441 hashtable, or alist. */ 444 hashtable, or alist. */
442 445
443static json_t * 446static json_t *
444lisp_to_json_toplevel (Lisp_Object lisp) 447lisp_to_json_toplevel (Lisp_Object lisp, Lisp_Object use_plists)
445{ 448{
446 if (++lisp_eval_depth > max_lisp_eval_depth) 449 if (++lisp_eval_depth > max_lisp_eval_depth)
447 xsignal0 (Qjson_object_too_deep); 450 xsignal0 (Qjson_object_too_deep);
448 json_t *json; 451 json_t *json;
449 lisp_to_json_toplevel_1 (lisp, &json); 452 lisp_to_json_toplevel_1 (lisp, use_plists, &json);
450 --lisp_eval_depth; 453 --lisp_eval_depth;
451 return json; 454 return json;
452} 455}
@@ -456,7 +459,7 @@ lisp_to_json_toplevel (Lisp_Object lisp)
456 JSON object. */ 459 JSON object. */
457 460
458static json_t * 461static json_t *
459lisp_to_json (Lisp_Object lisp) 462lisp_to_json (Lisp_Object lisp, Lisp_Object use_plists)
460{ 463{
461 if (EQ (lisp, QCnull)) 464 if (EQ (lisp, QCnull))
462 return json_check (json_null ()); 465 return json_check (json_null ());
@@ -486,24 +489,26 @@ lisp_to_json (Lisp_Object lisp)
486 } 489 }
487 490
488 /* LISP now must be a vector, hashtable, or alist. */ 491 /* LISP now must be a vector, hashtable, or alist. */
489 return lisp_to_json_toplevel (lisp); 492 return lisp_to_json_toplevel (lisp, use_plists);
490} 493}
491 494
492DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL, 495DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 2, NULL,
493 doc: /* Return the JSON representation of OBJECT as a string. 496 doc: /* Return the JSON representation of OBJECT as a string.
494 497
495OBJECT must be a vector of values or a key-value map. Hashtables, 498OBJECT must be a vector of values or a key-value map. Hashtables,
496alists and plists are accepted as maps, the variable 499alists and plists are accepted as maps. Since the latter two are both
497`json-serialize-use-plists' controlling which one of the latter two to 500lists and this function can't currently guess the format from the
498use. In any of these cases, values can be `:null', `:false', t, 501variable, the optional argument USE-PLISTS is used to control which of
499numbers, strings, or, recursively, other vectors, hashtables, alists 502the two to use. In any of these cases, values can be `:null',
500or plists. `:null', `:false', and t will be converted to JSON null, 503`:false', t, numbers, strings, or, recursively, other vectors,
501false, and true values, respectively. Vectors will be converted to 504hashtables, alists or plists. `:null', `:false', and t will be
502JSON arrays, and hashtables, alists and plists to JSON objects. 505converted to JSON null, false, and true values, respectively. Vectors
503Hashtable keys must be strings without embedded null characters and 506will be converted to JSON arrays, and hashtables, alists and plists to
504must be unique within each object. Alist or plist keys must be 507JSON objects. Hashtable keys must be strings without embedded null
505symbols; if a key is duplicate, the first instance is used. */) 508characters and must be unique within each object. Alist or plist keys
506 (Lisp_Object object) 509must be symbols; if a key is duplicate, the first instance is
510used. */)
511 (Lisp_Object object, Lisp_Object use_plists)
507{ 512{
508 ptrdiff_t count = SPECPDL_INDEX (); 513 ptrdiff_t count = SPECPDL_INDEX ();
509 514
@@ -522,7 +527,7 @@ symbols; if a key is duplicate, the first instance is used. */)
522 } 527 }
523#endif 528#endif
524 529
525 json_t *json = lisp_to_json_toplevel (object); 530 json_t *json = lisp_to_json_toplevel (object, use_plists);
526 record_unwind_protect_ptr (json_release_object, json); 531 record_unwind_protect_ptr (json_release_object, json);
527 532
528 /* If desired, we might want to add the following flags: 533 /* 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)
578 return NILP (d->error) ? 0 : -1; 583 return NILP (d->error) ? 0 : -1;
579} 584}
580 585
581DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, 1, NULL, 586DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, 2, NULL,
582 doc: /* Insert the JSON representation of OBJECT before point. 587 doc: /* Insert the JSON representation of OBJECT before point.
583This is the same as (insert (json-serialize OBJECT)), but potentially 588This is the same as (insert (json-serialize OBJECT)), but potentially
584faster. See the function `json-serialize' for allowed values of 589faster. See the function `json-serialize' for allowed values of
585OBJECT. */) 590OBJECT and the meaning of USE-PLISTS */)
586 (Lisp_Object object) 591 (Lisp_Object object, Lisp_Object use_plists)
587{ 592{
588 ptrdiff_t count = SPECPDL_INDEX (); 593 ptrdiff_t count = SPECPDL_INDEX ();
589 594
@@ -602,7 +607,7 @@ OBJECT. */)
602 } 607 }
603#endif 608#endif
604 609
605 json_t *json = lisp_to_json (object); 610 json_t *json = lisp_to_json (object, use_plists);
606 record_unwind_protect_ptr (json_release_object, json); 611 record_unwind_protect_ptr (json_release_object, json);
607 612
608 struct json_insert_data data; 613 struct json_insert_data data;
@@ -950,11 +955,6 @@ syms_of_json (void)
950 DEFSYM (Qpure, "pure"); 955 DEFSYM (Qpure, "pure");
951 DEFSYM (Qside_effect_free, "side-effect-free"); 956 DEFSYM (Qside_effect_free, "side-effect-free");
952 957
953 DEFVAR_LISP ("json-serialize-use-plists", Vjson_serialize_use_plists,
954 doc:
955 /* If non-nil use plists instead of alists in json-serialize.*/);
956 Vjson_serialize_use_plists = Qnil;
957
958 DEFSYM (Qjson_serialize, "json-serialize"); 958 DEFSYM (Qjson_serialize, "json-serialize");
959 DEFSYM (Qjson_parse_string, "json-parse-string"); 959 DEFSYM (Qjson_parse_string, "json-parse-string");
960 Fput (Qjson_serialize, Qpure, Qt); 960 Fput (Qjson_serialize, Qpure, Qt);
diff --git a/test/src/json-tests.el b/test/src/json-tests.el
index 5c9be20e957..b7c17a4cf10 100644
--- a/test/src/json-tests.el
+++ b/test/src/json-tests.el
@@ -71,17 +71,16 @@
71 (should-error (json-serialize '#1=((a . 1) . #1#)) :type 'circular-list) 71 (should-error (json-serialize '#1=((a . 1) . #1#)) :type 'circular-list)
72 (should-error (json-serialize '(#1=(a #1#)))) 72 (should-error (json-serialize '(#1=(a #1#))))
73 73
74 (let ((json-serialize-use-plists t)) 74 (should (equal (json-serialize '(:abc [1 2 t] :def :null) t)
75 (should (equal (json-serialize '(:abc [1 2 t] :def :null)) 75 "{\"abc\":[1,2,true],\"def\":null}"))
76 "{\"abc\":[1,2,true],\"def\":null}")) 76 (should (equal (json-serialize '(abc [1 2 t] :def :null) t)
77 (should (equal (json-serialize '(abc [1 2 t] :def :null)) 77 "{\"abc\":[1,2,true],\"def\":null}"))
78 "{\"abc\":[1,2,true],\"def\":null}")) 78 (should-error (json-serialize '#1=(:a 1 . #1#) t) :type 'circular-list)
79 (should-error (json-serialize '#1=(:a 1 . #1#)) :type 'circular-list) 79 (should-error (json-serialize '((abc . 1)) t) :type 'wrong-type-argument)
80 (should-error (json-serialize '((abc . 1))) :type 'wrong-type-argument) 80 (should-error (json-serialize '(:foo bar (abc . 1)) t)
81 (should-error (json-serialize '(:foo bar (abc . 1))) 81 :type 'wrong-type-argument)
82 :type 'wrong-type-argument) 82 (should-error (json-serialize '(:foo bar :odd-numbered) t)
83 (should-error (json-serialize '(:foo bar :odd-numbered)) 83 :type 'wrong-type-argument))
84 :type 'wrong-type-argument)))
85 84
86(ert-deftest json-serialize/object-with-duplicate-keys () 85(ert-deftest json-serialize/object-with-duplicate-keys ()
87 (skip-unless (fboundp 'json-serialize)) 86 (skip-unless (fboundp 'json-serialize))