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}