1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/*
 * Copyright 2022-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use super::node::ASTNode;
use smol_str::SmolStr;
// shortcut because we need CST nodes to potentially be empty,
// for example, if part of it failed the parse, we can
// still recover other parts
type Node<N> = ASTNode<Option<N>>;

/// The set of policy statements that forms an authorization policy
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Policies(pub Vec<Node<Policy>>);

/// Annotations: application-defined data, as a key-value pair
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Annotation {
    /// key
    pub key: Node<Ident>,
    /// value
    pub value: Node<Str>,
}

/// Literal strings
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Str {
    /// regular quoted string
    String(SmolStr),
    // this is not generated by the parser at time of comment,
    // but left as future improvement and to clarify the
    // validity of the above `String` form
    /// poorly formed string
    #[allow(unused)]
    Invalid(SmolStr),
}

/// Policy statement, the main building block of the language
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Policy {
    /// Annotations
    pub annotations: Vec<Node<Annotation>>,
    /// policy effect
    pub effect: Node<Ident>,
    /// Variables
    pub variables: Vec<Node<VariableDef>>,
    /// Conditions
    pub conds: Vec<Node<Cond>>,
}

/// The variable part of one of the main item of a policy
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariableDef {
    /// identifier, expected:
    /// principal, action, resource
    pub variable: Node<Ident>,
    /// type of entity
    pub name: Option<Node<Name>>,
    /// hierarchy of entity
    pub ineq: Option<(RelOp, Node<Expr>)>,
}

/// Any identifier, including special ones
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(unused)] // definitional, or for later improvements
pub enum Ident {
    // Variables
    /// principal
    Principal,
    /// action
    Action,
    /// resource
    Resource,
    /// context
    Context,

    // Other Identifiers
    /// true
    True,
    /// false
    False,
    /// permit
    Permit,
    /// forbid
    Forbid,
    /// when
    When,
    /// unless
    Unless,
    /// in
    In,
    /// has
    Has,
    /// like
    Like,
    /// if
    If,
    /// then
    Then,
    /// else
    Else,

    // Regular identifiers
    /// user-supplied, in the proper form
    Ident(SmolStr),
    // This is not generated from the parser a time of comment,
    // but here for future improvement and to clarify
    // the validity of the above `Ident` form
    /// user-supplied, not in the proper form
    Invalid(String),
}

/// Conditions: powerful extensions to a policy
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Cond {
    /// initial ident, expected to be "when" or "unless"
    pub cond: Node<Ident>,
    /// related expression. expected to not be `None`, but if it's `None`, that
    /// indicates the body was empty (as in `when {}`), and we can report a good
    /// error message
    pub expr: Option<Node<Expr>>,
}

/// The main computation aspect of a policy, outer
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Expr {
    /// expression content
    pub expr: Box<ExprData>,
}
/// The main computation aspect of a policy, inner
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExprData {
    /// || Op
    Or(Node<Or>),
    /// if-then-else
    If(Node<Expr>, Node<Expr>, Node<Expr>),
}
/// Logical Or
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Or {
    /// a singleton is a wrapper for a higher-priority node
    pub initial: Node<And>,
    /// additional elements represent a chained `||` computation
    pub extended: Vec<Node<And>>,
}
/// Logical And
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct And {
    /// a singleton is a wrapper for a higher-priority node
    pub initial: Node<Relation>,
    /// additional elements represent a chained `&&` computation
    pub extended: Vec<Node<Relation>>,
}
/// Comparison relations
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Relation {
    /// Regular relations
    Common {
        /// a singleton is a wrapper for a higher-priority node
        initial: Node<Add>,
        /// additional elements represent chained `>`, `<`, etc. computation
        extended: Vec<(RelOp, Node<Add>)>,
    },
    /// Built-in 'has' operation
    Has {
        /// element that may have a field
        target: Node<Add>,
        /// a field the element may have
        field: Node<Add>,
    },
    /// Built-in 'like' operation
    Like {
        /// element to test
        target: Node<Add>,
        /// pattern to match on
        pattern: Node<Add>,
    },
}

/// The operation involved in a comparision
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelOp {
    /// <
    Less,
    /// <=
    LessEq,
    /// >=
    GreaterEq,
    /// >
    Greater,
    /// !=
    NotEq,
    /// ==
    Eq,
    /// in
    In,
}

/// Allowed Ops for Add
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AddOp {
    /// +
    Plus,
    /// -
    Minus,
}

/// Allowed Ops for Mult
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MultOp {
    /// *
    Times,
    /// /
    Divide,
    /// %
    Mod,
}

/// Allowed Ops for Neg
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NegOp {
    /// count of `!`'s
    Bang(u8),
    /// too many `!`'s
    OverBang,
    /// count of `-`'s
    Dash(u8),
    /// too many `-`'s
    OverDash,
}

/// Additive arithmetic
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Add {
    /// a singleton is a wrapper for a higher-priority node
    pub initial: Node<Mult>,
    /// additional elements represent a chained `+`, `-`, etc. computation
    pub extended: Vec<(AddOp, Node<Mult>)>,
}
/// Multiplicative arithmetic
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Mult {
    /// a singleton is a wrapper for a higher-priority node
    pub initial: Node<Unary>,
    /// additional elements represent a chained `*`, `/`, etc. computation
    pub extended: Vec<(MultOp, Node<Unary>)>,
}
/// Unary negations
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Unary {
    /// the negation operation, if any
    pub op: Option<NegOp>,
    /// higher-priority node the negation is applied to
    pub item: Node<Member>,
}
/// Members on a primary item, accessed with '.'
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Member {
    /// Main element
    pub item: Node<Primary>,
    /// fields, indexes, etc.
    pub access: Vec<Node<MemAccess>>,
}
/// Forms of members and their accessors
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MemAccess {
    /// field identifier
    Field(Node<Ident>),
    /// function call
    Call(Vec<Node<Expr>>),
    /// index of a member
    Index(Node<Expr>),
}
/// Low-level elements like literals
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Primary {
    /// Literal
    Literal(Node<Literal>),
    /// References to entities
    Ref(Node<Ref>),
    /// Constructed elements with names
    Name(Node<Name>),
    /// Template Slots
    Slot(Node<Slot>),
    /// Parentheses
    Expr(Node<Expr>),
    /// Constructed array
    EList(Vec<Node<Expr>>),
    /// Constructed record
    RInits(Vec<Node<RecInit>>),
}

/// UID and Type of named items
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Name {
    /// path, like: "name0::name1::name"
    pub path: Vec<Node<Ident>>,
    /// Singleton name
    pub name: Node<Ident>,
}
/// Reference to an entity
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Ref {
    /// UID
    Uid {
        /// The path/type of an entity
        path: Node<Name>,
        /// EID, quoted name
        eid: Node<Str>,
    },
    /// Lookup references
    Ref {
        /// The path/type of an entity
        path: Node<Name>,
        /// The indicated fields of the entity
        rinits: Vec<Node<RefInit>>,
    },
}
/// Elements in a ref: `field: data`
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RefInit(pub Node<Ident>, pub Node<Literal>);
/// Elements of records: `field_from_expr: data_from_expr`
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RecInit(pub Node<Expr>, pub Node<Expr>);

/// Raw values
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Literal {
    /// true
    True,
    /// false
    False,
    /// some integer
    Num(u64),
    /// some String
    Str(Node<Str>),
}

/// Template Slots
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Slot {
    /// Slot for Principal Constraints
    Principal,
    /// Slot for Resource Constraints
    Resource,
}

impl Slot {
    /// Check if a slot matches a head variable.
    pub fn matches(&self, var: crate::ast::Var) -> bool {
        matches!(
            (self, var),
            (Slot::Principal, crate::ast::Var::Principal)
                | (Slot::Resource, crate::ast::Var::Resource)
        )
    }
}