microcad_lang/eval/
function.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! µcad Function call evaluation
5
6use crate::{eval::*, syntax::*, value::*};
7
8impl Eval for FunctionDefinition {
9    fn eval(&self, context: &mut Context) -> EvalResult<Value> {
10        context.grant(self)?;
11        context.scope(StackFrame::Function(Default::default()), |_context| {
12            /*
13
14            TODO: This whole thing is not working proper because statements can
15                  have other statements inside. Thinking about if clauses every path
16                  must be checked instead of just the top statements.
17
18            // check if there is any return statement
19            if !self
20                .body
21                .statements
22                .iter()
23                .any(|s| matches!(&s, Statement::Return(..)))
24            {
25                context.error(
26                    &self.body,
27                    EvalError::MissingReturn(context.current_name().with_suffix(self.id.clone())),
28                )?
29            }
30            */
31            // avoid body frame
32            Ok(Value::None)
33        })
34    }
35}
36
37impl CallTrait for FunctionDefinition {
38    fn call(&self, args: &ArgumentValueList, context: &mut Context) -> EvalResult<Value> {
39        match ArgumentMatch::find_multi_match(args, &self.signature.parameters.eval(context)?) {
40            Ok(matches) => {
41                let mut result: Vec<Value> = Vec::new();
42                for args in matches {
43                    result.push(context.scope(StackFrame::Function(args.into()), |context| {
44                        self.body.statements.eval(context)
45                    })?);
46                }
47                if result.len() == 1 {
48                    Ok(result.first().expect("one result item").clone())
49                } else {
50                    Ok(Value::Array(result.into_iter().collect()))
51                }
52            }
53
54            Err(err) => {
55                context.error(args, err)?;
56                Ok(Value::None)
57            }
58        }
59    }
60}