mf_expression/functions/
defs.rs

1use 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        // Check each parameter type
83        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}