cedar_policy_core/
expr_builder.rs

1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Contains the trait [`ExprBuilder`], defining a generic interface for
18//! building different expression data structures (e.g., AST and EST).
19
20use smol_str::SmolStr;
21
22use crate::{
23    ast::{
24        BinaryOp, EntityType, ExpressionConstructionError, Literal, Name, Pattern, SlotId, UnaryOp,
25        Unknown, Var,
26    },
27    parser::{cst, Loc},
28};
29
30#[cfg(feature = "tolerant-ast")]
31use {crate::parser::err::ParseErrors, std::fmt::Debug};
32
33/// Defines a generic interface for building different expression data
34/// structures.
35#[allow(clippy::wrong_self_convention)]
36pub trait ExprBuilder: Clone {
37    /// The type of expression constructed by this instance of `ExprBuilder`.
38    type Expr: Clone + std::fmt::Display;
39
40    /// Type for extra information stored on nodes of the expression AST. This
41    /// can be `()` if no data is stored.
42    type Data: Default;
43
44    /// Type for what error we return if we cannot construct an error node
45    ///
46    ///  By default we fail on errors and this should be a ParseErrors
47    ///  But when we run with error parsing enabled, can be Infallible
48    #[cfg(feature = "tolerant-ast")]
49    type ErrorType: Debug;
50
51    /// Construct a new expression builder for an expression that will not carry any data.
52    fn new() -> Self
53    where
54        Self: Sized,
55    {
56        Self::with_data(Self::Data::default())
57    }
58
59    /// Build an expression that failed to parse - can optionally include subexpressions that parsed successfully
60    #[cfg(feature = "tolerant-ast")]
61    fn error(self, parse_errors: ParseErrors) -> Result<Self::Expr, Self::ErrorType>;
62
63    /// Build an expression storing this information
64    fn with_data(data: Self::Data) -> Self;
65
66    /// Build an expression located at `l`, if `l` is Some. An implementation
67    /// may ignore this if it cannot store source information.
68    fn with_maybe_source_loc(self, l: Option<&Loc>) -> Self;
69
70    /// Build an expression located at `l`. An implementation may ignore this if
71    /// it cannot store source information.
72    fn with_source_loc(self, l: &Loc) -> Self
73    where
74        Self: Sized,
75    {
76        self.with_maybe_source_loc(Some(l))
77    }
78
79    /// Extract the location for this builder, if set. Used internally to
80    /// provide utilities that construct multiple nodes which should all be
81    /// reported as having the same source location.
82    fn loc(&self) -> Option<&Loc>;
83
84    /// Extract the data that will be stored on the constructed expression.
85    /// Used internally to provide utilities that construct multiple nodes which
86    /// will all have the same data.
87    fn data(&self) -> &Self::Data;
88
89    /// Create an expression that's just a single `Literal`.
90    ///
91    /// Note that you can pass this a `Literal`, an `Integer`, a `String`, etc.
92    fn val(self, v: impl Into<Literal>) -> Self::Expr;
93
94    /// Create an `Expr` that's just this literal `Var`
95    fn var(self, v: Var) -> Self::Expr;
96
97    /// Create an `Unknown` `Expr`
98    fn unknown(self, u: Unknown) -> Self::Expr;
99
100    /// Create an `Expr` that's just this `SlotId`
101    fn slot(self, s: SlotId) -> Self::Expr;
102
103    /// Create a ternary (if-then-else) `Expr`.
104    fn ite(self, test_expr: Self::Expr, then_expr: Self::Expr, else_expr: Self::Expr)
105        -> Self::Expr;
106
107    /// Create a 'not' expression.
108    fn not(self, e: Self::Expr) -> Self::Expr;
109
110    /// Create a '==' expression
111    fn is_eq(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
112
113    /// Create an 'and' expression.
114    fn and(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
115
116    /// Create an 'or' expression.
117    fn or(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
118
119    /// Create a '<' expression.
120    fn less(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
121
122    /// Create a '<=' expression.
123    fn lesseq(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
124
125    /// Create an 'add' expression.
126    fn add(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
127
128    /// Create a 'sub' expression.
129    fn sub(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
130
131    /// Create a 'mul' expression.
132    fn mul(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
133
134    /// Create a 'neg' expression.
135    fn neg(self, e: Self::Expr) -> Self::Expr;
136
137    /// Create an 'in' expression. First argument must evaluate to Entity type.
138    fn is_in(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
139
140    /// Create a 'contains' expression.
141    fn contains(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
142
143    /// Create a 'contains_all' expression. Arguments must evaluate to Set type
144    fn contains_all(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
145
146    /// Create an 'contains_any' expression. Arguments must evaluate to Set type
147    fn contains_any(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr;
148
149    /// Create an 'is_empty' expression. Argument must evaluate to Set type
150    fn is_empty(self, expr: Self::Expr) -> Self::Expr;
151
152    /// Create a 'getTag' expression.
153    fn get_tag(self, expr: Self::Expr, tag: Self::Expr) -> Self::Expr;
154
155    /// Create a 'hasTag' expression.
156    fn has_tag(self, expr: Self::Expr, tag: Self::Expr) -> Self::Expr;
157
158    /// Create an `Expr` which evaluates to a Set of the given `Expr`s
159    fn set(self, exprs: impl IntoIterator<Item = Self::Expr>) -> Self::Expr;
160
161    /// Create an `Expr` which evaluates to a Record with the given (key, value) pairs.
162    fn record(
163        self,
164        pairs: impl IntoIterator<Item = (SmolStr, Self::Expr)>,
165    ) -> Result<Self::Expr, ExpressionConstructionError>;
166
167    /// Create an `Expr` which calls the extension function with the given
168    /// `Name` on `args`
169    fn call_extension_fn(
170        self,
171        fn_name: Name,
172        args: impl IntoIterator<Item = Self::Expr>,
173    ) -> Self::Expr;
174
175    /// Create an `Expr` which gets a given attribute of a given `Entity` or record.
176    fn get_attr(self, expr: Self::Expr, attr: SmolStr) -> Self::Expr;
177
178    /// Create an `Expr` which tests for the existence of a given
179    /// attribute on a given `Entity` or record.
180    fn has_attr(self, expr: Self::Expr, attr: SmolStr) -> Self::Expr;
181
182    /// Create a 'like' expression.
183    fn like(self, expr: Self::Expr, pattern: Pattern) -> Self::Expr;
184
185    /// Create an 'is' expression.
186    fn is_entity_type(self, expr: Self::Expr, entity_type: EntityType) -> Self::Expr;
187
188    /// Create an `_ is _ in _`  expression
189    fn is_in_entity_type(
190        self,
191        e1: Self::Expr,
192        entity_type: EntityType,
193        e2: Self::Expr,
194    ) -> Self::Expr
195    where
196        Self: Sized,
197    {
198        self.clone().and(
199            self.clone().is_entity_type(e1.clone(), entity_type),
200            self.is_in(e1, e2),
201        )
202    }
203
204    /// Create an application `Expr` which applies the given built-in unary
205    /// operator to the given `arg`
206    fn unary_app(self, op: impl Into<UnaryOp>, arg: Self::Expr) -> Self::Expr
207    where
208        Self: Sized,
209    {
210        match op.into() {
211            UnaryOp::Not => self.not(arg),
212            UnaryOp::Neg => self.neg(arg),
213            UnaryOp::IsEmpty => self.is_empty(arg),
214        }
215    }
216
217    /// Create an application `Expr` which applies the given built-in binary
218    /// operator to `arg1` and `arg2`
219    fn binary_app(self, op: impl Into<BinaryOp>, arg1: Self::Expr, arg2: Self::Expr) -> Self::Expr
220    where
221        Self: Sized,
222    {
223        match op.into() {
224            BinaryOp::Eq => self.is_eq(arg1, arg2),
225            BinaryOp::Less => self.less(arg1, arg2),
226            BinaryOp::LessEq => self.lesseq(arg1, arg2),
227            BinaryOp::Add => self.add(arg1, arg2),
228            BinaryOp::Sub => self.sub(arg1, arg2),
229            BinaryOp::Mul => self.mul(arg1, arg2),
230            BinaryOp::In => self.is_in(arg1, arg2),
231            BinaryOp::Contains => self.contains(arg1, arg2),
232            BinaryOp::ContainsAll => self.contains_all(arg1, arg2),
233            BinaryOp::ContainsAny => self.contains_any(arg1, arg2),
234            BinaryOp::GetTag => self.get_tag(arg1, arg2),
235            BinaryOp::HasTag => self.has_tag(arg1, arg2),
236        }
237    }
238
239    /// Create a '!=' expression.
240    fn noteq(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr
241    where
242        Self: Sized,
243    {
244        self.clone().not(self.is_eq(e1, e2))
245    }
246
247    /// Create a '>' expression.
248    fn greater(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr
249    where
250        Self: Sized,
251    {
252        // e1 > e2 is defined as !(e1 <= e2)
253        self.clone().not(self.lesseq(e1, e2))
254    }
255
256    /// Create a '>=' expression.
257    fn greatereq(self, e1: Self::Expr, e2: Self::Expr) -> Self::Expr
258    where
259        Self: Sized,
260    {
261        // e1 >= e2 is defined as !(e1 < e2)
262        self.clone().not(self.less(e1, e2))
263    }
264
265    /// Create an `and` expression that may have more than two subexpressions (A && B && C)
266    /// or may have only one subexpression, in which case no `&&` is performed at all.
267    /// Arguments must evaluate to Bool type.
268    ///
269    /// This may create multiple AST `&&` nodes. If it does, all the nodes will have the same
270    /// source location and the same `T` data (taken from this builder) unless overridden, e.g.,
271    /// with another call to `with_source_loc()`.
272    fn and_nary(self, first: Self::Expr, others: impl IntoIterator<Item = Self::Expr>) -> Self::Expr
273    where
274        Self: Sized,
275    {
276        others
277            .into_iter()
278            .fold(first, |acc, next| self.clone().and(acc, next))
279    }
280
281    /// Create an `or` expression that may have more than two subexpressions (A || B || C)
282    /// or may have only one subexpression, in which case no `||` is performed at all.
283    /// Arguments must evaluate to Bool type.
284    ///
285    /// This may create multiple AST `||` nodes. If it does, all the nodes will have the same
286    /// source location and the same `T` data (taken from this builder) unless overridden, e.g.,
287    /// with another call to `with_source_loc()`.
288    fn or_nary(self, first: Self::Expr, others: impl IntoIterator<Item = Self::Expr>) -> Self::Expr
289    where
290        Self: Sized,
291    {
292        others
293            .into_iter()
294            .fold(first, |acc, next| self.clone().or(acc, next))
295    }
296
297    /// Create expression containing addition and subtraction that may have more
298    /// than two subexpressions (A + B - C) or may have only one subexpression,
299    /// in which case no operations are performed at all.
300    fn add_nary(
301        self,
302        first: Self::Expr,
303        other: impl IntoIterator<Item = (cst::AddOp, Self::Expr)>,
304    ) -> Self::Expr
305    where
306        Self: Sized,
307    {
308        other.into_iter().fold(first, |acc, (op, next)| match op {
309            cst::AddOp::Plus => self.clone().add(acc, next),
310            cst::AddOp::Minus => self.clone().sub(acc, next),
311        })
312    }
313
314    /// Create expression containing multiplication that may have more than two
315    /// subexpressions (A * B * C) or may have only one subexpression,
316    /// in which case no operations are performed at all.
317    fn mul_nary(self, first: Self::Expr, other: impl IntoIterator<Item = Self::Expr>) -> Self::Expr
318    where
319        Self: Sized,
320    {
321        other
322            .into_iter()
323            .fold(first, |acc, next| self.clone().mul(acc, next))
324    }
325}