/proc/self/cwd/common/source.h
Line | Count | Source |
1 | | // Copyright 2023 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #ifndef THIRD_PARTY_CEL_CPP_COMMON_SOURCE_H_ |
16 | | #define THIRD_PARTY_CEL_CPP_COMMON_SOURCE_H_ |
17 | | |
18 | | #include <cstdint> |
19 | | #include <memory> |
20 | | #include <string> |
21 | | #include <utility> |
22 | | |
23 | | #include "absl/base/attributes.h" |
24 | | #include "absl/base/nullability.h" |
25 | | #include "absl/container/inlined_vector.h" |
26 | | #include "absl/status/statusor.h" |
27 | | #include "absl/strings/cord.h" |
28 | | #include "absl/strings/string_view.h" |
29 | | #include "absl/types/optional.h" |
30 | | #include "absl/types/span.h" |
31 | | #include "absl/types/variant.h" |
32 | | |
33 | | namespace cel { |
34 | | |
35 | | namespace common_internal { |
36 | | class SourceImpl; |
37 | | } // namespace common_internal |
38 | | |
39 | | class Source; |
40 | | class SourceSubrange; |
41 | | |
42 | | // SourcePosition represents an offset in source text. |
43 | | using SourcePosition = int32_t; |
44 | | |
45 | | // SourceRange represents a range of positions, where `begin` is inclusive and |
46 | | // `end` is exclusive. |
47 | | struct SourceRange final { |
48 | | SourcePosition begin = -1; |
49 | | SourcePosition end = -1; |
50 | | }; |
51 | | |
52 | 0 | inline bool operator==(const SourceRange& lhs, const SourceRange& rhs) { |
53 | 0 | return lhs.begin == rhs.begin && lhs.end == rhs.end; |
54 | 0 | } |
55 | | |
56 | 0 | inline bool operator!=(const SourceRange& lhs, const SourceRange& rhs) { |
57 | 0 | return !operator==(lhs, rhs); |
58 | 0 | } |
59 | | |
60 | | // `SourceLocation` is a representation of a line and column in source text. |
61 | | struct SourceLocation final { |
62 | | int32_t line = -1; // 1-based line number. |
63 | | int32_t column = -1; // 0-based column number. |
64 | | }; |
65 | | |
66 | 0 | inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs) { |
67 | 0 | return lhs.line == rhs.line && lhs.column == rhs.column; |
68 | 0 | } |
69 | | |
70 | 0 | inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs) { |
71 | 0 | return !operator==(lhs, rhs); |
72 | 0 | } |
73 | | |
74 | | // `SourceContentView` is a view of the content owned by `Source`, which is a |
75 | | // sequence of Unicode code points. |
76 | | class SourceContentView final { |
77 | | public: |
78 | | SourceContentView(const SourceContentView&) = default; |
79 | | SourceContentView(SourceContentView&&) = default; |
80 | | SourceContentView& operator=(const SourceContentView&) = default; |
81 | | SourceContentView& operator=(SourceContentView&&) = default; |
82 | | |
83 | | SourcePosition size() const; |
84 | | |
85 | | bool empty() const; |
86 | | |
87 | | char32_t at(SourcePosition position) const; |
88 | | |
89 | | std::string ToString(SourcePosition begin, SourcePosition end) const; |
90 | 148k | std::string ToString(SourcePosition begin) const { |
91 | 148k | return ToString(begin, size()); |
92 | 148k | } |
93 | 0 | std::string ToString() const { return ToString(0); } |
94 | | |
95 | | void AppendToString(std::string& dest) const; |
96 | | |
97 | | private: |
98 | | friend class Source; |
99 | | friend class SourceSubrange; |
100 | | |
101 | 0 | constexpr SourceContentView() = default; |
102 | | |
103 | | constexpr explicit SourceContentView(absl::Span<const char> view) |
104 | 152k | : view_(view) {} |
105 | | |
106 | | constexpr explicit SourceContentView(absl::Span<const uint8_t> view) |
107 | 9.14k | : view_(view) {} |
108 | | |
109 | | constexpr explicit SourceContentView(absl::Span<const char16_t> view) |
110 | 26.6k | : view_(view) {} |
111 | | |
112 | | constexpr explicit SourceContentView(absl::Span<const char32_t> view) |
113 | 24.1k | : view_(view) {} |
114 | | |
115 | | absl::variant<absl::Span<const char>, absl::Span<const uint8_t>, |
116 | | absl::Span<const char16_t>, absl::Span<const char32_t>> |
117 | | view_; |
118 | | }; |
119 | | |
120 | | // `Source` represents the source expression. |
121 | | class Source { |
122 | | public: |
123 | | using ContentView = SourceContentView; |
124 | | |
125 | | Source(const Source&) = delete; |
126 | | Source(Source&&) = delete; |
127 | | |
128 | 21.6k | virtual ~Source() = default; |
129 | | |
130 | | Source& operator=(const Source&) = delete; |
131 | | Source& operator=(Source&&) = delete; |
132 | | |
133 | | virtual absl::string_view description() const |
134 | | ABSL_ATTRIBUTE_LIFETIME_BOUND = 0; |
135 | | |
136 | | // Maps a `SourcePosition` to a `SourceLocation`. Returns an empty |
137 | | // `absl::optional` when `SourcePosition` is invalid or the information |
138 | | // required to perform the mapping is not present. |
139 | | absl::optional<SourceLocation> GetLocation(SourcePosition position) const; |
140 | | |
141 | | // Maps a `SourceLocation` to a `SourcePosition`. Returns an empty |
142 | | // `absl::optional` when `SourceLocation` is invalid or the information |
143 | | // required to perform the mapping is not present. |
144 | | absl::optional<SourcePosition> GetPosition( |
145 | | const SourceLocation& location) const; |
146 | | |
147 | | absl::optional<std::string> Snippet(int32_t line) const; |
148 | | |
149 | | // Formats an annotated snippet highlighting an error at location, e.g. |
150 | | // |
151 | | // "\n | $SOURCE_SNIPPET" + |
152 | | // "\n | .......^" |
153 | | // |
154 | | // Returns an empty string if location is not a valid location in this source. |
155 | | std::string DisplayErrorLocation(SourceLocation location) const; |
156 | | |
157 | | // Returns a view of the underlying expression text, if present. |
158 | | virtual ContentView content() const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0; |
159 | | |
160 | | // Returns a `absl::Span` of `SourcePosition` which represent the positions |
161 | | // where new lines occur. |
162 | | virtual absl::Span<const SourcePosition> line_offsets() const |
163 | | ABSL_ATTRIBUTE_LIFETIME_BOUND = 0; |
164 | | |
165 | | protected: |
166 | 0 | static constexpr ContentView EmptyContentView() { return ContentView(); } |
167 | 152k | static constexpr ContentView MakeContentView(absl::Span<const char> view) { |
168 | 152k | return ContentView(view); |
169 | 152k | } |
170 | 9.14k | static constexpr ContentView MakeContentView(absl::Span<const uint8_t> view) { |
171 | 9.14k | return ContentView(view); |
172 | 9.14k | } |
173 | | static constexpr ContentView MakeContentView( |
174 | 26.6k | absl::Span<const char16_t> view) { |
175 | 26.6k | return ContentView(view); |
176 | 26.6k | } |
177 | | static constexpr ContentView MakeContentView( |
178 | 24.1k | absl::Span<const char32_t> view) { |
179 | 24.1k | return ContentView(view); |
180 | 24.1k | } |
181 | | |
182 | | private: |
183 | | friend class common_internal::SourceImpl; |
184 | | friend class SourceSubrange; |
185 | | |
186 | 21.6k | Source() = default; |
187 | | |
188 | | absl::optional<SourcePosition> FindLinePosition(int32_t line) const; |
189 | | |
190 | | absl::optional<std::pair<int32_t, SourcePosition>> FindLine( |
191 | | SourcePosition position) const; |
192 | | }; |
193 | | |
194 | | // `SourceSubrange` is a view of a subrange fo an underlying `Source` object. |
195 | | // Intended to be used when the CEL expression is embedded in a larger text |
196 | | // representation (such as a.celpolicy). |
197 | | // |
198 | | // The parent `Source` must outlive this object. |
199 | | class SourceSubrange final : public Source { |
200 | | public: |
201 | | SourceSubrange(const Source& source ABSL_ATTRIBUTE_LIFETIME_BOUND, |
202 | | SourceRange range); |
203 | | |
204 | 0 | absl::string_view description() const ABSL_ATTRIBUTE_LIFETIME_BOUND override { |
205 | 0 | return source_.description(); |
206 | 0 | } |
207 | | |
208 | | // Returns a view of the underlying expression text. |
209 | | ContentView content() const ABSL_ATTRIBUTE_LIFETIME_BOUND override; |
210 | | |
211 | | // Returns a `absl::Span` of `SourcePosition` which represent the positions |
212 | | // where new lines occur. |
213 | | absl::Span<const SourcePosition> line_offsets() const |
214 | | ABSL_ATTRIBUTE_LIFETIME_BOUND override; |
215 | | |
216 | | private: |
217 | | const Source& source_; |
218 | | SourceRange range_; |
219 | | absl::InlinedVector<SourcePosition, 1> line_offsets_; |
220 | | }; |
221 | | |
222 | | using SourcePtr = std::unique_ptr<Source>; |
223 | | |
224 | | absl::StatusOr<absl_nonnull SourcePtr> NewSource( |
225 | | absl::string_view content, std::string description = "<input>"); |
226 | | |
227 | | absl::StatusOr<absl_nonnull SourcePtr> NewSource( |
228 | | const absl::Cord& content, std::string description = "<input>"); |
229 | | |
230 | | } // namespace cel |
231 | | |
232 | | #endif // THIRD_PARTY_CEL_CPP_COMMON_SOURCE_H_ |