mf_expression/functions/
defs.rs1use crate::functions::arguments::Arguments;
2use crate::variable::VariableType;
3use crate::Variable;
4use std::collections::HashSet;
5use std::rc::Rc;
6
7pub trait FunctionDefinition {
8 fn required_parameters(&self) -> usize;
9 fn optional_parameters(&self) -> usize;
10 fn check_types(
11 &self,
12 args: &[VariableType],
13 ) -> FunctionTypecheck;
14 fn call(
15 &self,
16 args: Arguments,
17 ) -> anyhow::Result<Variable>;
18 fn param_type(
19 &self,
20 index: usize,
21 ) -> Option<VariableType>;
22 fn param_type_str(
23 &self,
24 index: usize,
25 ) -> String;
26 fn return_type(&self) -> VariableType;
27 fn return_type_str(&self) -> String;
28}
29
30#[derive(Debug, Default)]
31pub struct FunctionTypecheck {
32 pub general: Option<String>,
33 pub arguments: Vec<(usize, String)>,
34 pub return_type: VariableType,
35}
36
37#[derive(Clone)]
38pub struct FunctionSignature {
39 pub parameters: Vec<VariableType>,
40 pub return_type: VariableType,
41}
42
43impl FunctionSignature {
44 pub fn single(
45 parameter: VariableType,
46 return_type: VariableType,
47 ) -> Self {
48 Self { parameters: vec![parameter], return_type }
49 }
50}
51
52#[derive(Clone)]
53pub struct StaticFunction {
54 pub signature: FunctionSignature,
55 pub implementation: Rc<dyn Fn(Arguments) -> anyhow::Result<Variable>>,
56}
57
58impl FunctionDefinition for StaticFunction {
59 fn required_parameters(&self) -> usize {
60 self.signature.parameters.len()
61 }
62
63 fn optional_parameters(&self) -> usize {
64 0
65 }
66
67 fn check_types(
68 &self,
69 args: &[VariableType],
70 ) -> FunctionTypecheck {
71 let mut typecheck = FunctionTypecheck::default();
72 typecheck.return_type = self.signature.return_type.clone();
73
74 if args.len() != self.required_parameters() {
75 typecheck.general = Some(format!(
76 "Expected `{}` arguments, got `{}`.",
77 self.required_parameters(),
78 args.len()
79 ));
80 }
81
82 for (i, (arg, expected_type)) in
84 args.iter().zip(self.signature.parameters.iter()).enumerate()
85 {
86 if !arg.satisfies(expected_type) {
87 typecheck.arguments.push((
88 i,
89 format!(
90 "Argument of type `{arg}` is not assignable to parameter of type `{expected_type}`.",
91 ),
92 ));
93 }
94 }
95
96 typecheck
97 }
98
99 fn call(
100 &self,
101 args: Arguments,
102 ) -> anyhow::Result<Variable> {
103 (&self.implementation)(args)
104 }
105
106 fn param_type(
107 &self,
108 index: usize,
109 ) -> Option<VariableType> {
110 self.signature.parameters.get(index).cloned()
111 }
112
113 fn param_type_str(
114 &self,
115 index: usize,
116 ) -> String {
117 self.signature
118 .parameters
119 .get(index)
120 .map(|x| x.to_string())
121 .unwrap_or_else(|| "never".to_string())
122 }
123
124 fn return_type(&self) -> VariableType {
125 self.signature.return_type.clone()
126 }
127
128 fn return_type_str(&self) -> String {
129 self.signature.return_type.to_string()
130 }
131}
132
133#[derive(Clone)]
134pub struct CompositeFunction {
135 pub signatures: Vec<FunctionSignature>,
136 pub implementation: Rc<dyn Fn(Arguments) -> anyhow::Result<Variable>>,
137}
138
139impl FunctionDefinition for CompositeFunction {
140 fn required_parameters(&self) -> usize {
141 self.signatures.iter().map(|x| x.parameters.len()).min().unwrap_or(0)
142 }
143
144 fn optional_parameters(&self) -> usize {
145 let required_params = self.required_parameters();
146 let max = self
147 .signatures
148 .iter()
149 .map(|x| x.parameters.len())
150 .max()
151 .unwrap_or(0);
152
153 max - required_params
154 }
155
156 fn check_types(
157 &self,
158 args: &[VariableType],
159 ) -> FunctionTypecheck {
160 let mut typecheck = FunctionTypecheck::default();
161 if self.signatures.is_empty() {
162 typecheck.general = Some("No implementation".to_string());
163 return typecheck;
164 }
165
166 let required_params = self.required_parameters();
167 let optional_params = self.optional_parameters();
168 let total_params = required_params + optional_params;
169
170 if args.len() < required_params || args.len() > total_params {
171 typecheck.general = Some(format!(
172 "Expected `{required_params} - {total_params}` arguments, got `{}`.",
173 args.len()
174 ))
175 }
176
177 for signature in &self.signatures {
178 let all_match = args
179 .iter()
180 .zip(signature.parameters.iter())
181 .all(|(arg, param)| arg.satisfies(param));
182 if all_match {
183 typecheck.return_type = signature.return_type.clone();
184 return typecheck;
185 }
186 }
187
188 for (i, arg) in args.iter().enumerate() {
189 let possible_types: Vec<&VariableType> = self
190 .signatures
191 .iter()
192 .filter_map(|sig| sig.parameters.get(i))
193 .collect();
194
195 if !possible_types.iter().any(|param| arg.satisfies(param)) {
196 let type_union = self.param_type_str(i);
197 typecheck.arguments.push((
198 i,
199 format!(
200 "Argument of type `{arg}` is not assignable to parameter of type `{type_union}`.",
201 ),
202 ))
203 }
204 }
205
206 let available_signatures = self
207 .signatures
208 .iter()
209 .map(|sig| {
210 let param_list = sig
211 .parameters
212 .iter()
213 .map(|x| x.to_string())
214 .collect::<Vec<_>>()
215 .join(", ");
216 format!("`({param_list}) -> {}`", sig.return_type)
217 })
218 .collect::<Vec<_>>()
219 .join("\n");
220 typecheck.general = Some(format!(
221 "No function overload matches provided arguments. Available overloads:\n{available_signatures}"
222 ));
223
224 typecheck
225 }
226
227 fn call(
228 &self,
229 args: Arguments,
230 ) -> anyhow::Result<Variable> {
231 (&self.implementation)(args)
232 }
233
234 fn param_type(
235 &self,
236 index: usize,
237 ) -> Option<VariableType> {
238 self.signatures
239 .iter()
240 .filter_map(|sig| sig.parameters.get(index))
241 .cloned()
242 .reduce(|a, b| a.merge(&b))
243 }
244
245 fn param_type_str(
246 &self,
247 index: usize,
248 ) -> String {
249 let possible_types: Vec<String> = self
250 .signatures
251 .iter()
252 .filter_map(|sig| sig.parameters.get(index))
253 .map(|x| x.to_string())
254 .collect();
255 if possible_types.is_empty() {
256 return String::from("never");
257 }
258
259 let is_optional = possible_types.len() != self.signatures.len();
260 let possible_types: Vec<String> = possible_types
261 .into_iter()
262 .collect::<HashSet<_>>()
263 .into_iter()
264 .collect();
265
266 let type_union = possible_types.join(" | ");
267 if is_optional {
268 return format!("Optional<{type_union}>");
269 }
270
271 type_union
272 }
273
274 fn return_type(&self) -> VariableType {
275 self.signatures
276 .iter()
277 .map(|sig| &sig.return_type)
278 .cloned()
279 .reduce(|a, b| a.merge(&b))
280 .unwrap_or(VariableType::Null)
281 }
282
283 fn return_type_str(&self) -> String {
284 let possible_types: Vec<String> = self
285 .signatures
286 .iter()
287 .map(|sig| sig.return_type.clone())
288 .map(|x| x.to_string())
289 .collect();
290 if possible_types.is_empty() {
291 return String::from("never");
292 }
293
294 possible_types
295 .into_iter()
296 .collect::<HashSet<_>>()
297 .into_iter()
298 .collect::<Vec<_>>()
299 .join(" | ")
300 }
301}