1use std::{hash::Hash, ops::Deref};
2
3use iregex_automata::{
4 nfa::{BuildNFA, StateBuilder, Tags},
5 Class, Map, Token, NFA,
6};
7
8use crate::{Atom, Boundary, CaptureTag, Concatenation};
9
10#[derive(Debug, Clone)]
12pub struct Alternation<T = char, B = ()>(Vec<Concatenation<T, B>>);
13
14impl<T, B> Default for Alternation<T, B> {
15 fn default() -> Self {
16 Self(Vec::new())
17 }
18}
19
20impl<T, B> Alternation<T, B> {
21 pub fn new() -> Self {
22 Self::default()
23 }
24}
25
26impl<T, B> From<Concatenation<T, B>> for Alternation<T, B> {
27 fn from(value: Concatenation<T, B>) -> Self {
28 Self(vec![value])
29 }
30}
31
32impl<T, B> From<Atom<T, B>> for Alternation<T, B> {
33 fn from(value: Atom<T, B>) -> Self {
34 Self(vec![value.into()])
35 }
36}
37
38impl<T, B> Deref for Alternation<T, B> {
39 type Target = [Concatenation<T, B>];
40
41 fn deref(&self) -> &Self::Target {
42 self.0.as_slice()
43 }
44}
45
46impl<'a, T, B> IntoIterator for &'a Alternation<T, B> {
47 type IntoIter = std::slice::Iter<'a, Concatenation<T, B>>;
48 type Item = &'a Concatenation<T, B>;
49
50 fn into_iter(self) -> Self::IntoIter {
51 self.0.iter()
52 }
53}
54
55impl<T, B> IntoIterator for Alternation<T, B> {
56 type IntoIter = std::vec::IntoIter<Concatenation<T, B>>;
57 type Item = Concatenation<T, B>;
58
59 fn into_iter(self) -> Self::IntoIter {
60 self.0.into_iter()
61 }
62}
63
64impl<T, B> FromIterator<Concatenation<T, B>> for Alternation<T, B> {
65 fn from_iter<I: IntoIterator<Item = Concatenation<T, B>>>(iter: I) -> Self {
66 Self(Vec::from_iter(iter))
67 }
68}
69
70impl<T, B, Q, C> BuildNFA<T, Q, C, CaptureTag> for Alternation<T, B>
71where
72 T: Token,
73 B: Boundary<T, Class = C>,
74 Q: Copy + Ord,
75 C: Clone + Eq + Hash + Class<T>,
76{
77 fn build_nfa_from<S: StateBuilder<T, Q, C>>(
78 &self,
79 state_builder: &mut S,
80 nfa: &mut NFA<Q, T>,
81 tags: &mut Tags<Q, CaptureTag>,
82 class: &C,
83 ) -> Result<(Q, C::Map<Q>), S::Error> {
84 match self.0.as_slice() {
85 [] => {
86 let a = state_builder.next_state(nfa, class.clone())?;
87 Ok((a, Default::default()))
88 }
89 [concat] => concat.build_nfa_from(state_builder, nfa, tags, class),
90 list => {
91 let a = state_builder.next_state(nfa, class.clone())?;
92 let mut output: C::Map<Q> = Default::default();
93
94 for concat in list {
95 let (concat_a, concat_b_map) =
96 concat.build_nfa_from(state_builder, nfa, tags, class)?;
97 nfa.add(a, None, concat_a);
98
99 for (b_class, concat_b) in concat_b_map.into_entries() {
100 let b = *output.get_or_try_insert_with(&b_class, || {
101 state_builder.next_state(nfa, b_class.clone())
102 })?;
103
104 nfa.add(concat_b, None, b);
105 }
106 }
107
108 Ok((a, output))
109 }
110 }
111 }
112}