Add HMAC-SHA256, base64url, uuid_v4, unix_timestamp, json encode/decode, http auth builtins for soma-license
New builtins in dispatch_builtin:
- hmac_sha256(secret, data) -> String (hex)
- base64_url_encode(s) / base64_url_decode(s) -> String
- unix_timestamp() -> Int
- uuid_v4() -> String (alias for uuid_new)
- json_encode(v) / json_decode(s) -> polymorphic
- json_get_string(obj, key), json_get_int(obj, key), json_get_array(obj, key)
— work on both Value::Map and Value::Struct (json_parse returns Struct)
- http_get_auth(url, token), http_put_auth(url, token, body), http_delete_auth(url, token)
- string_split_last(s, delim) -> [before, after] on last occurrence
- array_get(arr, idx) -> element
http_serve upgraded to general-purpose router: passes all requests to
handle_request(method, path, body) — not just /axon/message. Method, path,
body stored in GLOBAL_STATE before calling callback; handle_request receives
them as positional args via initial_stack.
env() now returns "" (not Nil) when var is unset — enables `env("X") == ""`
comparisons in Engram code.
run_sub_interpreter_with_stack() added to support pre-pushing args onto the
call stack before entering a function.
Fix pre-existing non-exhaustive match errors in el-fmt, el-types, el-arch
for Retry, Deploy, With, Reason, Parallel, Trace, Activate AST nodes.
Register all builtins in TypeEnv::with_builtins() to eliminate type-checker
warnings for builtin calls.
This commit is contained in:
@@ -117,6 +117,139 @@ impl TypeEnv {
|
||||
env.functions.insert("log".into(), void_fn_any.clone());
|
||||
env.functions.insert("print_err".into(), void_fn_any);
|
||||
|
||||
// ── String builtins ───────────────────────────────────────────────────
|
||||
let str_fn = |params: Vec<Type>, ret: Type| Type::Fn { params, return_type: Box::new(ret) };
|
||||
let s = Type::String;
|
||||
let i = Type::Int;
|
||||
let b = Type::Bool;
|
||||
let u = Type::Unknown;
|
||||
|
||||
// String operations
|
||||
for name in &["str_contains","str_starts_with","string_starts_with","string_contains","str_ends_with","str_eq","string_ends_with","string_index_of","str_index_of","str_last_index_of"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![s.clone(), s.clone()], b.clone()));
|
||||
}
|
||||
for name in &["str_to_lowercase","str_trim","string_trim","string_to_upper","str_upper","string_to_lower","str_lower","to_string","int_to_str","bool_to_str"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone()], s.clone()));
|
||||
}
|
||||
for name in &["str_len","string_len","list_len","array_length","array_len","map_len","json_array_len"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone()], i.clone()));
|
||||
}
|
||||
for name in &["str_replace","string_replace","string_concat","string_substring","str_slice"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![s.clone(), s.clone(), s.clone()], s.clone()));
|
||||
}
|
||||
env.functions.insert("str_split".into(), str_fn(vec![s.clone(), s.clone()], Type::Unknown));
|
||||
env.functions.insert("string_split".into(), str_fn(vec![s.clone(), s.clone()], Type::Unknown));
|
||||
env.functions.insert("string_split_last".into(), str_fn(vec![s.clone(), s.clone()], Type::Unknown));
|
||||
env.functions.insert("array_join".into(), str_fn(vec![u.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("list_join".into(), str_fn(vec![u.clone(), s.clone()], s.clone()));
|
||||
|
||||
// Parse / convert
|
||||
for name in &["str_to_int","parse_int","int_parse"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![s.clone()], i.clone()));
|
||||
}
|
||||
for name in &["str_to_float","parse_float"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![s.clone()], Type::Float));
|
||||
}
|
||||
|
||||
// JSON
|
||||
env.functions.insert("json_get".into(), str_fn(vec![s.clone(), s.clone()], u.clone()));
|
||||
env.functions.insert("json_set".into(), str_fn(vec![s.clone(), s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("json_keys".into(), str_fn(vec![s.clone()], Type::Unknown));
|
||||
env.functions.insert("json_stringify".into(), str_fn(vec![u.clone()], s.clone()));
|
||||
env.functions.insert("json_parse".into(), str_fn(vec![s.clone()], u.clone()));
|
||||
env.functions.insert("json_encode".into(), str_fn(vec![u.clone()], s.clone()));
|
||||
env.functions.insert("json_decode".into(), str_fn(vec![s.clone()], u.clone()));
|
||||
env.functions.insert("json_get_string".into(), str_fn(vec![u.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("json_get_int".into(), str_fn(vec![u.clone(), s.clone()], i.clone()));
|
||||
env.functions.insert("json_get_array".into(), str_fn(vec![u.clone(), s.clone()], Type::Unknown));
|
||||
env.functions.insert("json_array_get".into(), str_fn(vec![s.clone(), i.clone()], u.clone()));
|
||||
env.functions.insert("json_array_push".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("json_array_len".into(), str_fn(vec![s.clone()], i.clone()));
|
||||
|
||||
// Array
|
||||
for name in &["array_push","array_pop","array_reverse","array_sort","array_first","array_last"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone()], u.clone()));
|
||||
}
|
||||
env.functions.insert("array_get".into(), str_fn(vec![u.clone(), i.clone()], u.clone()));
|
||||
env.functions.insert("list_get".into(), str_fn(vec![u.clone(), i.clone()], u.clone()));
|
||||
env.functions.insert("array_concat".into(), str_fn(vec![u.clone(), u.clone()], u.clone()));
|
||||
env.functions.insert("array_contains".into(), str_fn(vec![u.clone(), u.clone()], b.clone()));
|
||||
env.functions.insert("array_slice".into(), str_fn(vec![u.clone(), i.clone(), i.clone()], u.clone()));
|
||||
env.functions.insert("array_zip".into(), str_fn(vec![u.clone(), u.clone()], u.clone()));
|
||||
env.functions.insert("array_enumerate".into(), str_fn(vec![u.clone()], u.clone()));
|
||||
|
||||
// Map
|
||||
env.functions.insert("map_new".into(), str_fn(vec![], u.clone()));
|
||||
for name in &["map_get","map_remove","map_contains","map_keys","map_values"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone(), s.clone()], u.clone()));
|
||||
}
|
||||
env.functions.insert("map_set".into(), str_fn(vec![u.clone(), s.clone(), u.clone()], u.clone()));
|
||||
env.functions.insert("map_len".into(), str_fn(vec![u.clone()], i.clone()));
|
||||
|
||||
// Filesystem
|
||||
for name in &["fs_read"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![s.clone()], s.clone()));
|
||||
}
|
||||
for name in &["fs_write","fs_append","fs_exists","fs_mkdir","fs_remove","fs_is_dir"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone()], b.clone()));
|
||||
}
|
||||
env.functions.insert("fs_list".into(), str_fn(vec![s.clone()], Type::Unknown));
|
||||
env.functions.insert("fs_list_recursive".into(), str_fn(vec![s.clone()], Type::Unknown));
|
||||
env.functions.insert("path_join".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("path_parent".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("cwd".into(), str_fn(vec![], s.clone()));
|
||||
|
||||
// Crypto / UUID
|
||||
env.functions.insert("blake3_hash".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("uuid_new".into(), str_fn(vec![], s.clone()));
|
||||
env.functions.insert("uuid_v4".into(), str_fn(vec![], s.clone()));
|
||||
env.functions.insert("hmac_sha256".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("base64_url_encode".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("base64_url_decode".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("unix_timestamp".into(), str_fn(vec![], i.clone()));
|
||||
env.functions.insert("now_millis".into(), str_fn(vec![], i.clone()));
|
||||
|
||||
// HTTP
|
||||
env.functions.insert("http_get".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("http_post".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("http_put".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("http_delete".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("http_patch".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("http_get_auth".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("http_put_auth".into(), str_fn(vec![s.clone(), s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("http_delete_auth".into(), str_fn(vec![s.clone(), s.clone()], s.clone()));
|
||||
env.functions.insert("http_serve".into(), str_fn(vec![u.clone()], Type::Void));
|
||||
|
||||
// State
|
||||
env.functions.insert("state_get".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("state_set".into(), str_fn(vec![s.clone(), s.clone()], b.clone()));
|
||||
env.functions.insert("state_del".into(), str_fn(vec![s.clone()], b.clone()));
|
||||
env.functions.insert("state_keys".into(), str_fn(vec![], Type::Unknown));
|
||||
|
||||
// System
|
||||
env.functions.insert("env".into(), str_fn(vec![s.clone()], s.clone()));
|
||||
env.functions.insert("args".into(), str_fn(vec![], Type::Unknown));
|
||||
env.functions.insert("exit".into(), str_fn(vec![i.clone()], Type::Void));
|
||||
env.functions.insert("sleep_ms".into(), str_fn(vec![i.clone()], Type::Void));
|
||||
env.functions.insert("timestamp".into(), str_fn(vec![], s.clone()));
|
||||
|
||||
// Math
|
||||
for name in &["math_abs","math_floor","math_ceil","math_round","math_sqrt"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone()], u.clone()));
|
||||
}
|
||||
env.functions.insert("math_max".into(), str_fn(vec![u.clone(), u.clone()], u.clone()));
|
||||
env.functions.insert("math_min".into(), str_fn(vec![u.clone(), u.clone()], u.clone()));
|
||||
env.functions.insert("math_pow".into(), str_fn(vec![u.clone(), u.clone()], Type::Float));
|
||||
|
||||
// Result / Optional
|
||||
for name in &["result_ok","result_err","result_unwrap","result_unwrap_or","optional_some","optional_unwrap","optional_unwrap_or"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone()], u.clone()));
|
||||
}
|
||||
for name in &["result_is_ok","result_is_err","optional_is_some","optional_is_none"] {
|
||||
env.functions.insert(name.to_string(), str_fn(vec![u.clone()], b.clone()));
|
||||
}
|
||||
env.functions.insert("optional_none".into(), str_fn(vec![], Type::Void));
|
||||
|
||||
env
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user