1use crate::{
4 matcher::FindAllPartMatch,
5 token_entry::{Source, TokenStringBuilder},
6 utils::is_empty,
7 Rule,
8};
9use std::{
10 borrow::Cow,
11 fmt::{Debug, Display, Formatter},
12 mem::take,
13 ops::Range,
14};
15
16#[derive(Debug)]
17pub(crate) struct MatchAllBuilder<'a> {
18 source: Source<'a>,
19 parts: Vec<RawPart>,
20 changes: Vec<RawChangedPart>,
21
22 no_match_tes_start: usize,
23 no_match_tes_end: usize,
24}
25
26impl<'a> MatchAllBuilder<'a> {
27 pub fn new(source: Source<'a>) -> Self {
28 Self {
29 source,
30 parts: Vec::new(),
31 changes: Vec::new(),
32 no_match_tes_start: 0,
33 no_match_tes_end: 0,
34 }
35 }
36 pub fn push_no_match(&mut self, tes_len: usize) {
37 self.no_match_tes_end += tes_len;
38 }
39 fn commit_no_match(&mut self) {
40 let tes_range = self
41 .source
42 .unchanged_tes_range_in(self.no_match_tes_start..self.no_match_tes_end);
43 self.push_transform(self.no_match_tes_start..tes_range.start);
44 self.push_unchanged(tes_range.clone());
45 self.push_transform(tes_range.end..self.no_match_tes_end);
46 let tes_offset = self.no_match_tes_end;
47 self.no_match_tes_start = tes_offset;
48 self.no_match_tes_end = tes_offset;
49 }
50 pub fn push_match(&mut self, m: FindAllPartMatch) {
51 self.commit_no_match();
52 let tes_start = self.no_match_tes_end;
53 let tes_end = tes_start + m.tes_len;
54 self.changes.push(RawChangedPart {
55 tes_range: tes_start..tes_end,
56 m: Some(m),
57 });
58 self.no_match_tes_start = tes_end;
59 self.no_match_tes_end = tes_end;
60 }
61 fn push_transform(&mut self, tes_range: Range<usize>) {
62 if is_empty(&tes_range) {
63 return;
64 }
65 self.changes.push(RawChangedPart { tes_range, m: None });
66 }
67 fn push_unchanged(&mut self, tes_range: Range<usize>) {
68 if is_empty(&tes_range) {
69 return;
70 }
71 self.commit_changes();
72 self.parts.push(RawPart::Unchanged { tes_range });
73 }
74 fn commit_changes(&mut self) {
75 if !self.changes.is_empty() {
76 let tes_start = self.changes[0].tes_range.start;
77 let tes_end = self.changes[self.changes.len() - 1].tes_range.end;
78 self.parts.push(RawPart::Changed(RawChanged {
79 tes_range: tes_start..tes_end,
80 parts: take(&mut self.changes),
81 }));
82 }
83 }
84 pub fn finish(mut self, rule: &'a Rule) -> MatchAll<'a> {
85 self.commit_no_match();
86 self.commit_changes();
87 MatchAll {
88 source: self.source,
89 rule,
90 parts: self.parts,
91 }
92 }
93}
94
95pub struct MatchAll<'a> {
97 source: Source<'a>,
98 rule: &'a Rule,
99 parts: Vec<RawPart>,
100}
101
102impl<'a> MatchAll<'a> {
103 pub fn input(&self) -> &str {
105 self.source.as_str()
106 }
107
108 pub fn output(&self) -> String {
110 let mut b = TokenStringBuilder::new(&self.source);
111 for p in self.iter() {
112 p.output_to(&mut b);
113 }
114 b.s
115 }
116 pub fn iter(&self) -> impl Iterator<Item = MatchAllPart> {
117 self.parts
118 .iter()
119 .map(|part| match part {
120 RawPart::Unchanged { tes_range } => MatchAllPart::Unchanged(Unchanged {
121 ma: self,
122 tes_range: tes_range.clone(),
123 }),
124 RawPart::Changed(p) => MatchAllPart::Changed(Changed { ma: self, p }),
125 })
126 .collect::<Vec<_>>()
127 .into_iter()
128 }
129}
130impl Debug for MatchAll<'_> {
131 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
132 f.debug_list().entries(self.iter()).finish()
133 }
134}
135
136#[derive(Debug)]
137enum RawPart {
138 Unchanged { tes_range: Range<usize> },
139 Changed(RawChanged),
140}
141
142#[derive(Debug)]
143struct RawChanged {
144 tes_range: Range<usize>,
145 parts: Vec<RawChangedPart>,
146}
147#[derive(Debug)]
148struct RawChangedPart {
149 tes_range: Range<usize>,
150 m: Option<FindAllPartMatch>,
151}
152
153#[derive(Debug)]
155pub enum MatchAllPart<'a> {
156 Unchanged(Unchanged<'a>),
157 Changed(Changed<'a>),
158}
159
160impl<'a> MatchAllPart<'a> {
161 pub fn input(&self) -> &str {
163 match self {
164 MatchAllPart::Unchanged(u) => u.as_str(),
165 MatchAllPart::Changed(c) => c.input(),
166 }
167 }
168
169 pub fn output(&self) -> Cow<str> {
171 match self {
172 MatchAllPart::Unchanged(u) => Cow::Borrowed(u.as_str()),
173 MatchAllPart::Changed(c) => Cow::Owned(c.output()),
174 }
175 }
176 fn output_to(&self, sb: &mut TokenStringBuilder) {
177 match self {
178 MatchAllPart::Unchanged(u) => sb.push_str(u.as_str()),
179 MatchAllPart::Changed(c) => c.output_to(sb),
180 }
181 }
182}
183
184pub struct Unchanged<'a> {
186 ma: &'a MatchAll<'a>,
187 tes_range: Range<usize>,
188}
189impl<'a> Unchanged<'a> {
190 pub fn as_str(&self) -> &str {
191 self.ma.source.get_source(self.tes_range.clone())
192 }
193}
194impl Display for Unchanged<'_> {
195 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
196 write!(f, "{}", self.as_str())
197 }
198}
199impl Debug for Unchanged<'_> {
200 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
201 write!(f, "{}", self.as_str())
202 }
203}
204
205pub struct Changed<'a> {
207 ma: &'a MatchAll<'a>,
208 p: &'a RawChanged,
209}
210
211impl<'a> Changed<'a> {
212 pub fn input(&self) -> &str {
214 self.ma.source.get_source(self.p.tes_range.clone())
215 }
216
217 pub fn output(&self) -> String {
219 let mut b = TokenStringBuilder::new(&self.ma.source);
220 self.output_to(&mut b);
221 b.s
222 }
223 fn output_to(&self, b: &mut TokenStringBuilder) {
224 for p in &self.p.parts {
225 if let Some(m) = &p.m {
226 m.apply_string(self.ma.rule, b);
227 } else {
228 b.push_tes(p.tes_range.clone());
229 }
230 }
231 }
232
233 pub fn iter(&self) -> impl Iterator<Item = ChangedPart> {
234 let ma = &self.ma;
235 self.p.parts.iter().map(|p| {
236 if let Some(m) = &p.m {
237 ChangedPart::Match(Match { ma, m })
238 } else {
239 ChangedPart::Transform(Transform {
240 ma,
241 tes_range: p.tes_range.clone(),
242 })
243 }
244 })
245 }
246}
247impl Debug for Changed<'_> {
248 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
249 f.debug_struct("Changed")
250 .field("input", &self.input())
251 .field("output", &self.output())
252 .field("iter", &self.iter().collect::<Vec<_>>())
253 .finish()
254 }
255}
256
257#[derive(Debug)]
259pub enum ChangedPart<'a> {
260 Transform(Transform<'a>),
261 Match(Match<'a>),
262}
263
264pub struct Transform<'a> {
266 ma: &'a MatchAll<'a>,
267 tes_range: Range<usize>,
268}
269
270impl<'a> Transform<'a> {
271 #[allow(clippy::inherent_to_string)]
272 pub fn to_string(&self) -> String {
273 let mut b = TokenStringBuilder::new(&self.ma.source);
274 b.push_tes(self.tes_range.clone());
275 b.s
276 }
277}
278impl Debug for Transform<'_> {
279 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
280 f.write_str(&self.to_string())
281 }
282}
283
284pub struct Match<'a> {
286 ma: &'a MatchAll<'a>,
287 m: &'a FindAllPartMatch,
288}
289
290impl<'a> Match<'a> {
291 #[allow(clippy::inherent_to_string)]
292 pub fn to_string(&self) -> String {
293 let mut b = TokenStringBuilder::new(&self.ma.source);
294 self.m.apply_string(self.ma.rule, &mut b);
295 b.s
296 }
297}
298impl Debug for Match<'_> {
299 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
300 f.write_str(&self.to_string())
301 }
302}