lady_deirdre/syntax/rule.rs
1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Lady Deirdre", a compiler front-end foundation //
3// technology. //
4// //
5// This work is proprietary software with source-available code. //
6// //
7// To copy, use, distribute, or contribute to this work, you must agree to //
8// the terms of the General License Agreement: //
9// //
10// https://github.com/Eliah-Lakhin/lady-deirdre/blob/master/EULA.md //
11// //
12// The agreement grants a Basic Commercial License, allowing you to use //
13// this work in non-commercial and limited commercial products with a total //
14// gross revenue cap. To remove this commercial limit for one of your //
15// products, you must acquire a Full Commercial License. //
16// //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions. //
19// Contributions are governed by the "Contributions" section of the General //
20// License Agreement. //
21// //
22// Copying the work in parts is strictly forbidden, except as permitted //
23// under the General License Agreement. //
24// //
25// If you do not or cannot agree to the terms of this Agreement, //
26// do not use this work. //
27// //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid. //
30// //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин). //
32// All rights reserved. //
33////////////////////////////////////////////////////////////////////////////////
34
35use std::{
36 fmt::{Debug, Display, Formatter},
37 iter::FusedIterator,
38 marker::PhantomData,
39};
40
41use crate::syntax::AbstractNode;
42
43/// A numeric type that denotes a syntax parsing rule within the programming
44/// language grammar.
45///
46/// See the [Parse rules](crate::syntax::SyntaxSession#parse-rules) section of
47/// the parsing process specification for details.
48pub type NodeRule = u16;
49
50/// A static set of the syntax node rules without entries.
51///
52/// The value of this static equals to the [NodeSet::empty] value.
53pub static EMPTY_NODE_SET: NodeSet = NodeSet::empty();
54
55/// Denotes a syntax parse rule of the root node of the syntax tree.
56///
57/// See the [Parse rules](crate::syntax::SyntaxSession#parse-rules) section of
58/// the parsing process specification for details.
59pub const ROOT_RULE: NodeRule = 0;
60
61/// Denotes an invalid syntax parse rule.
62///
63/// This number does not belong to any syntax parse rule of any
64/// programming language.
65///
66/// See the [Parse rules](crate::syntax::SyntaxSession#parse-rules) section of
67/// the parsing process specification for details.
68pub const NON_RULE: NodeRule = NodeRule::MAX;
69
70/// A set of syntax parse [rules](NodeRule) of fixed size.
71///
72/// The set stores all entries in place, and the set object has a fixed size.
73///
74/// The maximum number of rules the object could store is [NodeSet::LIMIT].
75///
76/// Most methods of this object are the const functions. Some of them take up to
77/// `O(LIMIT)` and `O(LIMIT^2)` time to perform.
78///
79/// The object is assumed to be constructed in a const context as a static value
80/// upfront to reduce the runtime overhead.
81#[repr(transparent)]
82#[derive(Default, Clone, Copy, PartialEq, Eq)]
83pub struct NodeSet {
84 vector: [NodeRule; Self::LIMIT],
85}
86
87impl Debug for NodeSet {
88 #[inline]
89 fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
90 let mut debug_list = formatter.debug_list();
91
92 let mut entry = 0;
93
94 while entry < Self::LIMIT {
95 let probe = &self.vector[entry];
96
97 if probe == &NON_RULE {
98 break;
99 }
100
101 debug_list.entry(probe);
102
103 entry += 1;
104 }
105
106 debug_list.finish()
107 }
108}
109
110impl<'set> IntoIterator for &'set NodeSet {
111 type Item = NodeRule;
112 type IntoIter = NodeSetIter<'set>;
113
114 #[inline(always)]
115 fn into_iter(self) -> Self::IntoIter {
116 NodeSetIter { set: self, next: 0 }
117 }
118}
119
120impl FromIterator<NodeRule> for NodeSet {
121 #[inline(always)]
122 fn from_iter<I: IntoIterator<Item = NodeRule>>(iter: I) -> Self {
123 let mut result = Self::empty();
124
125 for rule in iter {
126 result = result.include(rule)
127 }
128
129 result
130 }
131}
132
133impl NodeSet {
134 /// The maximum number of entries this set can address.
135 ///
136 /// This number may be increased in future minor versions of Lady Deirdre.
137 pub const LIMIT: usize = 16;
138
139 /// Creates a node set without entries.
140 ///
141 /// If you need just a static empty node set, use the predefined
142 /// [EMPTY_NODE_SET] static.
143 #[inline(always)]
144 pub const fn empty() -> Self {
145 Self {
146 vector: [NON_RULE; Self::LIMIT],
147 }
148 }
149
150 /// Constructs a node set from the slice of the node rules.
151 ///
152 /// **Panic**
153 ///
154 /// Panics if the `rules` parameter has more than the [LIMIT](Self::LIMIT)
155 /// number of unique node rules.
156 ///
157 /// Panics if any value within the `rules` slice is a [NON_RULE].
158 #[inline(always)]
159 pub const fn new(rules: &[NodeRule]) -> Self {
160 Self::empty().include_all(rules)
161 }
162
163 /// Returns true if the node set contains the specified node `rule`.
164 #[inline(always)]
165 pub const fn contains(&self, rule: NodeRule) -> bool {
166 if rule == NON_RULE {
167 return false;
168 }
169
170 let mut entry = 0;
171
172 while entry < Self::LIMIT {
173 let probe = self.vector[entry];
174
175 if probe == NON_RULE {
176 break;
177 }
178
179 if probe == rule {
180 return true;
181 }
182
183 entry += 1;
184 }
185
186 false
187 }
188
189 /// Consumes this NodeSet instance and returns a new node set that
190 /// includes the `rule` node rule.
191 ///
192 /// **Panic**
193 ///
194 /// Panics if the `rule` argument is a [NON_RULE].
195 ///
196 /// Panics if the node set already has a [LIMIT](Self::LIMIT) number of
197 /// unique entries, and the `rule` argument is a new entry within this set.
198 #[inline(always)]
199 pub const fn include(mut self, mut rule: NodeRule) -> Self {
200 if rule == NON_RULE {
201 panic!("Non-rule cannot be inserted into the rule set.");
202 }
203
204 let mut entry = 0;
205
206 while entry < Self::LIMIT {
207 let mut probe = self.vector[entry];
208
209 if probe == rule {
210 return self;
211 }
212
213 if probe > rule {
214 while entry < Self::LIMIT {
215 probe = self.vector[entry];
216 self.vector[entry] = rule;
217
218 if probe == NON_RULE {
219 return self;
220 }
221
222 rule = probe;
223 entry += 1;
224 }
225
226 break;
227 }
228
229 entry += 1;
230 }
231
232 panic!("Too many rules in the rule set.");
233 }
234
235 /// Consumes this NodeSet instance and returns a new node set that
236 /// includes all node rules from the `rules` slice.
237 ///
238 /// **Panic**
239 ///
240 /// Panics if any rule number within the slice argument is a [NON_RULE].
241 ///
242 /// Panics if the total number if unique entries within this node set and
243 /// the rules from the `rules` slice exceeds [LIMIT](Self::LIMIT).
244 #[inline(always)]
245 pub const fn include_all(mut self, rules: &[NodeRule]) -> Self {
246 let mut slice_index = 0;
247
248 while slice_index < rules.len() {
249 self = self.include(rules[slice_index]);
250 slice_index += 1;
251 }
252
253 self
254 }
255
256 /// Consumes this NodeSet instance and returns a new node set without
257 /// the specified `rule` node rule.
258 #[inline(always)]
259 pub const fn exclude(mut self, rule: NodeRule) -> Self {
260 if rule == NON_RULE {
261 return self;
262 }
263
264 let mut entry = 0;
265
266 while entry < Self::LIMIT {
267 let mut probe = self.vector[entry];
268
269 if probe > rule {
270 break;
271 }
272
273 if probe == rule {
274 loop {
275 let next = entry + 1;
276
277 probe = match next < Self::LIMIT {
278 true => self.vector[next],
279 false => NON_RULE,
280 };
281
282 self.vector[entry] = probe;
283
284 if probe == NON_RULE {
285 break;
286 }
287
288 entry = next;
289 }
290
291 break;
292 }
293
294 entry += 1;
295 }
296
297 self
298 }
299
300 /// Consumes this NodeSet instance and returns a new node set without
301 /// the entries specified in the `rules` node rule slice.
302 #[inline(always)]
303 pub const fn exclude_all(mut self, rules: &[NodeRule]) -> Self {
304 let mut slice_index = 0;
305
306 while slice_index < rules.len() {
307 self = self.exclude(rules[slice_index]);
308 slice_index += 1;
309 }
310
311 self
312 }
313
314 /// Returns true if the NodeSet has no entries.
315 #[inline(always)]
316 pub const fn is_empty(&self) -> bool {
317 self.vector[0] == NON_RULE
318 }
319
320 /// Returns the number of entries in this NodeSet instance.
321 #[inline(always)]
322 pub const fn len(&self) -> usize {
323 let mut length = 0;
324
325 while length < Self::LIMIT {
326 if self.vector[length] == NON_RULE {
327 break;
328 }
329
330 length += 1;
331 }
332
333 length
334 }
335
336 /// Returns an object that displays all entries within this node set.
337 ///
338 /// The `N` generic parameter specifies the syntax grammar of
339 /// the programming language (see [Node](crate::syntax::Node)).
340 ///
341 /// The underlying displaying algorithm uses
342 /// the [rule_name](AbstractNode::rule_name) function to determine
343 /// the rules' display names.
344 #[inline(always)]
345 pub fn display<N: AbstractNode>(&self) -> impl Debug + Display + '_ {
346 pub struct DisplayNodeSet<'set, N> {
347 set: &'set NodeSet,
348 _token: PhantomData<N>,
349 }
350
351 impl<'set, N: AbstractNode> Debug for DisplayNodeSet<'set, N> {
352 #[inline(always)]
353 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
354 Display::fmt(self, formatter)
355 }
356 }
357
358 impl<'set, N: AbstractNode> Display for DisplayNodeSet<'set, N> {
359 fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
360 let mut vector = Vec::with_capacity(NodeSet::LIMIT);
361
362 for rule in self.set {
363 if let Some(name) = N::rule_name(rule) {
364 vector.push(name);
365 }
366 }
367
368 vector.sort();
369
370 formatter.debug_set().entries(vector).finish()
371 }
372 }
373
374 DisplayNodeSet {
375 set: self,
376 _token: PhantomData::<N>,
377 }
378 }
379}
380
381pub struct NodeSetIter<'set> {
382 set: &'set NodeSet,
383 next: usize,
384}
385
386impl<'set> Iterator for NodeSetIter<'set> {
387 type Item = NodeRule;
388
389 fn next(&mut self) -> Option<Self::Item> {
390 if self.next == NodeSet::LIMIT {
391 return None;
392 }
393
394 let probe = self.set.vector[self.next];
395
396 if probe == NON_RULE {
397 return None;
398 }
399
400 self.next += 1;
401
402 Some(probe)
403 }
404}
405
406impl<'set> FusedIterator for NodeSetIter<'set> {}