Skip to main content

microcad_lang/eval/call/
mod.rs

1// Copyright © 2024-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! µcad Call related evaluation entities
5
6#[macro_use]
7mod argument;
8mod argument_value;
9mod argument_value_list;
10mod call_method;
11mod call_trait;
12
13pub use argument_value::ArgumentValue;
14pub use argument_value_list::ArgumentValueList;
15pub use call_method::*;
16pub use call_trait::*;
17use microcad_lang_base::{Identifier, SrcReferrer};
18
19use crate::{eval::*, lower::ir, symbol::SymbolDef, value::*};
20
21impl Eval<ArgumentValueList> for ir::ArgumentList {
22    /// Evaluate into a [`ArgumentValueList`].
23    fn eval(&self, context: &mut EvalContext) -> EvalResult<ArgumentValueList> {
24        self.iter()
25            .map(|arg| {
26                (
27                    arg.id.clone().unwrap_or(Identifier::none()),
28                    arg.eval(context),
29                )
30            })
31            .map(|(id, arg)| match arg {
32                Ok(arg) => Ok((id.clone(), arg)),
33                Err(err) => Err(err),
34            })
35            .collect()
36    }
37}
38
39impl Eval for ir::Call {
40    fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
41        // find self in symbol table by own name
42        let symbol = match context.lookup(&self.name, LookupTarget::Function) {
43            Ok(symbol) => symbol,
44            Err(err) => {
45                context.error(self, err)?;
46                return Ok(Value::None);
47            }
48        };
49
50        // evaluate arguments
51        let args: ArgumentValueList = self.argument_list.eval(context)?;
52
53        log::debug!(
54            "{call} {name:?}({args:?})",
55            name = self.name,
56            call = microcad_lang_base::mark!(CALL),
57        );
58
59        match context.scope(
60            StackFrame::Call {
61                symbol: symbol.clone(),
62                args: args.clone(),
63                src_ref: self.src_ref(),
64            },
65            |context| {
66                symbol.with_def(|def| match def {
67                    SymbolDef::Builtin(f) => f.call(&args, context),
68                    SymbolDef::Workbench(w) => {
69                        if matches!(*w.kind, ir::WorkbenchKind::Operation) {
70                            context.error(self, EvalError::CannotCallOperationWithoutWorkpiece)?;
71                            Ok(Value::None)
72                        } else {
73                            Ok(Value::Model(w.call(
74                                self.src_ref(),
75                                symbol.clone(),
76                                &args,
77                                context,
78                            )?))
79                        }
80                    }
81                    SymbolDef::Function(f) => f.call(&args, context),
82                    _ => {
83                        context.error(self, EvalError::SymbolCannotBeCalled(symbol.full_name()))?;
84                        Ok(Value::None)
85                    }
86                })
87            },
88        ) {
89            Ok(value) => Ok(value),
90            Err(err) => {
91                context.error(self, err)?;
92                Ok(Value::None)
93            }
94        }
95    }
96}