diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-10-11 20:47:27 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-10-11 20:47:27 -0700 |
commit | aa02bc7f31edabb9e09f9756d7ae8fbc41995017 (patch) | |
tree | 60bd97475501b9c8484f3804a5ac5d409113d373 | |
parent | 5df51b54116d4287df161c42ca0edb16fb1f79a5 (diff) | |
download | txr-aa02bc7f31edabb9e09f9756d7ae8fbc41995017.tar.gz txr-aa02bc7f31edabb9e09f9756d7ae8fbc41995017.tar.bz2 txr-aa02bc7f31edabb9e09f9756d7ae8fbc41995017.zip |
json: support standard-style formatting.
* stream.c (standard_k, print_json_format_s):
New symbol variables.
(stream_init): New variables initialized.
* stream.h (enum json_fmt): New enum.
(standard_k, print_json_format_s): Declared.
* lib.c (out_json_rec): Take enum json_fmt param,
and pass it recursively. Printing for vector and
dictionaries reacts to argument value.
(out_json, put_json): Examine value of special
var *print-json-format* and calculate enum json_fmt
value from this. Pass to out_json_rec.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
-rw-r--r-- | lib.c | 127 | ||||
-rw-r--r-- | stdlib/doc-syms.tl | 1 | ||||
-rw-r--r-- | stream.c | 4 | ||||
-rw-r--r-- | stream.h | 8 | ||||
-rw-r--r-- | txr.1 | 23 |
5 files changed, 127 insertions, 36 deletions
@@ -13799,7 +13799,8 @@ static int check_emit_circle(val obj, val out, struct strm_ctx *ctx, val self) return 0; } -static void out_json_rec(val obj, val out, struct strm_ctx *ctx) +static void out_json_rec(val obj, val out, enum json_fmt jf, + struct strm_ctx *ctx) { val self = lit("print"); @@ -13827,55 +13828,78 @@ static void out_json_rec(val obj, val out, struct strm_ctx *ctx) val save_indent; int force_br = 0; val iter, next; - put_char(chr('{'), out); - save_indent = inc_indent(out, zero); + + if (jf == json_fmt_standard) { + put_string(lit("{\n"), out); + save_indent = inc_indent_abs(out, two); + } else { + put_char(chr('{'), out); + save_indent = inc_indent(out, zero); + } + for (iter = cddr(obj), next = nil; iter; iter = next) { val pair = car(iter); val k = car(pair), v = cadr(pair); - if (consp(k) || consp(v)) { - if (next) + if (jf == json_fmt_standard || consp(k) || consp(v)) { + if (jf != json_fmt_standard && next) put_char(chr(' '), out); - out_json_rec(k, out, ctx); + out_json_rec(k, out, jf, ctx); put_string(lit(" : "), out); } else { - out_json_rec(k, out, ctx); + out_json_rec(k, out, jf, ctx); put_char(chr(':'), out); } - out_json_rec(v, out, ctx); - if ((next = cdr(iter)) != 0) { + out_json_rec(v, out, jf, ctx); + + if (jf == json_fmt_standard) { + if ((next = cdr(iter)) != 0) + put_string(lit(",\n"), out); + else + put_char(chr('\n'), out); + } else if ((next = cdr(iter)) != 0) { put_char(chr(','), out); if (width_check(out, nil)) force_br = 1; } } + set_indent(out, save_indent); put_char(chr('}'), out); if (force_br) force_break(out); - if (save_indent) - set_indent(out, save_indent); return; } if (sym == vector_lit_s) { val save_indent; int force_br = 0; val iter, next; - put_char(chr('['), out); - save_indent = inc_indent(out, zero); + + if (jf == json_fmt_standard) { + put_string(lit("[\n"), out); + save_indent = inc_indent_abs(out, two); + } else { + put_char(chr('['), out); + save_indent = inc_indent(out, zero); + } + for (iter = cadr(obj), next = nil; iter; iter = next) { val elem = car(iter); next = cdr(iter); - out_json_rec(elem, out, ctx); - if (next) { + out_json_rec(elem, out, jf, ctx); + if (jf == json_fmt_standard) { + if (next) + put_string(lit(",\n"), out); + else + put_char(chr('\n'), out); + } else if (next) { put_char(chr(','), out); if (width_check(out, nil)) force_br = 1; } } + set_indent(out, save_indent); put_char(chr(']'), out); if (force_br) force_break(out); - if (save_indent) - set_indent(out, save_indent); return; } if (sym == sys_unquote_s) { @@ -13897,22 +13921,32 @@ static void out_json_rec(val obj, val out, struct strm_ctx *ctx) cnum len = c_num(length(obj), self); cnum i; - put_char(chr('['), out); - save_indent = inc_indent(out, zero); + if (jf == json_fmt_standard) { + put_string(lit("[\n"), out); + save_indent = inc_indent_abs(out, two); + } else { + put_char(chr('['), out); + save_indent = inc_indent(out, zero); + } + for (i = 0; i < len; i++) { val elem = obj->v.vec[i]; - out_json_rec(elem, out, ctx); - if (i < len - 1) { + out_json_rec(elem, out, jf, ctx); + if (jf == json_fmt_standard) { + if (i < len - 1) + put_string(lit(",\n"), out); + else + put_char(chr('\n'), out); + } else if (i < len - 1) { put_char(chr(','), out); if (width_check(out, nil)) force_br = 1; } } + set_indent(out, save_indent); put_char(chr(']'), out); if (force_br) force_break(out); - if (save_indent) - set_indent(out, save_indent); return; } break; @@ -13925,31 +13959,44 @@ static void out_json_rec(val obj, val out, struct strm_ctx *ctx) us_hash_iter_init(&hi, obj); - put_char(chr('{'), out); - save_indent = inc_indent(out, zero); + if (jf == json_fmt_standard) { + put_string(lit("{\n"), out); + save_indent = inc_indent_abs(out, two); + } else { + put_char(chr('{'), out); + save_indent = inc_indent(out, zero); + } + for (next = nil, cell = hash_iter_next(&hi); cell; cell = next) { val k = car(cell), v = cdr(cell); - if (consp(k) || consp(v)) { - if (next) + + if (jf == json_fmt_standard || consp(k) || consp(v)) { + if (jf != json_fmt_standard && next) put_char(chr(' '), out); - out_json_rec(k, out, ctx); + out_json_rec(k, out, jf, ctx); put_string(lit(" : "), out); } else { - out_json_rec(k, out, ctx); + out_json_rec(k, out, jf, ctx); put_char(chr(':'), out); } - out_json_rec(v, out, ctx); - if ((next = hash_iter_next(&hi)) != 0) { + out_json_rec(v, out, jf, ctx); + if (jf == json_fmt_standard) { + if ((next = hash_iter_next(&hi)) != 0) + put_string(lit(",\n"), out); + else + put_char(chr('\n'), out); + } else if ((next = hash_iter_next(&hi)) != 0) { put_char(chr(','), out); - if (width_check(out, nil)) + if (jf == json_fmt_standard) + put_char(chr('\n'), out); + else if (width_check(out, nil)) force_br = 1; } } + set_indent(out, save_indent); put_char(chr('}'), out); if (force_br) force_break(out); - if (save_indent) - set_indent(out, save_indent); return; } break; @@ -13973,9 +14020,13 @@ static void out_json(val op, val obj, val out, struct strm_ctx *ctx) { val save_mode = test_set_indent_mode(out, num_fast(indent_off), num_fast(indent_data)); + val jfsym = cdr(lookup_var(nil, print_json_format_s)); + enum json_fmt jf = if3(jfsym == standard_k, + json_fmt_standard, + json_fmt_default); if (op == sys_qquote_s) put_char(chr('^'), out); - out_json_rec(obj, out, ctx); + out_json_rec(obj, out, jf, ctx); set_indent_mode(out, save_mode); } @@ -14659,8 +14710,12 @@ val put_json(val obj, val stream_in, val flat) test_set_indent_mode(stream, num_fast(indent_off), num_fast(indent_data))); val isave = get_indent(stream); + val jfsym = cdr(lookup_var(nil, print_json_format_s)); + enum json_fmt jf = if3(jfsym == standard_k, + json_fmt_standard, + json_fmt_default); uw_simple_catch_begin; - out_json_rec(obj, stream, 0); + out_json_rec(obj, stream, jf, 0); uw_unwind { set_indent_mode(stream, imode); set_indent(stream, isave); diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl index e214011c..5cc46e6b 100644 --- a/stdlib/doc-syms.tl +++ b/stdlib/doc-syms.tl @@ -36,6 +36,7 @@ ("*print-flo-digits*" "N-00F41F6C") ("*print-flo-format*" "N-02B252AA") ("*print-flo-precision*" "N-02E97D03") + ("*print-json-format*" "N-02338B4D") ("*random-state*" "N-033875AD") ("*random-warmup*" "N-010348CD") ("*read-bad-json*" "N-01C77B65") @@ -95,9 +95,11 @@ val get_error_s, get_error_str_s, clear_error_s, get_fd_s; val print_flo_precision_s, print_flo_digits_s, print_flo_format_s; val pprint_flo_format_s, print_base_s, print_circle_s; +val print_json_format_s; val from_start_k, from_current_k, from_end_k; val real_time_k, name_k, addr_k, fd_k, byte_oriented_k; +val standard_k; val format_s; val stdio_stream_s; @@ -5414,6 +5416,7 @@ void stream_init(void) addr_k = intern(lit("addr"), keyword_package); fd_k = intern(lit("fd"), keyword_package); byte_oriented_k = intern(lit("byte-oriented"), keyword_package); + standard_k = intern(lit("standard"), keyword_package); format_s = intern(lit("format"), user_package); stdio_stream_s = intern(lit("stdio-stream"), user_package); #if HAVE_SOCKETS @@ -5469,6 +5472,7 @@ void stream_init(void) reg_var(print_base_s = intern(lit("*print-base*"), user_package), num_fast(10)); reg_var(print_circle_s = intern(lit("*print-circle*"), user_package), nil); + reg_var(print_json_format_s = intern(lit("*print-json-format*"), user_package), nil); #if HAVE_ISATTY if (isatty(fileno(stdin)) == 1) { @@ -131,10 +131,17 @@ struct stdio_mode { #define std_debug (deref(lookup_var_l(nil, stddebug_s))) #define std_error (deref(lookup_var_l(nil, stderr_s))) #define std_null (deref(lookup_var_l(nil, stdnull_s))) + +enum json_fmt { + json_fmt_default, + json_fmt_standard +}; + loc lookup_var_l(val env, val sym); extern val from_start_k, from_current_k, from_end_k; extern val real_time_k, name_k, addr_k, fd_k, byte_oriented_k; +extern val standard_k; extern val format_s; extern val stdio_stream_s; @@ -148,6 +155,7 @@ extern val get_error_s, get_error_str_s, clear_error_s, get_fd_s; extern val print_flo_precision_s, print_flo_digits_s, print_flo_format_s; extern val pprint_flo_format_s, print_base_s, print_circle_s; +extern val print_json_format_s; #if HAVE_SOCKETS extern val socket_error_s; @@ -79981,6 +79981,29 @@ argument is passed to that function, defaulting to The value returned is that of .codn put-jsons . +.coNP Variable @ *print-json-format* +.desc +The +.code *print-json-format* +variable controls the formatting style exhibited by +.code put-json +and related functions. The initial value of this variable is +.codn nil . + +If the value is the keyword symbol +.codn :standard , +then a widely-used format is used, in which the opening and closing +braces and brackets of vectors and dictionaries are printed +on separate lines, as are the elements of those objects. + +If the variable +has any other value, including the initial value +.codn nil , +then a default format is used in which braces, brackets +and elements appear on the same line, subject to automatic +breaking and indentation, similar to the way Lisp nested +list structure is printed. + .coNP Variable @ *read-bad-json* .desc This dynamic variable, initialized to a value of |