rimu-eval 0.2.0

A data structure template system.
Documentation
use std::{cell::RefCell, rc::Rc};

use rimu_meta::Span;
use rimu_value::{Environment, Function, FunctionBody, SpannedValue};

use crate::{evaluate_block, evaluate_expression, EvalError, Result};

pub fn call(span: Span, function: Function, args: &[SpannedValue]) -> Result<SpannedValue> {
    if let FunctionBody::Native(native) = function.body {
        for index in 0..function.args.len() {
            if args.get(index).is_none() {
                return Err(EvalError::MissingArgument {
                    span: span.clone(),
                    index,
                });
            }
        }
        return native.call(span, args);
    }

    let function_env = function.env.clone();
    let mut body_env = Environment::new_with_parent(function_env);

    let (args, _arg_spans): (Vec<_>, Vec<_>) = args.iter().map(|a| a.clone().take()).unzip();
    for index in 0..function.args.len() {
        let arg_name = function.args[index].clone();
        let arg_value = args.get(index).map(ToOwned::to_owned).map_or_else(
            || {
                Err(EvalError::MissingArgument {
                    span: span.clone(),
                    index,
                })
            },
            Ok,
        )?;
        body_env.insert(arg_name, arg_value);
    }

    let body_env = Rc::new(RefCell::new(body_env));

    let value = match &function.body {
        FunctionBody::Expression(expression) => evaluate_expression(expression, body_env)?,
        FunctionBody::Block(block) => evaluate_block(block, body_env)?,
        _ => unreachable!(),
    };
    Ok(value)
}