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}