use crate::core::RustValue;
use crate::eval::{ControlFlow, ErrorKind, EvalResult, Evaluator};
use anyhow::anyhow;
#[derive(Debug, Clone)]
pub struct EvalMatch {
pub data: super::eval_ref::MatchData,
}
#[crate::rust_value_any]
impl RustValue for EvalMatch {
fn dyn_clone(&self) -> Box<dyn RustValue> {
Box::new(self.clone())
}
fn eval(&self, evaluator: &mut Evaluator) -> anyhow::Result<EvalResult> {
let match_value = match self.data.expr.eval(evaluator)? {
Ok(val) => val,
Err(e) => return Ok(Err(e)),
};
for case in &self.data.cases {
match evaluator.match_pattern_matches(&case.pattern, &match_value) {
Ok(true) => {
if let Some(guard) = &case.guard {
let guard_result = match guard.eval(evaluator)? {
Ok(val) => val,
Err(e) => return Ok(Err(e)),
};
if !guard_result.is_truthy() {
continue;
}
}
if let super::eval_ref::EvalMatchPattern::Variable(var_name) = &case.pattern {
evaluator.current_env.define(var_name.clone(), match_value);
}
return case.body.eval(evaluator);
}
Ok(false) => continue,
Err(e) => return Ok(Err(e)),
}
}
Ok(Err(ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"No pattern matched in match expression"
)))))
}
fn str(&self) -> String {
let cases_str = self
.data
.cases
.iter()
.map(|case| format!("{:?} => {}", case.pattern, case.body.str()))
.collect::<Vec<_>>()
.join(", ");
format!("match {} {{ {} }}", self.data.expr.str(), cases_str)
}
}