mumu 0.11.1

Lava Mumu is a language for those in the now and that know
Documentation
use crate::parser::ast::Expr;
use crate::parser::types::{Value, FunctionValue, LambdaParam};
use crate::parser::interpreter::Interpreter;
use crate::parser::interpreter::apply;
use super::helpers::err_with_pos;
use super::regex::eval_regex_literal;
use super::indexing::eval_index_expr;

impl Interpreter {
    pub fn eval_expression(&mut self, expr: &Expr) -> Result<Value, String> {
        use Expr::*;
        match expr {
            Number { value, .. } => Ok(Value::Int(*value)),
            NumberFloat { value, .. } => Ok(Value::Float(*value)),
            StrLit { value, .. } => Ok(Value::SingleString(value.clone())),
            Bool { value, .. } => Ok(Value::Bool(*value)),
            Ident { name, line, col } => {
                let v = self.lookup_variable(name)
                    .ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *line, *col))?;
                match v {
                    Value::Ref(arc_mutex) => Ok(arc_mutex.lock().unwrap().clone()),
                    v => Ok(v),
                }
            }
            Ref { expr: inner, line, col } => {
                match &**inner {
                    Expr::Ident { name, line: n_line, col: n_col } => {
                        let storage = self.lookup_variable_storage(name)
                            .ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *n_line, *n_col))?;
                        Ok(Value::Ref(storage))
                    }
                    _ => Err(err_with_pos("Can only take reference of a variable", *line, *col)),
                }
            }
            Placeholder { .. } => Ok(Value::Placeholder),
            BracketedArray { items, .. } => crate::parser::interpreter::utils::eval_bracketed_array(self, items),
            KeyedArray { pairs, .. } => crate::parser::interpreter::utils::eval_keyed_array(self, pairs),
            FunctionCall { callee, args, line, col } => {
                let callee_val = self.eval_expression(callee)?;
                // Special-case for lambdas with LambdaParam::Ref:
                if let Value::Function(fb) = &callee_val {
                    if let FunctionValue::InlineLambdaAST { params, .. } = &**fb {
                        let mut arg_vals = Vec::new();
                        for (i, a_expr) in args.iter().enumerate() {
                            let use_ref = params.get(i)
                                .map(|p| matches!(p, LambdaParam::Ref(_)))
                                .unwrap_or(false);
                            if use_ref {
                                // Only Expr::Ident can be passed as variable reference
                                if let Expr::Ident { name, line: v_line, col: v_col } = a_expr {
                                    let storage = self.lookup_variable_storage(name)
                                        .ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *v_line, *v_col))?;
                                    arg_vals.push(Value::Ref(storage));
                                } else {
                                    // fallback: just evaluate as value and wrap as new Ref
                                    let v = self.eval_expression(a_expr)?;
                                    arg_vals.push(Value::Ref(std::sync::Arc::new(std::sync::Mutex::new(v))));
                                }
                            } else {
                                arg_vals.push(self.eval_expression(a_expr)?);
                            }
                        }
                        return apply::apply_n_ary_function_value(self, fb.clone(), arg_vals);
                    }
                }
                // Otherwise, classic behavior
                let mut arg_vals = Vec::new();
                for a_expr in args {
                    arg_vals.push(self.eval_expression(a_expr)?);
                }
                match callee_val {
                    Value::Function(fb) => apply::apply_n_ary_function_value(self, fb, arg_vals),
                    Value::InkTransform(fb) => apply::apply_n_ary_function_value(self, fb, arg_vals),
                    Value::Stream(sh) => {
                        Err(err_with_pos(format!("Cannot call a Stream as a function: stream_id={}", sh.stream_id), *line, *col))
                    }
                    other => Err(err_with_pos(format!("Cannot call non-function: {:?}", other), *line, *col)),
                }
            }
            Index { base, index, .. } => {
                let base_val = self.eval_expression(base)?;
                let idx_val = self.eval_expression(index)?;
                eval_index_expr(self, base_val, idx_val)
            }
            Gt { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_gt(lv, rv)
            }
            Lt { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_lt(lv, rv)
            }
            EqEq { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_eqeq(lv, rv)
            }
            Le { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_le(lv, rv)
            }
            Ge { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_ge(lv, rv)
            }
            Add { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_add(lv, rv)
            }
            Sub { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_sub(lv, rv)
            }
            Mul { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_mul(lv, rv)
            }
            Div { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_div(lv, rv)
            }
            Mod { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_mod(lv, rv)
            }
            Ternary { cond, if_true, if_false, .. } => {
                let cval = self.eval_expression(cond)?;
                match cval {
                    Value::Bool(flag) => {
                        if flag {
                            self.eval_expression(if_true)
                        } else {
                            self.eval_expression(if_false)
                        }
                    }
                    Value::Int(i) => {
                        if i == 0 {
                            self.eval_expression(if_false)
                        } else {
                            self.eval_expression(if_true)
                        }
                    }
                    Value::Float(f) => {
                        if f == 0.0 {
                            self.eval_expression(if_false)
                        } else {
                            self.eval_expression(if_true)
                        }
                    }
                    Value::Long(l) => {
                        if l == 0 {
                            self.eval_expression(if_false)
                        } else {
                            self.eval_expression(if_true)
                        }
                    }
                    _ => Err(err_with_pos("Ternary condition must be bool/int/float/long", 0, 0)),
                }
            }
            InlineLambdaAST { params, body, .. } => {
                let fv = FunctionValue::InlineLambdaAST {
                    params: params.clone(),
                    body_expr: body.clone(),
                };
                Ok(Value::Function(Box::new(fv)))
            }
            Block { stmts, .. } => {
                self.push_scope();
                let mut last_val = Value::Bool(true);
                for s in stmts {
                    let v = self.exec_statement(s)?;
                    last_val = v;
                }
                self.pop_scope();
                Ok(last_val)
            }
            UnaryMinus { expr: subexpr, .. } => {
                let val = self.eval_expression(subexpr)?;
                match val {
                    Value::Int(i) => i.checked_neg()
                        .map(Value::Int)
                        .ok_or_else(|| err_with_pos("Overflow in unary minus", 0, 0)),
                    Value::Long(l) => l.checked_neg()
                        .map(Value::Long)
                        .ok_or_else(|| err_with_pos("Overflow in unary minus (long)", 0, 0)),
                    Value::Float(ff) => Ok(Value::Float(-ff)),
                    other => Err(err_with_pos(format!("Cannot apply unary minus to {:?}", other), 0, 0)),
                }
            }
            AndAnd { left, right, .. } => {
                let left_val = self.eval_expression(left)?;
                let left_truth = crate::parser::interpreter::utils::bool_like(&left_val)?;
                if !left_truth {
                    Ok(Value::Bool(false))
                } else {
                    let right_val = self.eval_expression(right)?;
                    let right_truth = crate::parser::interpreter::utils::bool_like(&right_val)?;
                    Ok(Value::Bool(right_truth))
                }
            }
            UnaryNot { expr: subexpr, .. } => {
                let val = self.eval_expression(subexpr)?;
                let truth = crate::parser::interpreter::utils::bool_like(&val)?;
                Ok(Value::Bool(!truth))
            }
            Ne { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_ne(lv, rv)
            }
            BitAnd { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bitand(lv, rv)
            }
            OrOr { left, right, .. } => {
                let left_val = self.eval_expression(left)?;
                let left_truth = crate::parser::interpreter::utils::bool_like(&left_val)?;
                if left_truth {
                    Ok(Value::Bool(true))
                } else {
                    let right_val = self.eval_expression(right)?;
                    let right_truth = crate::parser::interpreter::utils::bool_like(&right_val)?;
                    Ok(Value::Bool(right_truth))
                }
            }
            Shl { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_shl(lv, rv)
            }
            Shr { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_shr(lv, rv)
            }
            BitXor { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bitxor(lv, rv)
            }
            BitTilde { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bittilde(lv, rv)
            }
            BitOr { left, right, .. } => {
                let lv = self.eval_expression(left)?;
                let rv = self.eval_expression(right)?;
                self.eval_bitor(lv, rv)
            }
            // Regex Literal
            RegexLit { pattern, flags, line, col } => {
                eval_regex_literal(pattern, flags, *line, *col)
            }
        }
    }
}