use crate::core::{Args, RustValue};
use crate::eval::{ControlFlow, ErrorKind, EvalResult, Evaluator};
use super::eval_ref::WithData;
#[derive(Debug, Clone)]
pub struct EvalWith {
pub data: WithData,
}
#[crate::rust_value_any]
impl RustValue for EvalWith {
fn dyn_clone(&self) -> Box<dyn RustValue> {
Box::new(self.clone())
}
fn eval(&self, evaluator: &mut Evaluator) -> anyhow::Result<EvalResult> {
let mut resources = Vec::new();
for (resource_name, resource_expr) in &self.data.resources {
let resource_value = match resource_expr.eval(evaluator)? {
Ok(val) => val,
Err(e) => {
evaluator.cleanup_resources(&resources);
return Ok(Err(e));
}
};
let open_method = resource_value.get_attr("op_open", evaluator);
if let Some(open_method) = open_method {
let args = Args::positional(vec![]);
if let Err(e) = open_method.call(args) {
evaluator.cleanup_resources(&resources);
return Ok(Err(ControlFlow::Error(ErrorKind::SystemError(e))));
}
}
evaluator
.current_env
.define(resource_name.clone(), resource_value.clone());
resources.push((resource_name.clone(), resource_value));
}
let body_result = self.data.body.eval(evaluator)?;
evaluator.cleanup_resources(&resources);
Ok(body_result)
}
fn str(&self) -> String {
let resources_str = self
.data
.resources
.iter()
.map(|(name, expr)| format!("{} = {}", name, expr.str()))
.collect::<Vec<_>>()
.join(", ");
format!("with {} {}", resources_str, self.data.body.str())
}
}