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