microcad_lang/eval/call/
call_method.rs1use microcad_lang_base::{PushDiag, SrcRef};
7
8use crate::{eval::*, lower::ir, model::Model, symbol::SymbolDef};
9
10pub trait CallMethod<T = Value> {
12 fn call_method(
18 &self,
19 id: &ir::QualifiedName,
20 args: &ArgumentValueList,
21 context: &mut EvalContext,
22 ) -> EvalResult<T>;
23}
24
25impl CallMethod for Array {
26 fn call_method(
27 &self,
28 id: &ir::QualifiedName,
29 _: &ArgumentValueList,
30 context: &mut EvalContext,
31 ) -> EvalResult<Value> {
32 use crate::lower::SingleIdentifier;
33
34 Ok(
35 match id.single_identifier().expect("Single id").id().as_str() {
36 "count" => self.len().into(),
37 "first" | "head" => self.first(), "last" => self.last(),
39 "tail" => self.tail().into(),
40 "rev" => self.rev().into(),
41 "sorted" => self.sorted().into(),
42 "all_equal" => self.all_equal().into(),
43 "is_ascending" => self.is_ascending().into(),
44 "is_descending" => self.is_descending().into(),
45 _ => {
46 context.error(id, EvalError::UnknownMethod(id.clone()))?;
47 Value::None
48 }
49 },
50 )
51 }
52}
53
54impl CallMethod<Option<Model>> for Model {
55 fn call_method(
56 &self,
57 name: &ir::QualifiedName,
58 args: &ArgumentValueList,
59 context: &mut EvalContext,
60 ) -> EvalResult<Option<Model>> {
61 match context.lookup(name, LookupTarget::Method) {
62 Ok(symbol) => context.scope(
63 StackFrame::Call {
64 symbol: symbol.clone(),
65 args: args.clone(),
66 src_ref: SrcRef::merge(name, args),
67 },
68 |context| {
69 symbol.with_def(|def| match def {
70 SymbolDef::Workbench(workbench_definition) => {
71 let model = workbench_definition.call(
72 SrcRef::merge(name, args),
73 symbol.clone(),
74 args,
75 context,
76 )?;
77
78 Ok::<_, Box<EvalError>>(Some(model.replace_input_placeholders(self)))
79 }
80 SymbolDef::Builtin(builtin) => match builtin.call(args, context)? {
81 Value::Model(model) => Ok(Some(model.replace_input_placeholders(self))),
82 value => panic!("Builtin call returned {value} but no models."),
83 },
84 _ => {
85 context.error(name, EvalError::SymbolCannotBeCalled(name.clone()))?;
86 Ok(None)
87 }
88 })
89 },
90 ),
91 Err(err) => {
92 context.error(name, err)?;
93 Ok(None)
94 }
95 }
96 }
97}
98
99impl CallMethod for Value {
100 fn call_method(
101 &self,
102 id: &ir::QualifiedName,
103 args: &ArgumentValueList,
104 context: &mut EvalContext,
105 ) -> EvalResult<Value> {
106 match self {
107 Value::Integer(_) => eval_todo!(context, id, "call_method for Integer"),
108 Value::Quantity(_) => eval_todo!(context, id, "call_method for Quantity"),
109 Value::Bool(_) => eval_todo!(context, id, "call_method for Bool"),
110 Value::String(_) => eval_todo!(context, id, "call_method for String"),
111 Value::Tuple(_) => eval_todo!(context, id, "call_method for Tuple"),
112 Value::Matrix(_) => eval_todo!(context, id, "call_method for Matrix"),
113 Value::Array(array) => array.call_method(id, args, context),
114 Value::Model(model) => Ok(model
115 .call_method(id, args, context)?
116 .map(Value::Model)
117 .unwrap_or_default()),
118 _ => {
119 context.error(id, EvalError::UnknownMethod(id.clone()))?;
120 Ok(Value::None)
121 }
122 }
123 }
124}