merge runtime/json — JSON operations in El
This commit is contained in:
+173
@@ -0,0 +1,173 @@
|
||||
// runtime/json.el — El JSON operations
|
||||
//
|
||||
// Thin El wrappers over seed JSON primitives, plus pure-El builders and
|
||||
// helpers. Each function here corresponds to (and replaces) a C function
|
||||
// from el-compiler/runtime/legacy/el_runtime.c (lines 2692–3333).
|
||||
//
|
||||
// Seed primitives consumed by this module:
|
||||
// __json_get(json, key) -> String (value as string)
|
||||
// __json_get_raw(json, key) -> String (raw JSON token)
|
||||
// __json_parse_map(s) -> Map<String, Any>
|
||||
// __json_stringify_val(v) -> String
|
||||
// __json_array_len(arr) -> Int
|
||||
// __json_array_get(arr, i) -> String (element as JSON fragment)
|
||||
// __json_array_get_string(arr, i) -> String (element as string value)
|
||||
// __json_set(json, key, value) -> String (JSON mutation)
|
||||
// __str_to_int(s) -> Int
|
||||
// __str_to_float(s) -> Float
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Core — thin wrappers that delegate directly to seed
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// json_get — extract a value from a JSON object as a string.
|
||||
// Supports dot-path traversal ("a.b.c") and array indices ("items.0.name").
|
||||
fn json_get(json: String, key: String) -> String {
|
||||
return __json_get(json, key)
|
||||
}
|
||||
|
||||
// json_get_raw — extract a raw JSON token (the un-decoded fragment) for a key.
|
||||
// Useful when the caller wants to pass a sub-object to another JSON function.
|
||||
fn json_get_raw(json: String, key: String) -> String {
|
||||
return __json_get_raw(json, key)
|
||||
}
|
||||
|
||||
// json_parse — parse a JSON string into a Map<String, Any>.
|
||||
// Arrays become ElList; objects become ElMap; scalars are typed values.
|
||||
fn json_parse(s: String) -> Map<String, Any> {
|
||||
return __json_parse_map(s)
|
||||
}
|
||||
|
||||
// json_stringify — serialize an El value (ElMap, ElList, String, Int) to JSON.
|
||||
fn json_stringify(v: Any) -> String {
|
||||
return __json_stringify_val(v)
|
||||
}
|
||||
|
||||
// json_array_len — return the number of elements in a JSON array string.
|
||||
fn json_array_len(arr: String) -> Int {
|
||||
return __json_array_len(arr)
|
||||
}
|
||||
|
||||
// json_array_get — return the i-th element of a JSON array as a JSON fragment.
|
||||
// Nested objects and arrays are returned verbatim. Out-of-range -> "".
|
||||
fn json_array_get(arr: String, i: Int) -> String {
|
||||
return __json_array_get(arr, i)
|
||||
}
|
||||
|
||||
// json_array_get_string — return the i-th element of a JSON array as a plain
|
||||
// string value (quotes and escape sequences removed). Non-string elements
|
||||
// and out-of-range indices yield "".
|
||||
fn json_array_get_string(arr: String, i: Int) -> String {
|
||||
return __json_array_get_string(arr, i)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Typed extractors — delegate to seed then convert
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// json_get_string — extract a string value for a key.
|
||||
// Equivalent to json_get but named explicitly for readability.
|
||||
fn json_get_string(json: String, key: String) -> String {
|
||||
return __json_get(json, key)
|
||||
}
|
||||
|
||||
// json_get_int — extract an integer value for a key.
|
||||
fn json_get_int(json: String, key: String) -> Int {
|
||||
let s: String = __json_get(json, key)
|
||||
return str_to_int(s)
|
||||
}
|
||||
|
||||
// json_get_float — extract a floating-point value for a key.
|
||||
fn json_get_float(json: String, key: String) -> Float {
|
||||
let s: String = __json_get(json, key)
|
||||
return str_to_float(s)
|
||||
}
|
||||
|
||||
// json_get_bool — extract a boolean value for a key.
|
||||
// Returns true only when the raw JSON token is the literal "true".
|
||||
fn json_get_bool(json: String, key: String) -> Bool {
|
||||
let s: String = __json_get(json, key)
|
||||
return str_eq(s, "true")
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mutation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// json_set — set or insert a key/value pair in a JSON object string.
|
||||
// If the key already exists its value is replaced in-place; otherwise the
|
||||
// pair is appended before the closing brace. The value must already be a
|
||||
// valid JSON-encoded string (e.g. a quoted string, number, or sub-object).
|
||||
fn json_set(json: String, key: String, value: String) -> String {
|
||||
return __json_set(json, key, value)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Pure-El builders — no seed call required
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// json_build_object — build a JSON object from alternating key/value strings.
|
||||
//
|
||||
// keys_and_values must contain an even number of elements laid out as:
|
||||
// [key0, val0, key1, val1, ...]
|
||||
//
|
||||
// Both keys and values are assumed to be plain strings that will be
|
||||
// double-quoted and JSON-escaped by this function. Pass a pre-encoded
|
||||
// number or sub-object as the value if you need non-string JSON types.
|
||||
//
|
||||
// Example:
|
||||
// json_build_object(["name", "alice", "role", "admin"])
|
||||
// -> {"name":"alice","role":"admin"}
|
||||
fn json_build_object(keys_and_values: [String]) -> String {
|
||||
let n: Int = el_list_len(keys_and_values)
|
||||
let result: String = "{"
|
||||
let i: Int = 0
|
||||
while i < n - 1 {
|
||||
let key: String = el_list_get(keys_and_values, i)
|
||||
let val: String = el_list_get(keys_and_values, i + 1)
|
||||
let sep: String = if i == 0 { "" } else { "," }
|
||||
let escaped_key: String = json_escape_string(key)
|
||||
let escaped_val: String = json_escape_string(val)
|
||||
let result = result + sep + "\"" + escaped_key + "\":\"" + escaped_val + "\""
|
||||
let i = i + 2
|
||||
}
|
||||
return result + "}"
|
||||
}
|
||||
|
||||
// json_build_array — build a JSON array from a list of already-JSON-encoded
|
||||
// strings.
|
||||
//
|
||||
// Each element in items must be a valid JSON fragment (quoted string, number,
|
||||
// object, array, or literal). The function joins them with commas and wraps
|
||||
// the result in brackets.
|
||||
//
|
||||
// Example:
|
||||
// json_build_array(["\"alice\"", "\"bob\""])
|
||||
// -> ["alice","bob"]
|
||||
fn json_build_array(items: [String]) -> String {
|
||||
let n: Int = el_list_len(items)
|
||||
let result: String = "["
|
||||
let i: Int = 0
|
||||
while i < n {
|
||||
let item: String = el_list_get(items, i)
|
||||
let sep: String = if i == 0 { "" } else { "," }
|
||||
let result = result + sep + item
|
||||
let i = i + 1
|
||||
}
|
||||
return result + "]"
|
||||
}
|
||||
|
||||
// json_escape_string — escape a raw string so it can be safely embedded as a
|
||||
// JSON string value.
|
||||
//
|
||||
// Characters escaped: backslash, double-quote, newline, carriage return, tab.
|
||||
// The returned value does NOT include surrounding double-quotes; wrap it in
|
||||
// quotes if you need a complete JSON string literal.
|
||||
fn json_escape_string(s: String) -> String {
|
||||
let s1: String = str_replace(s, "\\", "\\\\")
|
||||
let s2: String = str_replace(s1, "\"", "\\\"")
|
||||
let s3: String = str_replace(s2, "\n", "\\n")
|
||||
let s4: String = str_replace(s3, "\r", "\\r")
|
||||
let s5: String = str_replace(s4, "\t", "\\t")
|
||||
return s5
|
||||
}
|
||||
Reference in New Issue
Block a user