rustleaf 0.1.0

A simple programming language interpreter written in Rust
Documentation
use crate::core::{RustValue, Value};
use crate::eval::{ControlFlow, ErrorKind, EvalResult, Evaluator};

#[derive(Debug, Clone)]
pub struct EvalFor {
    pub var_name: String,
    pub iter_expr: Value,
    pub body: Value,
}

#[crate::rust_value_any]
impl RustValue for EvalFor {
    fn dyn_clone(&self) -> Box<dyn RustValue> {
        Box::new(self.clone())
    }
    fn eval(&self, evaluator: &mut Evaluator) -> anyhow::Result<EvalResult> {
        let iter_value = match self.iter_expr.eval(evaluator)? {
            Ok(val) => val,
            Err(e) => return Ok(Err(e)),
        };

        let loop_scope = evaluator.current_env.child();
        let previous_env = std::mem::replace(&mut evaluator.current_env, loop_scope);

        let mut result = Value::Unit;

        let mut iterator = match iter_value.op_iter() {
            Ok(iter) => iter,
            Err(e) => {
                evaluator.current_env = previous_env;
                return Ok(Err(ControlFlow::Error(ErrorKind::SystemError(e))));
            }
        };

        loop {
            let next_item = match iterator.op_next() {
                Ok(item) => item,
                Err(e) => {
                    evaluator.current_env = previous_env;
                    return Ok(Err(ControlFlow::Error(ErrorKind::SystemError(e))));
                }
            };

            match next_item {
                Some(item) => {
                    evaluator.current_env.define(&self.var_name, item);

                    match self.body.eval(evaluator)? {
                        Ok(_) => {}
                        Err(ControlFlow::Break(value)) => {
                            result = value;
                            break;
                        }
                        Err(ControlFlow::Continue) => continue,
                        Err(other) => {
                            evaluator.current_env = previous_env;
                            return Ok(Err(other));
                        }
                    }
                }
                None => break,
            }
        }

        evaluator.current_env = previous_env;
        Ok(Ok(result))
    }

    fn str(&self) -> String {
        format!(
            "for {} in {} {}",
            self.var_name,
            self.iter_expr.str(),
            self.body.str()
        )
    }
}