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> {}