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