1
1
s-lang/modules/json.sl

235 строки
6.0 KiB
Plaintext

% -*- mode: slang; mode: fold -*-
import("json");
%{{{ Type Handlers for json_encode
private variable Type_Map = Ref_Type[0];
private define add_type_handler ()
{
variable func = ();
loop (_NARGS-1)
{
variable type = ();
variable idx = __class_id (type);
variable n = length (Type_Map);
if (idx >= n)
{
variable new_map = Ref_Type[idx+1];
new_map[[0:n-1]] = Type_Map;
Type_Map = new_map;
}
Type_Map[idx] = func;
}
}
private define get_encode_func (type)
{
try
{
variable func = Type_Map[__class_id (type)];
if (func == NULL) throw IndexError;
return func;
}
catch IndexError:
throw Json_Invalid_Json_Error, "$type does not represent a JSON data structure"$;
}
%}}}
private define json_encode_string (indent, q, data) %{{{
{
return _json_encode_string (data);
}
add_type_handler (String_Type, BString_Type, &json_encode_string);
%}}}
private define json_encode_boolean (indent, q, data) %{{{
{
if (data == 1) return "true"B;
if (data == 0) return "false"B;
throw Json_Invalid_Json_Error, sprintf (`invalid boolean value '\%03o'; only '\000' and '\001' are allowed`, data);
}
add_type_handler (UChar_Type, &json_encode_boolean);
%}}}
private define json_encode_null (indent, q, data) %{{{
{
return "null"B;
}
add_type_handler (Null_Type, &json_encode_null);
%}}}
private define json_encode_number (indent, q, data) %{{{
{
return string (data);
}
add_type_handler (
Char_Type, % UChar_Type,
Short_Type, UShort_Type,
Int_Type, UInt_Type,
Long_Type, ULong_Type,
#ifexists LLong_Type
LLong_Type, ULLong_Type,
#endif
Float_Type, Double_Type,
&json_encode_number);
%}}}
private define json_encode_object (indent, q, object) %{{{
{
variable json = "{"B;
variable keys = get_struct_field_names (object);
variable n_values = length (keys);
if (n_values)
{
% pvs indent KEY nsep VAL vsep pvs indent KEY nsep VAL vsep
% ... pvs indent KEY nsep VAL pvs
variable new_indent = bstrcat (indent, q.indent);
variable sep = bstrcat (q.vsep, q.post_vsep, new_indent);
variable nsep = q.nsep;
variable key = keys[0];
variable val = get_struct_field(object, key);
variable type = typeof (val);
variable func = get_encode_func (type);
json = bstrcat (__tmp(json), q.post_vsep, new_indent,
_json_encode_string (key), nsep, (@func)(new_indent, q, val));
variable i;
_for i (1, n_values-1)
{
key = keys[i];
val = get_struct_field(object, key);
variable next_type = typeof (val);
if (next_type == String_Type)
{
json = bstrcat (__tmp(json), sep, _json_encode_string (key),
nsep, _json_encode_string (val));
continue;
}
if (next_type != type)
(type, func) = (next_type, get_encode_func (next_type));
json = bstrcat (__tmp(json), sep, _json_encode_string (key),
nsep, (@func)(new_indent, q, val));
}
json = bstrcat (__tmp(json), q.post_vsep);
}
return bstrcat (__tmp(json), indent, "}");
}
add_type_handler (Struct_Type, &json_encode_object);
%}}}
private define json_encode_array (indent, q, array) %{{{
{
variable json = "["B;
variable n_values = length (array);
if (n_values)
{
% pvs, new_indent, VALUE, vsep, pvs, new_indent, VALUE, vsep, pvs, ..., new_indent, VALUE, pvs
variable new_indent = bstrcat (indent, q.indent);
variable sep = bstrcat (q.vsep, q.post_vsep, new_indent);
variable i = 0;
variable a = array[i];
variable type = typeof (a);
variable func = get_encode_func (type);
json = bstrcat (__tmp(json), q.post_vsep,
new_indent, (@func)(new_indent, q, a));
if ((typeof (array) == Array_Type) && not any (_isnull (array)))
{
if (type == String_Type)
_for i (1, n_values-1)
json = bstrcat (__tmp(json), sep, _json_encode_string (array[i]));
else
_for i (1, n_values-1)
json = bstrcat (__tmp(json), sep, (@func)(new_indent, q, array[i]));
}
else _for i (1, n_values-1)
{
a = array[i];
variable next_type = typeof (a);
if (next_type == String_Type)
{
json = bstrcat (__tmp(json), sep, _json_encode_string (a));
continue;
}
if (next_type != type)
(type, func) = (next_type, get_encode_func (next_type));
json = bstrcat (__tmp(json), sep, (@func)(new_indent, q, a));
}
json = bstrcat (__tmp(json), q.post_vsep);
}
return bstrcat (__tmp(json), indent, "]");
}
add_type_handler (List_Type, Array_Type, &json_encode_array);
%}}}
private define default_handler (indent, q, data) %{{{
{
if (0 < __is_numeric (data) < 3)
return json_encode_number (data);
if (is_struct_type (data))
return json_encode_object (data);
variable type = _typeof (data);
throw Json_Invalid_Json_Error, "$type does not represent a JSON data structure"$;
}
Type_Map[where (_isnull (Type_Map))] = &default_handler;
%}}}
% process_qualifiers %{{{
private define split_post_vsep (post_vsep) %{{{
{
variable indent = "";
variable parts = strchop (post_vsep, '\n', 0);
if (length (parts) > 1)
{
indent = parts[-1];
parts[-1] = "";
post_vsep = strjoin (parts, "\n");
}
return (indent, post_vsep);
}
%}}}
private define only_whitespace (s)
{
return ""B + str_delete_chars (s, "^ \t\n\r");
}
private define process_qualifiers ()
{
variable post_vsep = split_post_vsep (qualifier ("post_vsep", ""));
variable indent = (); % other return value from split_post_vsep
variable q = struct {
pre_nsep = only_whitespace (qualifier ("pre_nsep", "")),
post_nsep = only_whitespace (qualifier ("post_nsep", "")),
pre_vsep = only_whitespace (qualifier ("pre_vsep", "")),
post_vsep = only_whitespace (post_vsep),
indent = only_whitespace (indent),
};
return struct {
nsep = q.pre_nsep + ":" + q.post_nsep,
vsep = q.pre_vsep + ",",
@q
};
}
%}}}
define json_encode (data)
{
variable q = process_qualifiers (;; __qualifiers);
variable func = get_encode_func (typeof (data));
variable json = (@func)(""B, q, data);
return typecast (json, String_Type);
}