cedar_policy_core/parser/cst.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
17use smol_str::SmolStr;
18
19// shortcut because we need CST nodes to potentially be empty,
20// for example, if part of it failed the parse, we can
21// still recover other parts
22type Node<N> = super::node::Node<Option<N>>;
23
24/// The set of policy statements that forms a policy set
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct Policies(pub Vec<Node<Policy>>);
27
28/// Annotations: application-defined data, as a key-value pair
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct Annotation {
31 /// key
32 pub key: Node<Ident>,
33 /// value
34 pub value: Option<Node<Str>>,
35}
36
37/// Literal strings
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum Str {
40 /// regular quoted string
41 String(SmolStr),
42 // this is not generated by the parser at time of comment,
43 // but left as future improvement and to clarify the
44 // validity of the above `String` form
45 /// poorly formed string
46 #[allow(unused)]
47 Invalid(SmolStr),
48}
49
50/// Policy statement, the main building block of the language
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct PolicyImpl {
53 /// Annotations
54 pub annotations: Vec<Node<Annotation>>,
55 /// policy effect
56 pub effect: Node<Ident>,
57 /// Variables
58 pub variables: Vec<Node<VariableDef>>,
59 /// Conditions
60 pub conds: Vec<Node<Cond>>,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
64/// Policy statement - can be an Error node when 'tolerant-ast' feature is switched on
65pub enum Policy {
66 /// Valid policy CST node
67 Policy(PolicyImpl),
68 #[cfg(feature = "tolerant-ast")]
69 /// Policy that has failed to parse
70 PolicyError,
71}
72
73/// The variable part of one of the main item of a policy
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct VariableDef {
76 /// identifier, expected:
77 /// principal, action, resource
78 pub variable: Node<Ident>,
79 /// type of entity using previously considered `var : type` syntax. This is
80 /// not used for anything other than error reporting.
81 pub unused_type_name: Option<Node<Name>>,
82 /// type of entity using current `var is type` syntax
83 pub entity_type: Option<Node<Add>>,
84 /// hierarchy of entity
85 pub ineq: Option<(RelOp, Node<Expr>)>,
86}
87
88/// Any identifier, including special ones
89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
90#[allow(unused)] // definitional, or for later improvements
91pub enum Ident {
92 // Variables
93 /// principal
94 Principal,
95 /// action
96 Action,
97 /// resource
98 Resource,
99 /// context
100 Context,
101
102 // Other Identifiers
103 /// true
104 True,
105 /// false
106 False,
107 /// permit
108 Permit,
109 /// forbid
110 Forbid,
111 /// when
112 When,
113 /// unless
114 Unless,
115 /// in
116 In,
117 /// has
118 Has,
119 /// like
120 Like,
121 /// is
122 Is,
123 /// if
124 If,
125 /// then
126 Then,
127 /// else
128 Else,
129
130 // Regular identifiers
131 /// user-supplied, in the proper form
132 Ident(SmolStr),
133 // This is not generated from the parser a time of comment,
134 // but here for future improvement and to clarify
135 // the validity of the above `Ident` form
136 /// user-supplied, not in the proper form
137 Invalid(String),
138}
139
140/// Conditions: powerful extensions to a policy
141#[derive(Debug, Clone, PartialEq, Eq)]
142pub struct Cond {
143 /// initial ident, expected to be "when" or "unless"
144 pub cond: Node<Ident>,
145 /// related expression. expected to not be `None`, but if it's `None`, that
146 /// indicates the body was empty (as in `when {}`), and we can report a good
147 /// error message
148 pub expr: Option<Node<Expr>>,
149}
150
151/// The main computation aspect of a policy, outer
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct ExprImpl {
154 /// expression content
155 pub expr: Box<ExprData>,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
159/// Expression CST Node
160pub enum Expr {
161 /// Expression that has been successfully parsed
162 Expr(ExprImpl),
163 /// To create a tolerant-ast, we keep a node to represented nodes that failed to parse
164 #[cfg(feature = "tolerant-ast")]
165 ErrorExpr,
166}
167
168/// The main computation aspect of a policy, inner
169#[derive(Debug, Clone, PartialEq, Eq)]
170pub enum ExprData {
171 /// || Op
172 Or(Node<Or>),
173 /// if-then-else
174 If(Node<Expr>, Node<Expr>, Node<Expr>),
175}
176/// Logical Or
177#[derive(Debug, Clone, PartialEq, Eq)]
178pub struct Or {
179 /// a singleton is a wrapper for a higher-priority node
180 pub initial: Node<And>,
181 /// additional elements represent a chained `||` computation
182 pub extended: Vec<Node<And>>,
183}
184/// Logical And
185#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct And {
187 /// a singleton is a wrapper for a higher-priority node
188 pub initial: Node<Relation>,
189 /// additional elements represent a chained `&&` computation
190 pub extended: Vec<Node<Relation>>,
191}
192/// Comparison relations
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub enum Relation {
195 /// Regular relations
196 Common {
197 /// a singleton is a wrapper for a higher-priority node
198 initial: Node<Add>,
199 /// additional elements represent chained `>`, `<`, etc. computation
200 extended: Vec<(RelOp, Node<Add>)>,
201 },
202 /// Built-in 'has' operation
203 Has {
204 /// element that may have a field
205 target: Node<Add>,
206 /// a field the element may have
207 field: Node<Add>,
208 },
209 /// Built-in 'like' operation
210 Like {
211 /// element to test
212 target: Node<Add>,
213 /// pattern to match on
214 pattern: Node<Add>,
215 },
216 /// Built-in '.. is .. (in ..)?' operation
217 IsIn {
218 /// element that may be an entity type and `in` an entity
219 target: Node<Add>,
220 /// entity type to check for
221 entity_type: Node<Add>,
222 /// entity that the target may be `in`
223 in_entity: Option<Node<Add>>,
224 },
225}
226
227/// The operation involved in a comparision
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub enum RelOp {
230 /// <
231 Less,
232 /// <=
233 LessEq,
234 /// >=
235 GreaterEq,
236 /// >
237 Greater,
238 /// !=
239 NotEq,
240 /// ==
241 Eq,
242 /// in
243 In,
244 /// =
245 ///
246 /// This is always invalid, but included so we can give a nice error suggesting '==' instead
247 InvalidSingleEq,
248}
249
250/// Allowed Ops for Add
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252pub enum AddOp {
253 /// +
254 Plus,
255 /// -
256 Minus,
257}
258
259/// Allowed Ops for Mult
260#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261pub enum MultOp {
262 /// *
263 Times,
264 /// /
265 Divide,
266 /// %
267 Mod,
268}
269
270/// Allowed Ops for Neg
271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
272pub enum NegOp {
273 /// count of `!`'s
274 Bang(u8),
275 /// too many `!`'s
276 OverBang,
277 /// count of `-`'s
278 Dash(u8),
279 /// too many `-`'s
280 OverDash,
281}
282
283/// Additive arithmetic
284#[derive(Debug, Clone, PartialEq, Eq)]
285pub struct Add {
286 /// a singleton is a wrapper for a higher-priority node
287 pub initial: Node<Mult>,
288 /// additional elements represent a chained `+`, `-`, etc. computation
289 pub extended: Vec<(AddOp, Node<Mult>)>,
290}
291/// Multiplicative arithmetic
292#[derive(Debug, Clone, PartialEq, Eq)]
293pub struct Mult {
294 /// a singleton is a wrapper for a higher-priority node
295 pub initial: Node<Unary>,
296 /// additional elements represent a chained `*`, `/`, etc. computation
297 pub extended: Vec<(MultOp, Node<Unary>)>,
298}
299/// Unary negations
300#[derive(Debug, Clone, PartialEq, Eq)]
301pub struct Unary {
302 /// the negation operation, if any
303 pub op: Option<NegOp>,
304 /// higher-priority node the negation is applied to
305 pub item: Node<Member>,
306}
307/// Members on a primary item, accessed with '.'
308#[derive(Debug, Clone, PartialEq, Eq)]
309pub struct Member {
310 /// Main element
311 pub item: Node<Primary>,
312 /// fields, indexes, etc.
313 pub access: Vec<Node<MemAccess>>,
314}
315/// Forms of members and their accessors
316#[derive(Debug, Clone, PartialEq, Eq)]
317pub enum MemAccess {
318 /// field identifier
319 Field(Node<Ident>),
320 /// function call
321 Call(Vec<Node<Expr>>),
322 /// index of a member
323 Index(Node<Expr>),
324}
325/// Low-level elements like literals
326#[derive(Debug, Clone, PartialEq, Eq)]
327pub enum Primary {
328 /// Literal
329 Literal(Node<Literal>),
330 /// References to entities
331 Ref(Node<Ref>),
332 /// Constructed elements with names
333 Name(Node<Name>),
334 /// Template Slots
335 Slot(Node<Slot>),
336 /// Parentheses
337 Expr(Node<Expr>),
338 /// Constructed array
339 EList(Vec<Node<Expr>>),
340 /// Constructed record
341 RInits(Vec<Node<RecInit>>),
342}
343
344/// UID and Type of named items
345#[derive(Debug, Clone, PartialEq, Eq, Hash)]
346pub struct Name {
347 /// path, like: "name0::name1::name"
348 pub path: Vec<Node<Ident>>,
349 /// Singleton name
350 pub name: Node<Ident>,
351}
352/// Reference to an entity
353#[derive(Debug, Clone, PartialEq, Eq)]
354pub enum Ref {
355 /// UID
356 Uid {
357 /// The path/type of an entity
358 path: Node<Name>,
359 /// EID, quoted name
360 eid: Node<Str>,
361 },
362 /// Lookup references
363 Ref {
364 /// The path/type of an entity
365 path: Node<Name>,
366 /// The indicated fields of the entity
367 rinits: Vec<Node<RefInit>>,
368 },
369}
370/// Elements in a ref: `field: data`
371#[derive(Debug, Clone, PartialEq, Eq)]
372pub struct RefInit(pub Node<Ident>, pub Node<Literal>);
373/// Elements of records: `field_from_expr: data_from_expr`
374#[derive(Debug, Clone, PartialEq, Eq)]
375pub struct RecInit(pub Node<Expr>, pub Node<Expr>);
376
377/// Raw values
378#[derive(Debug, Clone, PartialEq, Eq)]
379pub enum Literal {
380 /// true
381 True,
382 /// false
383 False,
384 /// some integer
385 Num(u64),
386 /// some String
387 Str(Node<Str>),
388}
389
390/// Template Slots
391#[derive(Debug, Clone, PartialEq, Eq)]
392pub enum Slot {
393 /// Slot for Principal Constraints
394 Principal,
395 /// Slot for Resource Constraints
396 Resource,
397 /// Slot other than one of the valid slots
398 Other(SmolStr),
399}
400
401impl Slot {
402 /// Check if a slot matches a scope variable.
403 pub fn matches(&self, var: crate::ast::Var) -> bool {
404 matches!(
405 (self, var),
406 (Slot::Principal, crate::ast::Var::Principal)
407 | (Slot::Resource, crate::ast::Var::Resource)
408 )
409 }
410}