summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c1
-rw-r--r--lib.c21
-rw-r--r--lib.h1
-rw-r--r--share/txr/stdlib/doc-syms.tl1
-rw-r--r--txr.166
5 files changed, 90 insertions, 0 deletions
diff --git a/eval.c b/eval.c
index 15454da8..117890c7 100644
--- a/eval.c
+++ b/eval.c
@@ -6873,6 +6873,7 @@ void eval_init(void)
reg_fun(intern(lit("prinl"), user_package), func_n2o(prinl, 1));
reg_fun(intern(lit("pprinl"), user_package), func_n2o(pprinl, 1));
reg_fun(intern(lit("tprint"), user_package), func_n2o(tprint, 1));
+ reg_fun(intern(lit("tojson"), user_package), func_n2o(tojson, 1));
reg_fun(intern(lit("display-width"), user_package), func_n1(display_width));
reg_fun(intern(lit("fmt-simple"), system_package), func_n5o(fmt_simple, 1));
diff --git a/lib.c b/lib.c
index e1879df6..75cbc739 100644
--- a/lib.c
+++ b/lib.c
@@ -13454,6 +13454,27 @@ val tostringp(val obj)
return get_string_from_stream(ss);
}
+val tojson(val obj, val flat)
+{
+ if (consp(obj) && eq(car(obj), json_s)) {
+ val ss = make_string_output_stream();
+ if (default_null_arg(flat))
+ set_indent_mode(ss, num_fast(indent_foff));
+ obj_print(obj, ss, nil);
+ return get_string_from_stream(ss);
+ } else {
+ val json = cons(json_s, cons(quote_s, cons(obj, nil)));
+ val ss = make_string_output_stream();
+ if (default_null_arg(flat))
+ set_indent_mode(ss, num_fast(indent_foff));
+ obj_print(json, ss, nil);
+ rcyc_pop(&json);
+ rcyc_pop(&json);
+ rcyc_pop(&json);
+ return get_string_from_stream(ss);
+ }
+}
+
val display_width(val obj)
{
if (stringp(obj)) {
diff --git a/lib.h b/lib.h
index 1b9c1702..1d1ee673 100644
--- a/lib.h
+++ b/lib.h
@@ -1206,6 +1206,7 @@ val print(val obj, val stream, val pretty);
val pprint(val obj, val stream);
val tostring(val obj);
val tostringp(val obj);
+val tojson(val obj, val flat);
val display_width(val obj);
#if !HAVE_SETENV
void setenv(const char *name, const char *value, int overwrite);
diff --git a/share/txr/stdlib/doc-syms.tl b/share/txr/stdlib/doc-syms.tl
index 1b9eb503..1e12d115 100644
--- a/share/txr/stdlib/doc-syms.tl
+++ b/share/txr/stdlib/doc-syms.tl
@@ -1854,6 +1854,7 @@
("tofloatz" "N-03E2D4B8")
("toint" "N-01DBC9D7")
("tointz" "N-03E2D4B8")
+ ("tojson" "N-017848BD")
("tok" "N-0117F60C")
("tok-str" "N-0225F28F")
("tok-where" "N-0225F28F")
diff --git a/txr.1 b/txr.1
index 94a88cc1..dffd9b4b 100644
--- a/txr.1
+++ b/txr.1
@@ -71808,6 +71808,72 @@ etc.
.SS* Data Interchange Support
+.coNP Function @ tojson
+.synb
+.mets (tojson < obj <> [ flat-p ])
+.syne
+.desc
+The
+.code tojson
+function converts
+.meta obj
+into JSON notation, returned as a character string.
+
+If
+.meta obj
+is
+.code json
+macro syntax generated by the parser, or else generated programmatically in a compatible way,
+then this is converted back into JSON syntax.
+
+Otherwise if
+.meta obj
+conforms to the conventions by which JSON objects are represented in Lisp,
+it is converted to JSON syntax also.
+
+The behavior is unspecified if
+.meta obj
+or any component of
+.meta obj
+is an object incompatible with the JSON representation conventions.
+An exception may be thrown.
+
+An object conforms to the JSON representation conventions if:
+.RS
+.IP 1.
+It is one of the symbols
+.codn nil ,
+.code t
+or
+.codn null ,
+which map to the JSON keywords
+.codn false ,
+.code true
+and
+.codn null ,
+respectively.
+.IP 2.
+It is a floating-point number.
+.IP 3.
+It is a character string.
+.IP 4.
+It is a vector of JSON-conforming objects.
+.IP 5.
+It is a hash table whose keys and values are JSON-conforming objects.
+.RE
+.IP
+Note that if unless the keys in a hash table are all strings, nonstandard JSON
+is produced, since RFC 8259 requires JSON object keys to be strings.
+
+If the
+.code flat-p
+argument is present and has a true value, then the JSON is generated
+without any line breaks or indentation.
+
+Otherwise, the JSON is potentially subject to such formatting.
+
+Even if the JSON data contains line breaks, it does not end in a line break.
+
.coNP Macro @ json
.synb
.mets (json [quote | sys:qquote] << object )