cedar_policy_core/parser/
node.rs

1/*
2 * Copyright 2022-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
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 serde::{Deserialize, Serialize};
18
19/// Describes where in policy source code a node in the CST or expression AST
20/// occurs.
21#[derive(Serialize, Deserialize, Hash, Debug, Clone, PartialEq, Eq)]
22pub struct SourceInfo(pub std::ops::Range<usize>);
23
24impl SourceInfo {
25    /// Get the start of range.
26    pub fn range_start(&self) -> usize {
27        self.0.start
28    }
29
30    /// Get the end of range.
31    pub fn range_end(&self) -> usize {
32        self.0.end
33    }
34}
35
36/// Metadata for our syntax trees
37// Note that these derives are likely to need explicit impls as we develop further
38#[derive(Debug, Clone)]
39pub struct ASTNode<N> {
40    /// Main data represented
41    pub node: N,
42
43    /// additional information
44    pub info: SourceInfo,
45}
46
47impl<N> ASTNode<N> {
48    /// Create a new Node from main data
49    pub fn new(node: N, left: usize, right: usize) -> Self {
50        let info = SourceInfo(left..right);
51        ASTNode { node, info }
52    }
53
54    /// Create a new Node from main data
55    pub fn from_source(node: N, info: SourceInfo) -> Self {
56        ASTNode { node, info }
57    }
58
59    /// like Option.as_ref()
60    pub fn as_ref(&self) -> ASTNode<&N> {
61        ASTNode {
62            node: &self.node,
63            info: self.info.clone(),
64        }
65    }
66
67    /// map the main data, leaving the SourceInfo alone
68    pub fn map<D>(self, f: impl FnOnce(N) -> D) -> ASTNode<D> {
69        ASTNode {
70            node: f(self.node),
71            info: self.info,
72        }
73    }
74
75    /// consume the Node, producing the main data and the SourceInfo
76    pub fn into_inner(self) -> (N, SourceInfo) {
77        (self.node, self.info)
78    }
79}
80
81// Ignore the metadata this node contains
82impl<N: PartialEq> PartialEq for ASTNode<N> {
83    /// ignores metadata
84    fn eq(&self, other: &Self) -> bool {
85        self.node == other.node
86    }
87}
88impl<N: Eq> Eq for ASTNode<N> {}
89
90/// Convenience methods on `ASTNode<Option<T>>`
91impl<T> ASTNode<Option<T>> {
92    /// Similar to `.as_inner()`, but also gives access to the `SourceInfo`
93    pub fn as_inner_pair(&self) -> (&SourceInfo, Option<&T>) {
94        (&self.info, self.node.as_ref())
95    }
96
97    /// Get the inner data as `&T`, if it exists
98    pub fn as_inner(&self) -> Option<&T> {
99        self.node.as_ref()
100    }
101
102    /// `None` if the node is empty, otherwise a node without the `Option`
103    pub fn collapse(&self) -> Option<ASTNode<&T>> {
104        self.node.as_ref().map(|node| ASTNode {
105            node,
106            info: self.info.clone(),
107        })
108    }
109
110    /// Apply the function `f` to the main data and source info. Returns `None`
111    /// if no main data or if `f` returns `None`.
112    pub fn apply<F, R>(&self, f: F) -> Option<R>
113    where
114        F: FnOnce(&T, &SourceInfo) -> Option<R>,
115    {
116        f(self.node.as_ref()?, &self.info)
117    }
118
119    /// Apply the function `f` to the main data and source info, consuming them.
120    /// Returns `None` if no main data or if `f` returns `None`.
121    pub fn into_apply<F, R>(self, f: F) -> Option<R>
122    where
123        F: FnOnce(T, SourceInfo) -> Option<R>,
124    {
125        f(self.node?, self.info)
126    }
127}