1use super::{
2 BoolExpr, CallArg, CustomFieldAccess, FloatExpr, IntExpr, PanicExpr, StringExpr,
3 TupleFunctionExpr, TupleListExpr,
4};
5use crate::plan::{ConstantTupleReference, FunctionInstantiation, Step, TupleLocalId, ValueType};
6use ecow::EcoString;
7use num_bigint::BigInt;
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct TupleExpr {
11 type_: Vec<ValueType>,
12 shape: Box<[crate::plan::ValueShape]>,
13 kind: TupleExprKind,
14}
15
16#[derive(Debug, Clone, PartialEq)]
17pub(crate) enum TupleExprKind {
18 Value(Vec<super::Expr>),
19 Constant(ConstantTupleReference),
20 LocalGet {
21 local: TupleLocalId,
22 name: EcoString,
23 },
24 Call {
25 function: FunctionInstantiation,
26 args: Vec<CallArg>,
27 site: crate::plan::HostCallSite,
28 },
29 FunctionCall {
30 function: Box<TupleFunctionExpr>,
31 args: Vec<CallArg>,
32 site: crate::plan::HostCallSite,
33 },
34 TupleIndex {
35 tuple: Box<TupleExpr>,
36 index: usize,
37 },
38 CustomField(CustomFieldAccess),
39 ListIndex {
40 list: Box<TupleListExpr>,
41 index: usize,
42 },
43 Panic(PanicExpr),
44 BoolCase {
45 subject: Box<BoolExpr>,
46 true_: Box<TupleExpr>,
47 false_: Box<TupleExpr>,
48 },
49 IntCase {
50 subject: Box<IntExpr>,
51 clauses: Vec<(BigInt, TupleExpr)>,
52 fallback: Box<TupleExpr>,
53 },
54 StringCase {
55 subject: Box<StringExpr>,
56 clauses: Vec<(EcoString, TupleExpr)>,
57 fallback: Box<TupleExpr>,
58 },
59 FloatCase {
60 subject: Box<FloatExpr>,
61 clauses: Vec<(f64, TupleExpr)>,
62 fallback: Box<TupleExpr>,
63 },
64 Block {
65 steps: Vec<Step>,
66 return_: Box<TupleExpr>,
67 },
68}
69
70impl TupleExpr {
71 pub(crate) fn value(elements: Vec<super::Expr>, type_: Vec<ValueType>) -> Self {
72 let shape = elements
73 .iter()
74 .map(|element| element.value_shape().clone())
75 .collect::<Vec<_>>()
76 .into_boxed_slice();
77 Self {
78 type_,
79 shape,
80 kind: TupleExprKind::Value(elements),
81 }
82 }
83
84 pub(in crate::plan::module) fn constant(reference: ConstantTupleReference) -> Self {
85 let type_ = reference
86 .shape()
87 .iter()
88 .map(crate::plan::ValueShape::value_type)
89 .collect();
90 let shape = reference.shape().to_vec().into_boxed_slice();
91 Self {
92 type_,
93 shape,
94 kind: TupleExprKind::Constant(reference),
95 }
96 }
97
98 pub(crate) fn local_get(local: TupleLocalId, name: EcoString, type_: Vec<ValueType>) -> Self {
99 Self::new(type_, TupleExprKind::LocalGet { local, name })
100 }
101
102 #[cfg(test)]
103 pub(crate) fn call(
104 function: FunctionInstantiation,
105 args: Vec<CallArg>,
106 type_: Vec<ValueType>,
107 ) -> Self {
108 Self::call_at(function, args, type_, crate::plan::HostCallSite::unknown())
109 }
110
111 pub(crate) fn call_at(
112 function: FunctionInstantiation,
113 args: Vec<CallArg>,
114 type_: Vec<ValueType>,
115 site: crate::plan::HostCallSite,
116 ) -> Self {
117 Self::new(
118 type_,
119 TupleExprKind::Call {
120 function,
121 args,
122 site,
123 },
124 )
125 }
126
127 #[cfg(test)]
128 pub(crate) fn function_call(
129 function: TupleFunctionExpr,
130 args: Vec<CallArg>,
131 type_: Vec<ValueType>,
132 ) -> Self {
133 Self::function_call_at(function, args, type_, crate::plan::HostCallSite::unknown())
134 }
135
136 pub(crate) fn function_call_at(
137 function: TupleFunctionExpr,
138 args: Vec<CallArg>,
139 type_: Vec<ValueType>,
140 site: crate::plan::HostCallSite,
141 ) -> Self {
142 Self::new(
143 type_,
144 TupleExprKind::FunctionCall {
145 function: Box::new(function),
146 args,
147 site,
148 },
149 )
150 }
151
152 pub(crate) fn tuple_index(tuple: TupleExpr, index: usize, type_: Vec<ValueType>) -> Self {
153 Self::new(
154 type_,
155 TupleExprKind::TupleIndex {
156 tuple: Box::new(tuple),
157 index,
158 },
159 )
160 }
161
162 pub(crate) fn custom_field(access: CustomFieldAccess, type_: Vec<ValueType>) -> Self {
163 Self::new(type_, TupleExprKind::CustomField(access))
164 }
165
166 pub(crate) fn list_index(
167 list: impl Into<TupleListExpr>,
168 index: usize,
169 type_: Vec<ValueType>,
170 ) -> Self {
171 Self::new(
172 type_,
173 TupleExprKind::ListIndex {
174 list: Box::new(list.into()),
175 index,
176 },
177 )
178 }
179
180 pub(crate) fn panic(panic: PanicExpr, type_: Vec<ValueType>) -> Self {
181 Self::new(type_, TupleExprKind::Panic(panic))
182 }
183
184 pub(crate) fn bool_case(subject: BoolExpr, true_: TupleExpr, false_: TupleExpr) -> Self {
185 Self::new(
186 true_.type_.clone(),
187 TupleExprKind::BoolCase {
188 subject: Box::new(subject),
189 true_: Box::new(true_),
190 false_: Box::new(false_),
191 },
192 )
193 }
194
195 pub(crate) fn int_case(
196 subject: IntExpr,
197 clauses: Vec<(BigInt, TupleExpr)>,
198 fallback: TupleExpr,
199 ) -> Self {
200 Self::new(
201 fallback.type_.clone(),
202 TupleExprKind::IntCase {
203 subject: Box::new(subject),
204 clauses,
205 fallback: Box::new(fallback),
206 },
207 )
208 }
209
210 pub(crate) fn string_case(
211 subject: StringExpr,
212 clauses: Vec<(EcoString, TupleExpr)>,
213 fallback: TupleExpr,
214 ) -> Self {
215 Self::new(
216 fallback.type_.clone(),
217 TupleExprKind::StringCase {
218 subject: Box::new(subject),
219 clauses,
220 fallback: Box::new(fallback),
221 },
222 )
223 }
224
225 pub(crate) fn float_case(
226 subject: FloatExpr,
227 clauses: Vec<(f64, TupleExpr)>,
228 fallback: TupleExpr,
229 ) -> Self {
230 Self::new(
231 fallback.type_.clone(),
232 TupleExprKind::FloatCase {
233 subject: Box::new(subject),
234 clauses,
235 fallback: Box::new(fallback),
236 },
237 )
238 }
239
240 pub(crate) fn block(steps: Vec<Step>, return_: TupleExpr) -> Self {
241 Self::new(
242 return_.type_.clone(),
243 TupleExprKind::Block {
244 steps,
245 return_: Box::new(return_),
246 },
247 )
248 }
249
250 pub fn type_(&self) -> &[ValueType] {
251 &self.type_
252 }
253
254 pub(crate) fn kind(&self) -> &TupleExprKind {
255 &self.kind
256 }
257
258 pub(crate) fn shape(&self) -> &[crate::plan::ValueShape] {
259 &self.shape
260 }
261
262 pub(crate) fn with_shape(mut self, shape: Box<[crate::plan::ValueShape]>) -> Self {
263 self.shape = shape;
264 self
265 }
266
267 fn new(type_: Vec<ValueType>, kind: TupleExprKind) -> Self {
268 let shape = type_
269 .iter()
270 .cloned()
271 .map(crate::plan::ValueShape::from_value_type)
272 .collect::<Vec<_>>()
273 .into_boxed_slice();
274 Self { type_, shape, kind }
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::{TupleExpr, TupleExprKind};
281 use crate::plan::{
282 BoolExpr, Expr, FunctionInstantiation, FunctionShape, FunctionType, IntExpr, Step,
283 TupleFunctionExpr, TupleFunctionReference, TupleLocalId, ValueShape, ValueType,
284 monomorphic_function_instantiation,
285 };
286
287 #[test]
288 fn tuple_expr_kind_accessors() {
289 assert_eq!(
290 tuple_value().kind(),
291 &TupleExprKind::Value(vec![Expr::int(IntExpr::value(1.into()))]),
292 );
293 assert_eq!(
294 TupleExpr::local_get(TupleLocalId(0), "pair".into(), tuple_type()).kind(),
295 &TupleExprKind::LocalGet {
296 local: TupleLocalId(0),
297 name: "pair".into(),
298 },
299 );
300 assert_eq!(
301 TupleExpr::call(function_instantiation(), Vec::new(), tuple_type()).kind(),
302 &TupleExprKind::Call {
303 function: function_instantiation(),
304 args: Vec::new(),
305 site: crate::plan::HostCallSite::unknown(),
306 },
307 );
308 assert_eq!(
309 TupleExpr::function_call(tuple_function_expr(), Vec::new(), tuple_type()).kind(),
310 &TupleExprKind::FunctionCall {
311 function: Box::new(tuple_function_expr()),
312 args: Vec::new(),
313 site: crate::plan::HostCallSite::unknown(),
314 },
315 );
316 assert_eq!(
317 TupleExpr::tuple_index(tuple_value(), 0, tuple_type()).kind(),
318 &TupleExprKind::TupleIndex {
319 tuple: Box::new(tuple_value()),
320 index: 0,
321 },
322 );
323 assert_eq!(
324 TupleExpr::bool_case(BoolExpr::value(true), tuple_value(), tuple_value()).kind(),
325 &TupleExprKind::BoolCase {
326 subject: Box::new(BoolExpr::value(true)),
327 true_: Box::new(tuple_value()),
328 false_: Box::new(tuple_value()),
329 },
330 );
331 assert_eq!(
332 TupleExpr::int_case(
333 IntExpr::value(1.into()),
334 vec![(1.into(), tuple_value())],
335 tuple_value(),
336 )
337 .kind(),
338 &TupleExprKind::IntCase {
339 subject: Box::new(IntExpr::value(1.into())),
340 clauses: vec![(1.into(), tuple_value())],
341 fallback: Box::new(tuple_value()),
342 },
343 );
344 assert_eq!(
345 TupleExpr::string_case(
346 crate::plan::StringExpr::value("one".into()),
347 vec![("one".into(), tuple_value())],
348 tuple_value(),
349 )
350 .kind(),
351 &TupleExprKind::StringCase {
352 subject: Box::new(crate::plan::StringExpr::value("one".into())),
353 clauses: vec![("one".into(), tuple_value())],
354 fallback: Box::new(tuple_value()),
355 },
356 );
357 assert_eq!(
358 TupleExpr::float_case(
359 crate::plan::FloatExpr::value(1.0),
360 vec![(1.0, tuple_value())],
361 tuple_value(),
362 )
363 .kind(),
364 &TupleExprKind::FloatCase {
365 subject: Box::new(crate::plan::FloatExpr::value(1.0)),
366 clauses: vec![(1.0, tuple_value())],
367 fallback: Box::new(tuple_value()),
368 },
369 );
370 assert_eq!(
371 TupleExpr::block(
372 vec![Step::evaluate(Expr::int(IntExpr::value(1.into())))],
373 tuple_value(),
374 )
375 .kind(),
376 &TupleExprKind::Block {
377 steps: vec![Step::evaluate(Expr::int(IntExpr::value(1.into())))],
378 return_: Box::new(tuple_value()),
379 },
380 );
381 }
382
383 #[test]
384 fn tuple_expr_type() {
385 assert_eq!(tuple_value().type_(), tuple_type());
386 assert_eq!(
387 TupleExpr::bool_case(BoolExpr::value(true), tuple_value(), tuple_value()).type_(),
388 tuple_type(),
389 );
390 assert_eq!(
391 TupleExpr::int_case(
392 IntExpr::value(1.into()),
393 vec![(1.into(), tuple_value())],
394 tuple_value(),
395 )
396 .type_(),
397 tuple_type(),
398 );
399 assert_eq!(
400 TupleExpr::string_case(
401 crate::plan::StringExpr::value("one".into()),
402 vec![("one".into(), tuple_value())],
403 tuple_value(),
404 )
405 .type_(),
406 tuple_type(),
407 );
408 assert_eq!(
409 TupleExpr::float_case(
410 crate::plan::FloatExpr::value(1.0),
411 vec![(1.0, tuple_value())],
412 tuple_value(),
413 )
414 .type_(),
415 tuple_type(),
416 );
417 assert_eq!(
418 TupleExpr::block(Vec::new(), tuple_value()).type_(),
419 tuple_type(),
420 );
421 }
422
423 fn tuple_value() -> TupleExpr {
424 TupleExpr::value(
425 vec![Expr::int(IntExpr::value(1.into()))],
426 vec![ValueType::Int],
427 )
428 }
429
430 fn tuple_type() -> Vec<ValueType> {
431 vec![ValueType::Int]
432 }
433
434 fn tuple_function_expr() -> TupleFunctionExpr {
435 TupleFunctionExpr::reference(TupleFunctionReference::new(function_instantiation()))
436 }
437
438 fn function_instantiation() -> FunctionInstantiation {
439 monomorphic_function_instantiation(
440 0,
441 FunctionShape::new(
442 Vec::new(),
443 ValueShape::Tuple(vec![ValueShape::Int].into_boxed_slice()),
444 ),
445 )
446 }
447
448 #[test]
449 fn tuple_function_value_type_fixture() {
450 assert_eq!(
451 tuple_function_expr().type_(),
452 &FunctionType::new(Vec::new(), ValueType::Tuple(tuple_type())),
453 );
454 }
455}