This commit is contained in:
root
2026-06-15 21:42:50 +00:00
parent 34a97e2577
commit 99cd92fb4a
126 changed files with 1615 additions and 1057 deletions
+157 -98
View File
@@ -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);