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}