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