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