use reddb_io_toon::Value;
use super::ast::{AssignOp, BinaryOp, Expr};
use super::eval::{self, Env};
use super::paths;
enum Update<'a> {
Filter(&'a Expr),
Binary(BinaryOp, Value),
Alternative(Value),
}
pub(super) fn evaluate(
operator: AssignOp,
target: &Expr,
source: &Expr,
input: &Value,
env: &Env,
) -> Result<Vec<Value>, String> {
let selected = paths::locate(target, input, env)?
.into_iter()
.map(|located| located.path)
.collect::<Vec<_>>();
match operator {
AssignOp::Update => modify(input, &selected, &Update::Filter(source), env).map(|v| vec![v]),
AssignOp::Set => source
.eval(input, env)?
.iter()
.map(|value| set_all(input, &selected, value))
.collect(),
AssignOp::Arithmetic(binary) => source
.eval(input, env)?
.into_iter()
.map(|value| modify(input, &selected, &Update::Binary(binary, value), env))
.collect(),
AssignOp::Alternative => source
.eval(input, env)?
.into_iter()
.map(|value| modify(input, &selected, &Update::Alternative(value), env))
.collect(),
}
}
fn set_all(input: &Value, selected: &[Vec<Value>], value: &Value) -> Result<Value, String> {
let mut result = input.clone();
for path in selected {
result = paths::set_path(&result, path, value)?;
}
Ok(result)
}
fn modify(
input: &Value,
selected: &[Vec<Value>],
update: &Update<'_>,
env: &Env,
) -> Result<Value, String> {
let mut result = input.clone();
let mut deleted = Vec::new();
for path in selected {
let current = paths::get_path(&result, path)?;
match update.apply(¤t, env)? {
Some(value) => result = paths::set_path(&result, path, &value)?,
None => deleted.push(path.clone()),
}
}
if deleted.is_empty() {
return Ok(result);
}
paths::delete_all(&result, deleted)
}
impl Update<'_> {
fn apply(&self, current: &Value, env: &Env) -> Result<Option<Value>, String> {
match self {
Self::Filter(filter) => Ok(filter.eval(current, env)?.into_iter().next()),
Self::Binary(operator, value) => {
eval::evaluate_binary(*operator, current, value).map(Some)
}
Self::Alternative(value) => Ok(Some(if eval::is_truthy(current) {
current.clone()
} else {
value.clone()
})),
}
}
}