[Nickle] nickle: Branch 'master' - 2 commits
Keith Packard
keithp at keithp.com
Thu Nov 30 12:12:13 PST 2023
json.5c | 171 +++++++++++++++++++++++++++++++++++++------------------
test/jsontest.5c | 21 ++++++
2 files changed, 135 insertions(+), 57 deletions(-)
New commits:
commit f88bf667f87450ccc25f7cb5ba1d3f81272f37d3
Author: Keith Packard <keithp at keithp.com>
Date: Thu Nov 30 12:11:42 2023 -0800
test: Test true/false/null values in json
Signed-off-by: Keith Packard <keithp at keithp.com>
diff --git a/test/jsontest.5c b/test/jsontest.5c
index a7aa0fa..b1405f6 100644
--- a/test/jsontest.5c
+++ b/test/jsontest.5c
@@ -16,10 +16,27 @@ void json_test_val(poly val, string match) {
json_test_val(1, "1");
json_test_val(1.1, "1.1000000000000");
json_test_val("hello world", "\"hello world\"");
+json_test_val(true, "true");
+json_test_val(false, "false");
+json_test_val(<>, "null");
json_test_val((poly[string]) {
+ "false" => false,
"float" => 1.1,
"hash" => (poly[string]) { "hashval" => 12 },
"int" => 10,
- "string" => "world"
+ "null" => <>,
+ "string" => "world",
+ "true" => true,
},
- "{\n\t\"float\": 1.1000000000000,\n\t\"hash\": {\n\t\t\"hashval\": 12\n\t},\n\t\"int\": 10,\n\t\"string\": \"world\"\n}");
+ "{\n" +
+ "\t\"false\": false,\n" +
+ "\t\"float\": 1.1000000000000,\n" +
+ "\t\"hash\": {\n" +
+ "\t\t\"hashval\": 12\n" +
+ "\t},\n" +
+ "\t\"int\": 10,\n" +
+ "\t\"null\": null,\n" +
+ "\t\"string\": \"world\",\n" +
+ "\t\"true\": true\n" +
+ "}"
+ );
commit 488c6539e23bf4e6a6d27dd4729d4dc350e72940
Author: Keith Packard <keithp at keithp.com>
Date: Thu Nov 30 12:10:22 2023 -0800
Add true/false/null and file in/out to json.5c
json.5c missing support for three value tokens.
Also add support for file input and output of json
data, in addition to strings.
Signed-off-by: Keith Packard <keithp at keithp.com>
diff --git a/json.5c b/json.5c
index 3e9fe9d..2ae7c04 100644
--- a/json.5c
+++ b/json.5c
@@ -7,85 +7,96 @@ autoload Ctype;
namespace JSON {
- string quote(string a) {
- string result = "\"";
- for (int i = 0; i < String::length(a); i++) {
- int c = a[i];
- switch (c) {
- case '"':
- case '\\':
- result = result + "\\" + String::new(c);
- break;
- case '\n':
- result = result + "\\n";
- break;
- default:
- result = result + String::new(c);
- break;
+ public void to_json_file(file output, poly arg)
+ {
+ void do_indent(int indent) {
+ File::putc('\n', output);
+ for (int i = 0; i < indent; i++)
+ File::putc('\t', output);
+ }
+
+ void json_string(string a) {
+ File::putc('"', output);
+ for (int i = 0; i < String::length(a); i++) {
+ int c = a[i];
+ switch (c) {
+ case '\n':
+ c = 'n';
+ case '"':
+ case '\\':
+ File::putc('\\', output);
+ break;
+ default:
+ break;
+ }
+ File::putc(c, output);
}
+ File::putc('"', output);
}
- return result + "\"";
- }
- public string to_json(poly arg)
- {
- string do_indent(int indent) {
- string result = "\n";
- for (int i = 0; i < indent; i++)
- result = result + "\t";
- return result;
+ void putc(int c) {
+ File::putc(c, output);
+ }
+
+ void puts(string s) {
+ File::fprintf(output, "%s", s);
}
- string json(poly arg, int indent);
+ void json(poly arg, int indent);
- string json_hash(poly[string] a, int indent) {
+ void json_hash(poly[string] a, int indent) {
string[] keys = hash_keys(a);
- string result = "{";
+ putc('{');
bool first = true;
Sort::qsort(&keys, bool func(poly a, poly b) { return a > b; });
for (int i = 0; i < dim(keys); i++) {
string key = keys[i];
- string value = json(a[key], indent+1);
if (!first)
- result = result + ",";
+ putc(',');
first = false;
- result = result + do_indent(indent+1);
- result = result + quote(key) + ": " + value;
+ do_indent(indent+1);
+ json_string(key);
+ puts(": ");
+ json(a[key], indent+1);
}
- result = result + do_indent(indent) + "}";
- return result;
+ do_indent(indent);
+ putc('}');
}
- string json_array(poly[] a, int indent) {
- string result = "[";
+ void json_array(poly[] a, int indent) {
+ putc('[');
bool first = true;
for (int i = 0; i < dim(a); i++) {
if (!first)
- result = result + ",";
+ putc(',');
first = false;
- result = result + do_indent(indent+1);
- result = result + to_json(a[i]);
+ do_indent(indent + 1);
+ json(a[i], indent + 1);
}
- result = result + do_indent(indent) + "]";
- return result;
+ do_indent(indent);
+ putc(']');
+ }
+
+ void json_int(int arg) {
+ File::fprintf (output, "%d", arg);
}
- string json_string(string arg) {
- return quote(arg);
+ void json_float(real arg) {
+ File::fprintf(output, "%.13g", arg);
}
- string json_int(int arg) {
- return sprintf ("%d", arg);
+ void json_bool(bool arg) {
+ File::fprintf(output, "%s", arg ? "true" : "false");
}
- string json_float(real arg) {
- return sprintf("%.13g", arg);
+ void json_null(void arg) {
+ File::fprintf(output, "null");
}
- json = string func(poly arg, int indent) {
+ json = void func(poly arg, int indent) {
if (is_hash(arg))
return json_hash(arg, indent);
if (is_array(arg))
@@ -96,16 +107,28 @@ namespace JSON {
return json_int(arg);
if (is_number(arg))
return json_float(arg);
- return "";
+ if (is_bool(arg))
+ return json_bool(arg);
+ if (is_void(arg))
+ return json_null(arg);
};
- return json(arg, 0);
+ json(arg, 0);
+ }
+
+ public string to_json(poly arg)
+ {
+ file output = File::string_write();
+ to_json_file(output, arg);
+ return File::string_string(output);
}
typedef enum {
_string,
_int,
_float,
+ _bool,
+ _null,
_oc,
_cc,
_os,
@@ -121,6 +144,8 @@ namespace JSON {
int ival;
string sval;
real fval;
+ bool bval;
+ void nval;
} val;
term_t token;
} token_t;
@@ -135,6 +160,8 @@ namespace JSON {
return (json_input_t) { .f = File::string_read(s), .line = 1 };
}
+ public exception json_parse_error(int line, string token);
+
token_t lex(*json_input_t f) {
int ch() {
@@ -172,6 +199,16 @@ namespace JSON {
return false;
}
+ bool match_keyword(string keyword) {
+ int l = String::length(keyword);
+ for (int i = 1; i < l; i++) {
+ int c = ch();
+ if (keyword[i] != c)
+ return false;
+ }
+ return true;
+ }
+
try {
f->token = "";
for (;;) {
@@ -233,6 +270,21 @@ namespace JSON {
sval = sval + String::new(c);
}
return (token_t) { .val = { .sval = sval }, .token = term_t._string };
+ case 't':
+ if (match_keyword("true"))
+ return (token_t) { .val = { .bval = true }, .token = term_t._bool };
+ raise json_parse_error(f->line, f->token);
+ break;
+ case 'f':
+ if (match_keyword("false"))
+ return (token_t) { .val = { .bval = false }, .token = term_t._bool };
+ raise json_parse_error(f->line, f->token);
+ break;
+ case 'n':
+ if (match_keyword("null"))
+ return (token_t) { .val = { .nval = <> }, .token = term_t._null };
+ raise json_parse_error(f->line, f->token);
+ break;
default:
break;
}
@@ -245,11 +297,8 @@ namespace JSON {
return (token_t) { .token = term_t._error };
}
- public exception json_parse_error(int line, string token);
-
- public poly from_json(string arg) {
- json_input_t f = start_json(arg);
-
+ public poly from_json_file(file input) {
+ json_input_t f = { .f = input, .line = 1 };
token_t token;
void next() {
@@ -308,7 +357,7 @@ namespace JSON {
switch (token.token) {
case term_t._oc:
next();
- return hash();
+ return hash();
case term_t._os:
next();
return array();
@@ -324,10 +373,22 @@ namespace JSON {
string sval = token.val.sval;
next();
return sval;
+ case term_t._bool:
+ bool bval = token.val.bval;
+ next();
+ return bval;
+ case term_t._null:
+ void nval = token.val.nval;
+ next();
+ return nval;
}
};
next();
return value();
}
+
+ public poly from_json(string arg) {
+ return from_json_file(File::string_read(arg));
+ }
}
More information about the Nickle
mailing list