///|
/// Helper to set value at a path in JSON structure
fn set_at_path(root : Json, path : ArrayView[Json], value : Json) -> Json {
match path {
[] => value
[segment, .. rest] =>
match (root, segment) {
(Object(obj), String(key)) => {
let new_obj = obj.copy()
let next_value = match rest {
[] => value
_ => {
let current = obj.get(key).unwrap_or(null)
set_at_path(current, rest, value)
}
}
new_obj[key] = next_value
Json::object(new_obj)
}
(Array(arr), Number(idx, ..)) => {
let i = idx.to_int()
if i >= 0 && i < arr.length() {
let new_arr = arr.copy()
let next_value = match rest {
[] => value
_ => set_at_path(arr[i], rest, value)
}
new_arr[i] = next_value
Json::array(new_arr)
} else {
root
}
}
_ => root
}
}
}
///|
/// Helper to delete value at a path in JSON structure
fn delete_at_path(root : Json, path : ArrayView[Json]) -> Json {
match path {
[] => null
[segment] =>
match (root, segment) {
(Object(obj), String(key)) => {
let new_obj = obj.copy()
new_obj.remove(key)
Json::object(new_obj)
}
(Array(arr), Number(idx, ..)) => {
let i = idx.to_int()
if i >= 0 && i < arr.length() {
let filtered = arr.mapi(fn(j, v) {
if j == i {
None
} else {
Some(v)
}
})
Json::array(filtered.filter_map(fn(v) { v }))
} else {
root
}
}
_ => root
}
[segment, .. rest] =>
match (root, segment) {
(Object(obj), String(key)) => {
let new_obj = obj.copy()
match obj.get(key) {
Some(current) => new_obj[key] = delete_at_path(current, rest)
None => ()
}
Json::object(new_obj)
}
(Array(arr), Number(idx, ..)) => {
let i = idx.to_int()
if i >= 0 && i < arr.length() {
let new_arr = arr.copy()
new_arr[i] = delete_at_path(arr[i], rest)
Json::array(new_arr)
} else {
root
}
}
_ => root
}
}
}
///|
/// Evaluate SetPath
fn eval_set_path(
path_expr : Expr,
value_expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
let path_results = eval_with_env(path_expr, input, env).collect()
let value_results = eval_with_env(value_expr, input, env).collect()
match (path_results, value_results) {
([Array(path_arr), ..], [value, ..]) =>
match path_arr {
[] => Iter::singleton(value)
_ => Iter::singleton(set_at_path(input, path_arr, value))
}
_ => Iter::singleton(input)
}
}
///|
/// Evaluate DelPaths
fn eval_del_paths(
paths_expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
match eval_with_env(paths_expr, input, env).collect() {
[Array(paths_arr), ..] =>
Iter::singleton(
paths_arr.fold(init=input, fn(acc, path_json) {
match path_json {
Array(path) => delete_at_path(acc, path)
_ => acc
}
}),
)
_ => Iter::singleton(input)
}
}