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