1use regex_automata::dfa::Automaton;
2use regex_automata::dfa::dense::DFA;
3
4use crate::Hash;
5use crate::Hasher;
6use crate::GLLImplementationError;
7use crate::ImplementationResult;
8use crate::GLLError;
9use crate::from_utf8;
10use crate::GLLBlockLabel;
11use crate::Terminal;
12use crate::GLLResult;
13use crate::HashSet;
14use crate::Rc;
15use crate::Value;
16use std::fmt::Debug;
17
18use crate::GLLState;
19
20pub trait Label<'a>: Debug {
27 fn is_eps(&self) -> bool {
31 false
32 }
33 fn first_set(&self, state: &GLLState<'a>) -> ImplementationResult<'a, Vec<(Vec<GLLBlockLabel<'a>>, Option<Terminal<'a>>)>>;
62 fn code(&self, state: &mut GLLState<'a>) -> GLLResult<'a, ()>;
69 fn first(&self, state: &mut GLLState<'a>) -> GLLResult<'a, bool> {
74 self._first(state, &mut HashSet::default())
75 }
76 fn _first(&self, state: &mut GLLState<'a>, seen: &mut HashSet<Rc<str>>) -> GLLResult<'a, bool> {
83 let fst = self.first_set(state)?;
84 for (alt, fin) in fst {
85 let mut check_fin = true;
86 for sub in alt {
87 let uuid = sub.uuid();
88 if seen.contains(uuid) {
89 continue
90 }
91 seen.insert(uuid.into());
92 if sub._first(state, seen)? {
93 return Ok(true);
94 } else if !sub.is_nullable(state)? {
95 check_fin = false;
96 break;
97 }
98 }
99 if check_fin {
100 if let Some(last) = fin {
101 return Ok(last.is_empty() || state.has_next(last))
102 }
103 }
104 }
105 Ok(false)
106 }
107 fn is_terminal(&self) -> bool {
111 false
112 }
113 fn is_nullable(&self, state: &GLLState<'a>) -> ImplementationResult<'a, bool> {
118 self._is_nullable(state, &mut HashSet::default())
119 }
120
121 fn _is_nullable(&self, state: &GLLState<'a>, seen: &mut HashSet<Rc<str>>) -> ImplementationResult<'a, bool> {
128 if self.is_eps() {
129 Ok(true)
130 } else {
131 let str_repr = self.uuid();
132 if !seen.contains(str_repr) {
133 seen.insert(str_repr.into());
134 let fst = self.first_set(state)?;
135 for (alt, _) in fst {
136 if let Some(sub) = alt.into_iter().next() {
137 if sub._is_nullable(state, seen)? {
138 return Ok(true)
139 }
140 }
141 }
142 }
143 Ok(false)
144 }
145 }
146
147 fn _weight(&self, state: &GLLState<'a>) -> Option<ImplementationResult<'a, Value<'a>>>;
151 fn weight(&self, state: &GLLState<'a>) -> ImplementationResult<'a, Value<'a>> {
156 self._weight(state).map_or_else(|| Ok(1.into()), |weight| weight)
157 }
158 fn to_string(&self) -> &str;
160 fn str_parts(&self) -> Vec<&str>;
162 fn uuid(&self) -> &str;
164 fn attr_rep_map(&self) -> (Vec<&str>, Vec<&str>);
169}
170
171impl<'a> Label<'a> for Terminal<'a> {
172 fn is_eps(&self) -> bool {
173 self.is_empty()
174 }
175
176 fn first_set(&self, _: &GLLState<'a>) -> ImplementationResult<'a, Vec<(Vec<GLLBlockLabel<'a>>, Option<Terminal<'a>>)>> {
177 Ok(vec![(Vec::new(), Some(*self))])
178 }
179
180 fn _first(&self, state: &mut GLLState<'a>, _: &mut HashSet<Rc<str>>) -> GLLResult<'a, bool> {
181 Ok(self.is_eps() || state.has_next(self))
182 }
183
184 fn code(&self, _: &mut GLLState<'a>) -> GLLResult<'a, ()> {
185 Err(GLLError::ImplementationError(GLLImplementationError::Fatal("Attempted running the `code` method on a terminal.")))
186 }
187
188 fn is_terminal(&self) -> bool {
189 true
190 }
191
192 fn to_string(&self) -> &str {
200 #[allow(clippy::expect_used)]
201 from_utf8(self).expect("Terminal was non-utf8")
202 }
203
204 fn _is_nullable(&self, _: &GLLState<'a>, _: &mut HashSet<Rc<str>>) -> ImplementationResult<'a, bool> {
205 Ok(self.is_eps())
206 }
207
208 fn uuid(&self) -> &str {
209 self.to_string()
210 }
211
212 fn str_parts(&self) -> Vec<&str> {
213 vec![self.to_string()]
214 }
215
216 fn attr_rep_map(&self) -> (Vec<&str>, Vec<&str>) {
217 (Vec::new(), Vec::new())
218 }
219
220 fn _weight(&self, _state: &GLLState<'a>) -> Option<ImplementationResult<'a, Value<'a>>> {
221 Some(Err(GLLImplementationError::Fatal("Attempted running the `_weight` method on a terminal.")))
222 }
223}
224
225#[derive(Debug)]
226pub struct RegexTerminal<'a> {
230 pattern: &'a str,
231 pub automaton: DFA<&'a [u32]>
233}
234
235impl<'a> RegexTerminal<'a> {
236 #[must_use]
238 pub const fn new(pattern: &'a str, automaton: DFA<&'a [u32]>) -> Self {
239 Self { pattern, automaton }
240 }
241}
242
243impl<'a> Label<'a> for RegexTerminal<'a> {
244 fn first_set(&self, _: &GLLState<'a>) -> ImplementationResult<'a, Vec<(Vec<GLLBlockLabel<'a>>, Option<Terminal<'a>>)>> {
245 Err(GLLImplementationError::Fatal("Attempted running the `first_set` method on a regex."))
246 }
247
248 fn code(&self, _: &mut GLLState<'a>) -> GLLResult<'a, ()> {
249 Err(GLLError::ImplementationError(GLLImplementationError::Fatal("Attempted running the `code` method on a regex.")))
250 }
251
252 fn _weight(&self, _: &GLLState<'a>) -> Option<ImplementationResult<'a, Value<'a>>> {
253 Some(Err(GLLImplementationError::Fatal("Attempted running the `weight` method on a regex.")))
254 }
255
256 fn to_string(&self) -> &str {
257 self.pattern
258 }
259
260 fn str_parts(&self) -> Vec<&str> {
261 vec![self.to_string()]
262 }
263
264 fn uuid(&self) -> &str {
265 self.to_string()
266 }
267
268 fn attr_rep_map(&self) -> (Vec<&str>, Vec<&str>) {
269 (Vec::new(), Vec::new())
270 }
271 fn is_eps(&self) -> bool {
272 self.automaton.pattern_len() == 0
273 }
274
275 fn _first(&self, state: &mut GLLState<'a>, _: &mut HashSet<Rc<str>>) -> GLLResult<'a, bool> {
278 state.has_regex(self.pattern)
279 }
280
281 fn is_terminal(&self) -> bool {
282 true
283 }
284
285 fn _is_nullable(&self, _: &GLLState<'a>, _: &mut HashSet<Rc<str>>) -> ImplementationResult<'a, bool> {
286 Ok(self.automaton.has_empty())
287 }
288}
289
290impl<'a> Hash for dyn Label<'a> {
291 fn hash<H: Hasher>(&self, state: &mut H) {
292 self.uuid().hash(state);
293 }
294}
295
296impl<'a> PartialEq for dyn Label<'a> {
297 fn eq(&self, other: &Self) -> bool {
298 self.uuid() == other.uuid()
299 }
300}
301
302impl<'a> Eq for dyn Label<'a>{}