microcad_lang/eval/call/
mod.rs1#[macro_use]
7mod argument;
8mod call_method;
9mod call_trait;
10
11pub use call_method::*;
12pub use call_trait::*;
13
14use crate::{eval::*, syntax::*, value::*};
15
16use thiserror::Error;
17
18impl Eval<ArgumentValueList> for ArgumentList {
19 fn eval(&self, context: &mut Context) -> EvalResult<ArgumentValueList> {
21 self.iter()
22 .map(|arg| {
23 (
24 arg.id.clone().unwrap_or(Identifier::none()),
25 arg.eval_value(context),
26 )
27 })
28 .map(|(id, arg)| match arg {
29 Ok(arg) => Ok((id.clone(), arg)),
30 Err(err) => Err(err),
31 })
32 .collect()
33 }
34}
35
36impl Eval for Call {
37 fn eval(&self, context: &mut Context) -> EvalResult<Value> {
38 let symbol = match context.lookup(&self.name) {
40 Ok(symbol) => symbol,
41 Err(err) => {
42 context.error(self, err)?;
43 return Ok(Value::None);
44 }
45 };
46
47 let args = match self.argument_list.eval(context) {
49 Ok(args) => args,
50 Err(err) => {
51 if matches!(symbol.borrow().def, SymbolDefinition::Builtin(..)) {
55 self.argument_list
56 .iter()
57 .map(|arg| match context.source_code(&arg.value) {
58 Ok(code) => Ok((
59 arg.id.clone().unwrap_or(Identifier::none()),
60 ArgumentValue::new(
61 code.into(),
62 arg.id.clone(),
63 arg.src_ref.clone(),
64 ),
65 )),
66 Err(err) => Err(err),
67 })
68 .collect::<EvalResult<ArgumentValueList>>()?
69 } else {
70 Err(err)?
71 }
72 }
73 };
74
75 log::debug!(
76 "{call} {name}({args})",
77 name = self.name,
78 call = crate::mark!(CALL),
79 );
80
81 match context.scope(
82 StackFrame::Call {
83 symbol: symbol.clone(),
84 args: args.clone(),
85 src_ref: self.src_ref(),
86 },
87 |context| match &symbol.borrow().def {
88 SymbolDefinition::Builtin(f) => f.call(&args, context),
89 SymbolDefinition::Workbench(w) => {
90 if matches!(*w.kind, WorkbenchKind::Operation) {
91 context.error(self, EvalError::CannotCallOperationWithoutWorkpiece)?;
92 Ok(Value::None)
93 } else {
94 Ok(Value::Model(w.call(
95 self.src_ref(),
96 symbol.clone(),
97 &args,
98 context,
99 )?))
100 }
101 }
102 SymbolDefinition::Function(f) => f.call(&args, context),
103 def => {
104 context.error(
105 self,
106 EvalError::SymbolCannotBeCalled(symbol.full_name(), Box::new(def.clone())),
107 )?;
108 Ok(Value::None)
109 }
110 },
111 ) {
112 Ok(value) => Ok(value),
113 Err(err) => {
114 context.error(self, err)?;
115 Ok(Value::None)
116 }
117 }
118 }
119}
120
121#[derive(Error, Debug)]
123pub enum MatchError {
124 #[error("Duplicated argument: {0}")]
126 DuplicatedArgument(Identifier),
127 #[error("Parameter `{0}` is not defined.")]
129 ParameterNotDefined(Identifier),
130 #[error("Type mismatch for parameter `{0}`: expected `{1}`, got {2}")]
132 PositionalArgumentTypeMismatch(Identifier, Type, Type),
133 #[error("Missing parameter: {0}")]
135 MissingParameter(Identifier),
136}