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}