Skip to main content

geam_core/plan/module/expression/
nil.rs

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