Skip to main content

geam_core/plan/module/expression/function/
external.rs

1use crate::plan::{
2    BoolExpr, CaptureArg, ConstantExternalFunctionInstantiation, CustomFieldAccess,
3    ExternalFunctionLocal, ExternalFunctionReference, ExternalFunctionType, ExternalValueShape,
4    FloatExpr, FunctionFunctionExpr, FunctionInstantiation, FunctionListExpr, FunctionType,
5    IntExpr, PanicExpr, Step, StringExpr, TupleExpr,
6};
7use ecow::EcoString;
8use num_bigint::BigInt;
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct ExternalFunctionExpr {
12    type_: ExternalFunctionType,
13    kind: ExternalFunctionExprKind,
14}
15
16#[derive(Debug, Clone, PartialEq)]
17pub(crate) enum ExternalFunctionExprKind {
18    Constant(ConstantExternalFunctionInstantiation),
19    Reference(ExternalFunctionReference),
20    Closure {
21        function: FunctionInstantiation,
22        captures: Vec<CaptureArg>,
23    },
24    LocalGet {
25        local: ExternalFunctionLocal,
26        name: EcoString,
27    },
28    Call {
29        function: FunctionInstantiation,
30        args: Vec<crate::plan::CallArg>,
31        site: crate::plan::HostCallSite,
32    },
33    FunctionCall {
34        function: Box<FunctionFunctionExpr>,
35        args: Vec<crate::plan::CallArg>,
36        site: crate::plan::HostCallSite,
37    },
38    TupleIndex {
39        tuple: Box<TupleExpr>,
40        index: usize,
41    },
42    CustomField(CustomFieldAccess),
43    ListIndex {
44        list: Box<FunctionListExpr>,
45        index: usize,
46    },
47    Panic(PanicExpr),
48    BoolCase {
49        subject: Box<BoolExpr>,
50        true_: Box<ExternalFunctionExprKind>,
51        false_: Box<ExternalFunctionExprKind>,
52    },
53    IntCase {
54        subject: Box<IntExpr>,
55        clauses: Vec<(BigInt, ExternalFunctionExprKind)>,
56        fallback: Box<ExternalFunctionExprKind>,
57    },
58    StringCase {
59        subject: Box<StringExpr>,
60        clauses: Vec<(EcoString, ExternalFunctionExprKind)>,
61        fallback: Box<ExternalFunctionExprKind>,
62    },
63    FloatCase {
64        subject: Box<FloatExpr>,
65        clauses: Vec<(f64, ExternalFunctionExprKind)>,
66        fallback: Box<ExternalFunctionExprKind>,
67    },
68    Block {
69        steps: Vec<Step>,
70        return_: Box<ExternalFunctionExprKind>,
71    },
72}
73
74impl ExternalFunctionExpr {
75    pub(crate) fn constant(
76        value: ConstantExternalFunctionInstantiation,
77        type_: ExternalFunctionType,
78    ) -> Self {
79        Self {
80            type_,
81            kind: ExternalFunctionExprKind::Constant(value),
82        }
83    }
84
85    pub(crate) fn reference(
86        value: ExternalFunctionReference,
87        return_shape: ExternalValueShape,
88    ) -> Self {
89        let type_ = ExternalFunctionType::from_shapes(
90            value.instantiation().shape().argument_shapes().to_vec(),
91            return_shape,
92        );
93        Self {
94            type_,
95            kind: ExternalFunctionExprKind::Reference(value),
96        }
97    }
98
99    pub(crate) fn closure(
100        function: FunctionInstantiation,
101        captures: Vec<CaptureArg>,
102        type_: ExternalFunctionType,
103    ) -> Self {
104        Self {
105            type_,
106            kind: ExternalFunctionExprKind::Closure { function, captures },
107        }
108    }
109
110    pub(crate) fn local_get(local: ExternalFunctionLocal, name: EcoString) -> Self {
111        let type_ = local.type_().clone();
112        Self {
113            type_,
114            kind: ExternalFunctionExprKind::LocalGet { local, name },
115        }
116    }
117
118    pub(crate) fn call_at(
119        function: FunctionInstantiation,
120        args: Vec<crate::plan::CallArg>,
121        type_: ExternalFunctionType,
122        site: crate::plan::HostCallSite,
123    ) -> Self {
124        Self {
125            type_,
126            kind: ExternalFunctionExprKind::Call {
127                function,
128                args,
129                site,
130            },
131        }
132    }
133
134    pub(crate) fn function_call_at(
135        function: FunctionFunctionExpr,
136        args: Vec<crate::plan::CallArg>,
137        type_: ExternalFunctionType,
138        site: crate::plan::HostCallSite,
139    ) -> Self {
140        Self {
141            type_,
142            kind: ExternalFunctionExprKind::FunctionCall {
143                function: Box::new(function),
144                args,
145                site,
146            },
147        }
148    }
149
150    pub(crate) fn tuple_index(tuple: TupleExpr, index: usize, type_: ExternalFunctionType) -> Self {
151        Self {
152            type_,
153            kind: ExternalFunctionExprKind::TupleIndex {
154                tuple: Box::new(tuple),
155                index,
156            },
157        }
158    }
159
160    pub(crate) fn custom_field(access: CustomFieldAccess, type_: ExternalFunctionType) -> Self {
161        Self {
162            type_,
163            kind: ExternalFunctionExprKind::CustomField(access),
164        }
165    }
166
167    pub(crate) fn list_index(
168        list: FunctionListExpr,
169        index: usize,
170        type_: ExternalFunctionType,
171    ) -> Self {
172        Self {
173            type_,
174            kind: ExternalFunctionExprKind::ListIndex {
175                list: Box::new(list),
176                index,
177            },
178        }
179    }
180
181    pub(crate) fn panic(panic: PanicExpr, type_: ExternalFunctionType) -> Self {
182        Self {
183            type_,
184            kind: ExternalFunctionExprKind::Panic(panic),
185        }
186    }
187
188    pub(crate) fn bool_case(subject: BoolExpr, true_: Self, false_: Self) -> Self {
189        let (type_, true_) = true_.into_parts();
190        let (_, false_) = false_.into_parts();
191        Self {
192            type_,
193            kind: ExternalFunctionExprKind::BoolCase {
194                subject: Box::new(subject),
195                true_: Box::new(true_),
196                false_: Box::new(false_),
197            },
198        }
199    }
200
201    pub(crate) fn int_case(subject: IntExpr, clauses: Vec<(BigInt, Self)>, fallback: Self) -> Self {
202        let clauses = clauses
203            .into_iter()
204            .map(|(pattern, branch)| (pattern, branch.into_parts().1))
205            .collect();
206        let (type_, fallback) = fallback.into_parts();
207        Self {
208            type_,
209            kind: ExternalFunctionExprKind::IntCase {
210                subject: Box::new(subject),
211                clauses,
212                fallback: Box::new(fallback),
213            },
214        }
215    }
216
217    pub(crate) fn string_case(
218        subject: StringExpr,
219        clauses: Vec<(EcoString, Self)>,
220        fallback: Self,
221    ) -> Self {
222        let clauses = clauses
223            .into_iter()
224            .map(|(pattern, branch)| (pattern, branch.into_parts().1))
225            .collect();
226        let (type_, fallback) = fallback.into_parts();
227        Self {
228            type_,
229            kind: ExternalFunctionExprKind::StringCase {
230                subject: Box::new(subject),
231                clauses,
232                fallback: Box::new(fallback),
233            },
234        }
235    }
236
237    pub(crate) fn float_case(
238        subject: FloatExpr,
239        clauses: Vec<(f64, Self)>,
240        fallback: Self,
241    ) -> Self {
242        let clauses = clauses
243            .into_iter()
244            .map(|(pattern, branch)| (pattern, branch.into_parts().1))
245            .collect();
246        let (type_, fallback) = fallback.into_parts();
247        Self {
248            type_,
249            kind: ExternalFunctionExprKind::FloatCase {
250                subject: Box::new(subject),
251                clauses,
252                fallback: Box::new(fallback),
253            },
254        }
255    }
256
257    pub(crate) fn block(steps: Vec<Step>, return_: Self) -> Self {
258        let (type_, return_) = return_.into_parts();
259        Self {
260            type_,
261            kind: ExternalFunctionExprKind::Block {
262                steps,
263                return_: Box::new(return_),
264            },
265        }
266    }
267
268    pub fn type_(&self) -> FunctionType {
269        self.type_.to_function_type()
270    }
271
272    pub(crate) fn external_function_type(&self) -> &ExternalFunctionType {
273        &self.type_
274    }
275
276    pub(super) fn with_type(mut self, type_: ExternalFunctionType) -> Self {
277        self.type_ = type_;
278        self
279    }
280
281    pub(crate) fn kind(&self) -> &ExternalFunctionExprKind {
282        &self.kind
283    }
284
285    pub(crate) fn into_parts(self) -> (ExternalFunctionType, ExternalFunctionExprKind) {
286        (self.type_, self.kind)
287    }
288}
289
290#[cfg(test)]
291mod tests {
292    use super::ExternalFunctionExpr;
293    use crate::plan::{
294        CallArg, Expr, ExternalFunctionType, ExternalTypeName, ExternalValueShape,
295        FunctionFunctionExpr, FunctionFunctionReference, FunctionShape, FunctionType, IntExpr,
296        ValueShape, ValueType, monomorphic_function_instantiation,
297    };
298
299    #[test]
300    fn function_call_stores_the_validated_external_callable_type() {
301        let external = ExternalValueShape::new(
302            ExternalTypeName::new("geam".into(), "main".into(), "Resource".into()),
303            Vec::new(),
304        );
305        let returned = FunctionShape::new(Vec::new(), ValueShape::External(external.clone()));
306        let returned_type =
307            FunctionType::new(Vec::new(), ValueType::External(external.type_().clone()));
308        let callee = FunctionFunctionExpr::reference(
309            FunctionFunctionReference::new(monomorphic_function_instantiation(
310                0,
311                FunctionShape::new(
312                    vec![ValueShape::Int],
313                    ValueShape::Function(Box::new(returned.clone())),
314                ),
315            )),
316            returned_type.clone(),
317        );
318        let argument = CallArg::new(Expr::int(IntExpr::value(1.into())));
319
320        let type_ = ExternalFunctionType::from_shapes(Vec::new(), external);
321        let expression = ExternalFunctionExpr::function_call_at(
322            callee.clone(),
323            vec![argument.clone()],
324            type_,
325            crate::plan::HostCallSite::unknown(),
326        );
327
328        assert_eq!(expression.type_(), returned_type);
329    }
330}