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}