docs
This commit is contained in:
+157
-98
@@ -112,95 +112,6 @@ String list_find(StringList items, std::function<bool (String)> f, String fallba
|
||||
return(fallback);
|
||||
}
|
||||
|
||||
StringList dv_keys(DValue tree)
|
||||
{
|
||||
StringList result;
|
||||
tree.each([&](const DValue& item, String key) {
|
||||
if(key != "")
|
||||
result.push_back(key);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DValue dv_values(DValue tree)
|
||||
{
|
||||
DValue result;
|
||||
result.set_array();
|
||||
tree.each([&](const DValue& item, String key) {
|
||||
result.push(item);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DValue dv_pick(DValue tree, StringList keys)
|
||||
{
|
||||
DValue result;
|
||||
for(auto key : keys)
|
||||
{
|
||||
DValue* item = tree.key(key);
|
||||
if(item)
|
||||
result[key] = *item;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
DValue dv_omit(DValue tree, StringList keys)
|
||||
{
|
||||
DValue result;
|
||||
std::set<String> omitted(keys.begin(), keys.end());
|
||||
tree.each([&](const DValue& item, String key) {
|
||||
if(key != "" && omitted.find(key) == omitted.end())
|
||||
result[key] = item;
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DValue dv_map(DValue tree, std::function<DValue (const DValue&, String)> f)
|
||||
{
|
||||
DValue result;
|
||||
bool input_is_list = tree.is_list();
|
||||
if(input_is_list)
|
||||
result.set_array();
|
||||
tree.each([&](const DValue& item, String key) {
|
||||
DValue mapped = f(item, key);
|
||||
if(key != "" && !input_is_list)
|
||||
result[key] = mapped;
|
||||
else
|
||||
result.push(mapped);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DValue dv_filter(DValue tree, std::function<bool (const DValue&, String)> f)
|
||||
{
|
||||
DValue result;
|
||||
bool input_is_list = tree.is_list();
|
||||
if(input_is_list)
|
||||
result.set_array();
|
||||
tree.each([&](const DValue& item, String key) {
|
||||
if(!f(item, key))
|
||||
return;
|
||||
if(key != "" && !input_is_list)
|
||||
result[key] = item;
|
||||
else
|
||||
result.push(item);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DValue dv_group_by(DValue tree, std::function<String (const DValue&, String)> f)
|
||||
{
|
||||
DValue result;
|
||||
tree.each([&](const DValue& item, String key) {
|
||||
String group = f(item, key);
|
||||
DValue* group_items = result.get_or_create(group);
|
||||
if(!group_items->is_array())
|
||||
group_items->set_array();
|
||||
group_items->push(item);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
String substr(String s, s64 start_pos)
|
||||
{
|
||||
s64 len = s.length();
|
||||
@@ -643,7 +554,7 @@ StringList regex_split(String pattern, String subject, String flags)
|
||||
#else
|
||||
|
||||
// PCRE2 is not compiled into the wasm core; regex runs host-side (the host
|
||||
// already links libpcre2). One UCEB1-marshalled hostcall carries the request
|
||||
// already links libpcre2). One UCEB2-marshalled hostcall carries the request
|
||||
// {op,pattern,subject,flags,replacement} in and the result tree out — the host
|
||||
// runs the native regex_* and packs the answer. See uce_host_regex in
|
||||
// src/wasm/worker.cpp.
|
||||
@@ -1063,6 +974,48 @@ f64 float_val(String s)
|
||||
return(strtod(s.c_str(), 0));
|
||||
}
|
||||
|
||||
u64 to_u64(String s, u64 fallback)
|
||||
{
|
||||
String raw = trim(s);
|
||||
if(raw == "")
|
||||
return(fallback);
|
||||
char* end = 0;
|
||||
unsigned long long value = strtoull(raw.c_str(), &end, 10);
|
||||
return(end && *end == 0 ? (u64)value : fallback);
|
||||
}
|
||||
|
||||
s64 to_s64(String s, s64 fallback)
|
||||
{
|
||||
String raw = trim(s);
|
||||
if(raw == "")
|
||||
return(fallback);
|
||||
char* end = 0;
|
||||
long long value = strtoll(raw.c_str(), &end, 10);
|
||||
return(end && *end == 0 ? (s64)value : fallback);
|
||||
}
|
||||
|
||||
f64 to_f64(String s, f64 fallback)
|
||||
{
|
||||
String raw = trim(s);
|
||||
if(raw == "")
|
||||
return(fallback);
|
||||
char* end = 0;
|
||||
double value = strtod(raw.c_str(), &end);
|
||||
return(end && *end == 0 ? (f64)value : fallback);
|
||||
}
|
||||
|
||||
bool to_bool(String s, bool fallback)
|
||||
{
|
||||
String raw = trim(to_lower(s));
|
||||
if(raw == "")
|
||||
return(fallback);
|
||||
if(raw == "1" || raw == "true" || raw == "yes" || raw == "on")
|
||||
return(true);
|
||||
if(raw == "0" || raw == "false" || raw == "no" || raw == "off")
|
||||
return(false);
|
||||
return(fallback);
|
||||
}
|
||||
|
||||
String nibble(String& haystack, String delim)
|
||||
{
|
||||
auto idx = haystack.find(delim);
|
||||
@@ -2255,6 +2208,58 @@ DValue yaml_decode(String s)
|
||||
return(parser.parse_document());
|
||||
}
|
||||
|
||||
static bool json_hex_to_u32(String s, u32 start, u32& value)
|
||||
{
|
||||
value = 0;
|
||||
if(start > s.length() || s.length() - start < 4)
|
||||
return(false);
|
||||
for(u32 i = 0; i < 4; i += 1)
|
||||
{
|
||||
char c = s[start + i];
|
||||
if(c >= '0' && c <= '9')
|
||||
value = (value << 4) | (c - '0');
|
||||
else if(c >= 'a' && c <= 'f')
|
||||
value = (value << 4) | (c - 'a' + 10);
|
||||
else if(c >= 'A' && c <= 'F')
|
||||
value = (value << 4) | (c - 'A' + 10);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
static bool json_decode_unicode_escape(String s, u32& i, String& result)
|
||||
{
|
||||
u32 codepoint = 0;
|
||||
if(i >= s.length() || s[i] != 'u' || !json_hex_to_u32(s, i + 1, codepoint))
|
||||
return(false);
|
||||
|
||||
u32 next_sequence_start = i + 5;
|
||||
if(codepoint >= 0xd800 && codepoint <= 0xdbff)
|
||||
{
|
||||
u32 low = 0;
|
||||
if(next_sequence_start <= s.length() && s.length() - next_sequence_start >= 6 && s[next_sequence_start] == '\\' && s[next_sequence_start + 1] == 'u' && json_hex_to_u32(s, next_sequence_start + 2, low) && low >= 0xdc00 && low <= 0xdfff)
|
||||
{
|
||||
codepoint = 0x10000 + (((codepoint - 0xd800) << 10) | (low - 0xdc00));
|
||||
String utf8 = xml_utf8_from_codepoint(codepoint);
|
||||
if(utf8 != "")
|
||||
result += utf8;
|
||||
i += 10;
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
if(codepoint >= 0xdc00 && codepoint <= 0xdfff)
|
||||
return(false);
|
||||
|
||||
String utf8 = xml_utf8_from_codepoint(codepoint);
|
||||
if(utf8 == "")
|
||||
return(false);
|
||||
result += utf8;
|
||||
i += 4;
|
||||
return(true);
|
||||
}
|
||||
|
||||
// https://i.stack.imgur.com/SHLOB.gif
|
||||
String json_decode_String(String s, u32& i, char termination_char)
|
||||
{
|
||||
@@ -2271,6 +2276,9 @@ String json_decode_String(String s, u32& i, char termination_char)
|
||||
}
|
||||
else if(c == '\\')
|
||||
{
|
||||
if(i + 1 >= s.length())
|
||||
return(result);
|
||||
|
||||
i += 1;
|
||||
c = s[i];
|
||||
switch(c)
|
||||
@@ -2293,9 +2301,16 @@ String json_decode_String(String s, u32& i, char termination_char)
|
||||
case('f'):
|
||||
result.append(1, '\f');
|
||||
break;
|
||||
case('u'):
|
||||
// todo decode
|
||||
case('"'):
|
||||
result.append(1, '"');
|
||||
break;
|
||||
case('\''):
|
||||
result.append(1, '\'');
|
||||
break;
|
||||
case('u'):
|
||||
if(i <= s.length() && s.length() - i >= 5 && json_decode_unicode_escape(s, i, result))
|
||||
break;
|
||||
return(result);
|
||||
default:
|
||||
result.append(1, c);
|
||||
break;
|
||||
@@ -2342,19 +2357,58 @@ String json_decode_keyword(String s, u32& i)
|
||||
String json_decode_number(String s, u32& i)
|
||||
{
|
||||
String result;
|
||||
bool saw_dot = false;
|
||||
bool saw_exponent = false;
|
||||
|
||||
json_consume_space(s, i);
|
||||
if(i < s.length() && s[i] == '-')
|
||||
{
|
||||
result.append(1, '-');
|
||||
i += 1;
|
||||
}
|
||||
if(i >= s.length() || !isdigit(s[i]))
|
||||
return("");
|
||||
|
||||
while(i < s.length())
|
||||
{
|
||||
char c = s[i];
|
||||
if(isdigit(c) || c == '.')
|
||||
if(isdigit(c))
|
||||
{
|
||||
result.append(1, c);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if(c == '.' && !saw_dot && !saw_exponent)
|
||||
{
|
||||
return(result);
|
||||
result.append(1, c);
|
||||
saw_dot = true;
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
i += 1;
|
||||
if((c == 'e' || c == 'E') && !saw_exponent)
|
||||
{
|
||||
if(i + 1 >= s.length())
|
||||
break;
|
||||
u32 exponent_start = i;
|
||||
u32 next = i + 1;
|
||||
if(s[next] == '+' || s[next] == '-')
|
||||
next += 1;
|
||||
if(next < s.length() && isdigit(s[next]))
|
||||
{
|
||||
result.append(1, s[i]);
|
||||
i = i + 1;
|
||||
if(i < s.length() && (s[i] == '+' || s[i] == '-'))
|
||||
{
|
||||
result.append(1, s[i]);
|
||||
i += 1;
|
||||
}
|
||||
saw_exponent = true;
|
||||
continue;
|
||||
}
|
||||
i = exponent_start;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
@@ -2364,6 +2418,9 @@ DValue json_decode_value(String s, u32& i)
|
||||
DValue result;
|
||||
String value = "";
|
||||
json_consume_space(s, i);
|
||||
if(i >= s.length())
|
||||
return(result);
|
||||
|
||||
char c = s[i];
|
||||
//print("json_decode_value " + s.substr(i) + "\n");
|
||||
if(c == '"' || c == '\'') // String value
|
||||
@@ -2373,7 +2430,7 @@ DValue json_decode_value(String s, u32& i)
|
||||
result._String = json_decode_String(s, i, s[i-1]);
|
||||
return(result);
|
||||
}
|
||||
else if(isdigit(c))
|
||||
else if(c == '-' || isdigit(c))
|
||||
{
|
||||
result.type = 'S';
|
||||
result._String = json_decode_number(s, i);
|
||||
@@ -2426,9 +2483,11 @@ DValue json_decode_map(String s, u32& i)
|
||||
else if(c == '"' || c == '\'')
|
||||
{
|
||||
i += 1;
|
||||
if(i >= s.length())
|
||||
return(result);
|
||||
key = json_decode_String(s, i, s[i-1]);
|
||||
json_consume_space(s, i);
|
||||
if(s[i] != ':')
|
||||
if(i >= s.length() || s[i] != ':')
|
||||
return(result); // malformed
|
||||
i += 1;
|
||||
DValue v = json_decode_value(s, i);
|
||||
|
||||
Reference in New Issue
Block a user