///|
/// Evaluate Update operator
fn eval_update(
path : Expr,
update_expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
fn apply_update(
obj : Json,
p : Expr,
upd : Expr,
) -> Json raise InterpreterError {
match p {
Identity =>
match eval_with_env(upd, obj, env).collect() {
[first, ..] => first
[] => obj
}
Key(key) =>
match obj {
Object(map) => {
let current = map.get(key).unwrap_or(null)
match eval_with_env(upd, current, env).collect() {
[updated, ..] => {
let new_map = map.copy()
new_map[key] = updated
Json::object(new_map)
}
[] => obj
}
}
_ => obj
}
Index(indices) =>
match (obj, indices) {
(Array(arr), [idx]) =>
if idx < 0 || idx >= arr.length() {
obj
} else {
match eval_with_env(upd, arr[idx], env).collect() {
[updated, ..] => {
let new_arr = arr.copy()
new_arr[idx] = updated
Json::array(new_arr)
}
[] => obj
}
}
_ => obj
}
Pipe(left, right) =>
match left {
Identity => apply_update(obj, right, upd)
Key(key) =>
match obj {
Object(map) => {
let current = map.get(key).unwrap_or(null)
let updated = apply_update(current, right, upd)
let new_map = map.copy()
new_map[key] = updated
Json::object(new_map)
}
_ => obj
}
Index(indices) =>
match (obj, indices) {
(Array(arr), [idx]) =>
if idx < 0 || idx >= arr.length() {
obj
} else {
let updated = apply_update(arr[idx], right, upd)
let new_arr = arr.copy()
new_arr[idx] = updated
Json::array(new_arr)
}
_ => obj
}
_ =>
match eval_with_env(left, obj, env).collect() {
[navigated, ..] => apply_update(navigated, right, upd)
[] => obj
}
}
_ =>
match eval_with_env(p, obj, env).collect() {
[current, ..] =>
match eval_with_env(upd, current, env).collect() {
[updated, ..] => updated
[] => obj
}
[] => obj
}
}
}
Iter::singleton(apply_update(input, path, update_expr))
}