Skip to main content

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}