Skip to main content

regast_core/
pool.rs

1use std::collections::HashMap;
2
3use regast_syntax::{AnchorKind, ClassSet};
4
5use crate::{IrId, IrKind, Prov, ir::ClassSetId, simp::Rect};
6
7#[derive(Clone, Debug)]
8pub struct IrPool {
9    kinds: Vec<IrKind>,
10    dedup: HashMap<IrKind, IrId>,
11    class_sets: Vec<ClassSet>,
12    class_dedup: HashMap<ClassSet, ClassSetId>,
13    nullable: Vec<Option<bool>>,
14    pub(crate) deriv_memo: HashMap<(IrId, char, bool, bool), IrId>,
15    pub(crate) rects: Vec<Rect>,
16}
17
18impl Default for IrPool {
19    fn default() -> Self {
20        let mut pool = Self {
21            kinds: Vec::new(),
22            dedup: HashMap::new(),
23            class_sets: Vec::new(),
24            class_dedup: HashMap::new(),
25            nullable: Vec::new(),
26            deriv_memo: HashMap::new(),
27            rects: vec![Rect::Id],
28        };
29        pool.intern(IrKind::Zero);
30        pool.intern(IrKind::One);
31        pool
32    }
33}
34
35impl IrPool {
36    #[must_use]
37    pub fn new() -> Self {
38        Self::default()
39    }
40
41    #[must_use]
42    pub const fn zero(&self) -> IrId {
43        IrId(0)
44    }
45
46    #[must_use]
47    pub const fn one(&self) -> IrId {
48        IrId(1)
49    }
50
51    /// Intern a normalized character set.
52    ///
53    /// # Panics
54    ///
55    /// Panics if more than `u32::MAX` distinct sets are interned.
56    pub fn class_set(&mut self, set: ClassSet) -> ClassSetId {
57        if let Some(id) = self.class_dedup.get(&set) {
58            return *id;
59        }
60        let id = ClassSetId(u32::try_from(self.class_sets.len()).expect("class arena exceeds u32"));
61        self.class_sets.push(set.clone());
62        self.class_dedup.insert(set, id);
63        id
64    }
65
66    #[must_use]
67    pub fn get_class_set(&self, id: ClassSetId) -> &ClassSet {
68        &self.class_sets[id.0 as usize]
69    }
70
71    pub fn class(&mut self, set: ClassSetId, prov: Prov) -> IrId {
72        if self.get_class_set(set).is_empty() {
73            return self.zero();
74        }
75        self.intern(IrKind::Class(set, prov))
76    }
77
78    pub fn anchor(&mut self, kind: AnchorKind, prov: Prov) -> IrId {
79        self.intern(IrKind::Anchor(kind, prov))
80    }
81
82    pub fn alt(&mut self, left: IrId, right: IrId, prov: Prov, ordered: bool) -> IrId {
83        self.intern(IrKind::Alt(left, right, prov, ordered))
84    }
85
86    pub fn seq(&mut self, left: IrId, right: IrId, prov: Prov) -> IrId {
87        self.intern(IrKind::Seq(left, right, prov))
88    }
89
90    pub fn star(&mut self, inner: IrId, prov: Prov, greedy: bool) -> IrId {
91        self.intern(IrKind::Star(inner, prov, greedy))
92    }
93
94    pub(crate) fn intern(&mut self, kind: IrKind) -> IrId {
95        if let Some(id) = self.dedup.get(&kind) {
96            return *id;
97        }
98        let id = IrId(u32::try_from(self.kinds.len()).expect("IR arena exceeds u32"));
99        self.kinds.push(kind.clone());
100        self.nullable.push(None);
101        self.dedup.insert(kind, id);
102        id
103    }
104
105    #[must_use]
106    pub fn kind(&self, id: IrId) -> &IrKind {
107        &self.kinds[id.0 as usize]
108    }
109
110    #[must_use]
111    pub fn len(&self) -> usize {
112        self.kinds.len()
113    }
114
115    #[must_use]
116    pub fn is_empty(&self) -> bool {
117        self.kinds.is_empty()
118    }
119
120    /// Return whether `root` accepts the empty string, caching every visited result.
121    ///
122    /// # Panics
123    ///
124    /// Panics only if the IR arena's internal child-reference invariant is broken.
125    pub fn nullable(&mut self, root: IrId) -> bool {
126        if let Some(value) = self.nullable[root.0 as usize] {
127            return value;
128        }
129        let mut stack = vec![(root, false)];
130        while let Some((id, expanded)) = stack.pop() {
131            if self.nullable[id.0 as usize].is_some() {
132                continue;
133            }
134            if !expanded {
135                stack.push((id, true));
136                match self.kind(id) {
137                    IrKind::Alt(left, right, _, _) | IrKind::Seq(left, right, _) => {
138                        stack.push((*right, false));
139                        stack.push((*left, false));
140                    }
141                    IrKind::Zero
142                    | IrKind::One
143                    | IrKind::Anchor(..)
144                    | IrKind::Class(..)
145                    | IrKind::Star(..) => {}
146                }
147                continue;
148            }
149            let value = match self.kind(id) {
150                IrKind::Zero | IrKind::Anchor(..) | IrKind::Class(..) => false,
151                IrKind::One | IrKind::Star(..) => true,
152                IrKind::Alt(left, right, _, _) => {
153                    self.nullable[left.0 as usize].expect("left computed")
154                        || self.nullable[right.0 as usize].expect("right computed")
155                }
156                IrKind::Seq(left, right, _) => {
157                    self.nullable[left.0 as usize].expect("left computed")
158                        && self.nullable[right.0 as usize].expect("right computed")
159                }
160            };
161            self.nullable[id.0 as usize] = Some(value);
162        }
163        self.nullable[root.0 as usize].expect("root computed")
164    }
165
166    pub(crate) fn prefers_empty(&mut self, root: IrId) -> bool {
167        match self.kind(root).clone() {
168            IrKind::One => true,
169            IrKind::Star(_, _, greedy) => !greedy,
170            IrKind::Alt(left, right, _, true) => {
171                if self.nullable(left) {
172                    self.prefers_empty(left)
173                } else {
174                    self.prefers_empty(right)
175                }
176            }
177            IrKind::Seq(left, right, _) => self.prefers_empty(left) && self.prefers_empty(right),
178            IrKind::Zero | IrKind::Anchor(..) | IrKind::Class(..) | IrKind::Alt(..) => false,
179        }
180    }
181
182    pub(crate) fn add_rect(&mut self, rect: Rect) -> crate::simp::RectId {
183        if matches!(rect, Rect::Id) {
184            return crate::simp::RectId(0);
185        }
186        let id = crate::simp::RectId(
187            u32::try_from(self.rects.len()).expect("rectification arena exceeds u32"),
188        );
189        self.rects.push(rect);
190        id
191    }
192
193    #[must_use]
194    pub(crate) fn rect(&self, id: crate::simp::RectId) -> &Rect {
195        &self.rects[id.0 as usize]
196    }
197
198    #[must_use]
199    pub fn display(&self, root: IrId) -> String {
200        match self.kind(root) {
201            IrKind::Zero => "0".into(),
202            IrKind::One => "1".into(),
203            IrKind::Anchor(kind, _) => format!("{kind:?}"),
204            IrKind::Class(..) => "class".into(),
205            IrKind::Alt(left, right, _, _) => {
206                format!("({}+{})", self.display(*left), self.display(*right))
207            }
208            IrKind::Seq(left, right, _) => {
209                format!("({}ยท{})", self.display(*left), self.display(*right))
210            }
211            IrKind::Star(inner, _, greedy) => format!(
212                "({})*{}",
213                self.display(*inner),
214                if *greedy { "" } else { "?" }
215            ),
216        }
217    }
218}