Files
el/lang/runtime/json.el
T
will.anderson 0a72fced28
El SDK CI - dev / build-and-test (pull_request) Failing after 13m17s
engram: WAL persistence + integrity hardening + single canonical runtime
Establish lang/runtime/ as the ONE canonical el runtime (from the active
runtime that carries hebb/emb persistence + the new WAL); repoint the el CI
publish, engram build, elb default, and in-repo build scripts to it; delete
the el-compiler/runtime + lang/releases/ forks; add scripts/check-single-runtime.sh
drift guard.

Fixes a live prod bug: the el CI published el-runtime-c/-h from the LAGGING
el-compiler fork (0 hebb refs), so the shipped soul never persisted Hebbian
edge weights — learned co-activation was wiped on every restart. Publishing
from canonical ships the stranded 'learning that cannot outlive the process'
fix.

WAL storage engine + integrity fixes (DELETE->tombstone + store-layer
protection, safe data-dir default) ride in behind ENGRAM_WAL (default off =
byte-identical to today). Verified: engram elb per-module build clean, WAL
gate 66/66, native smoke ok, drift-guard green.
2026-08-11 21:31:37 -05:00

214 lines
8.3 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 runtime/el_runtime.c (lines 26923333).
//
// 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_array_push append a pre-encoded JSON element to a JSON array string.
// elem must be a valid JSON fragment (e.g. "\"foo\"" or "42").
// Returns a new JSON array string with elem appended.
// Example: json_array_push("[]", "\"alice\"") -> "[\"alice\"]"
fn json_array_push(arr: String, elem: String) -> String {
let n: Int = json_array_len(arr)
if n == 0 {
return "[" + elem + "]"
}
// arr ends with ']'; insert before it
let inner_end: Int = str_last_index_of(arr, "]")
if inner_end < 0 {
return "[" + elem + "]"
}
let prefix: String = str_slice(arr, 0, inner_end)
return prefix + "," + elem + "]"
}
// 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
}
// ---------------------------------------------------------------------------
// DHARMA byte decoding
// ---------------------------------------------------------------------------
// bytes_to_str decode a JSON array of integer byte values back to a string.
// "[104,105]" -> "hi"
// Inverse of str_to_bytes (defined in string.el). Defined here because it
// depends on json_array_len and json_array_get_string which live in this file.
fn bytes_to_str(arr: String) -> String {
let n: Int = json_array_len(arr)
if n == 0 { return "" }
let out: String = __str_alloc(n)
let i: Int = 0
while i < n {
let elem: String = json_array_get_string(arr, i)
let b: Int = __str_to_int(elem)
out = __str_set_char(out, i, b)
i = i + 1
}
return out
}