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 EvalContext) -> EvalResult<ArgumentValueList> {
21 self.iter()
22 .map(|arg| {
23 (
24 arg.id.clone().unwrap_or(Identifier::none()),
25 arg.eval(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
36pub struct ArgumentValueListRaw(ArgumentValueList);
41
42impl From<ArgumentValueListRaw> for ArgumentValueList {
43 fn from(value: ArgumentValueListRaw) -> Self {
44 value.0
45 }
46}
47
48impl Eval<ArgumentValueListRaw> for ArgumentList {
49 fn eval(&self, context: &mut EvalContext) -> EvalResult<ArgumentValueListRaw> {
51 let arguments = self
52 .iter()
53 .map(|arg| {
54 (
55 arg.id.clone().unwrap_or(Identifier::none()),
56 if let Expression::QualifiedName(name) = &arg.expression {
57 Ok(ArgumentValue::new(
58 Value::Target(Target::new(
59 name.un_super(),
60 match context.lookup(name, LookupTarget::Any) {
61 Ok(symbol) => Some(symbol.full_name()),
62 Err(_) => None,
63 },
64 )),
65 arg.id.clone(),
66 arg.src_ref.clone(),
67 ))
68 } else {
69 arg.eval(context)
70 },
71 )
72 })
73 .map(|(id, arg)| match arg {
74 Ok(arg) => Ok((id.clone(), arg)),
75 Err(err) => Err(err),
76 })
77 .collect::<EvalResult<_>>()?;
78
79 Ok(ArgumentValueListRaw(arguments))
80 }
81}
82
83impl Eval for Call {
84 fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
85 let symbol = match context.lookup(&self.name, LookupTarget::Function) {
87 Ok(symbol) => symbol,
88 Err(err) => {
89 context.error(self, err)?;
90 return Ok(Value::None);
91 }
92 };
93
94 let args: ArgumentValueList = if symbol.is_target_mode() {
96 Eval::<ArgumentValueListRaw>::eval(&self.argument_list, context)?.into()
98 } else {
99 self.argument_list.eval(context)?
100 };
101
102 log::debug!(
103 "{call} {name:?}({args:?})",
104 name = self.name,
105 call = crate::mark!(CALL),
106 );
107
108 match context.scope(
109 StackFrame::Call {
110 symbol: symbol.clone(),
111 args: args.clone(),
112 src_ref: self.src_ref(),
113 },
114 |context| {
115 symbol.with_def(|def| match def {
116 SymbolDef::Builtin(f) => f.call(&args, context),
117 SymbolDef::Workbench(w) => {
118 if matches!(*w.kind, WorkbenchKind::Operation) {
119 context.error(self, EvalError::CannotCallOperationWithoutWorkpiece)?;
120 Ok(Value::None)
121 } else {
122 Ok(Value::Model(w.call(
123 self.src_ref(),
124 symbol.clone(),
125 &args,
126 context,
127 )?))
128 }
129 }
130 SymbolDef::Function(f) => f.call(&args, context),
131 _ => {
132 context.error(self, EvalError::SymbolCannotBeCalled(symbol.full_name()))?;
133 Ok(Value::None)
134 }
135 })
136 },
137 ) {
138 Ok(value) => Ok(value),
139 Err(err) => {
140 context.error(self, err)?;
141 Ok(Value::None)
142 }
143 }
144 }
145}
146
147#[derive(Error, Debug)]
149pub enum MatchError {
150 #[error("Duplicated argument: {0}")]
152 DuplicatedArgument(Identifier),
153 #[error("Parameter `{0}` is not defined.")]
155 ParameterNotDefined(Identifier),
156 #[error("Type mismatch for parameter `{0}`: expected `{1}`, got {2}")]
158 PositionalArgumentTypeMismatch(Identifier, Type, Type),
159 #[error("Missing parameter: {0}")]
161 MissingParameter(Identifier),
162}