Skip to main content

flams_utils/parsing/
string.rs

1use crate::{
2    CharExt,
3    parsing::SourceParser,
4    sourcerefs::{PositionKind, StringPosition},
5};
6
7pub struct StrParser<'a, P: StringPosition> {
8    input: &'a str,
9    pub pos: P,
10}
11
12impl<'a, P: StringPosition> StrParser<'a, P> {
13    #[must_use]
14    pub fn new(input: &'a str) -> Self {
15        Self {
16            input,
17            pos: P::default(),
18        }
19    }
20    #[inline]
21    pub const fn rest(&self) -> &'a str {
22        self.input
23    }
24
25    pub fn read_until_is(&mut self, mut pred: impl FnMut(&'a str) -> bool) -> &'a str {
26        let mut curr = self.input;
27        while !curr.is_empty() {
28            if pred(curr) {
29                let ret = &self.input[..self.input.len() - curr.len()];
30                self.input = curr;
31                self.pos += P::len(ret);
32                return ret;
33            }
34            if let Some(next) = curr.chars().next() {
35                curr = &curr[next.len_utf8()..];
36            }
37        }
38        self.pos += P::len(self.input);
39        std::mem::take(&mut self.input)
40    }
41
42    pub fn preview_until_with_brackets(
43        &self,
44        open: char,
45        close: char,
46        mut pred: impl FnMut(char) -> bool,
47    ) -> &'a str {
48        let mut depth = 0;
49        let i = self
50            .input
51            .find(|c| {
52                if c == open {
53                    depth += 1;
54                    false
55                } else if c == close && depth > 0 {
56                    depth -= 1;
57                    false
58                } else {
59                    depth == 0 && pred(c)
60                }
61            })
62            .unwrap_or(self.input.len());
63        let (l, _r) = self.input.split_at(i);
64        l
65    }
66
67    pub fn read_until_escaped(&mut self, find: char, escape: char) -> &'a str {
68        let mut chars = self.input.chars();
69        let mut i: usize = 0;
70        while let Some(c) = chars.next() {
71            if c == escape {
72                if let Some(c) = chars.next() {
73                    i += c.len_utf8();
74                }
75            } else if c == find {
76                let (l, r) = self.input.split_at(i);
77                self.input = r;
78                self.pos += P::len(l);
79                return l;
80            }
81            i += c.len_utf8();
82        }
83        let ret = self.input;
84        self.input = "";
85        self.pos += P::len(ret);
86        ret
87    }
88}
89
90impl<'a, P: StringPosition> SourceParser<'a> for StrParser<'a, P> {
91    type Pos = P;
92    type Str = &'a str;
93    type Source = &'a str;
94
95    #[inline]
96    fn curr_pos(&self) -> P {
97        self.pos
98    }
99
100    #[inline]
101    fn starts_with_str(&mut self, s: &str) -> bool {
102        self.input.starts_with(s)
103    }
104    fn drop_prefix(&mut self, s: &str) -> bool {
105        self.input.starts_with(s) && {
106            self.input = &self.input[s.len()..];
107            self.pos += P::len(s);
108            true
109        }
110    }
111
112    fn next_char(&mut self) -> Option<char> {
113        if self.input.starts_with(['\r', '\n']) {
114            if self.input.starts_with("\r\n") {
115                self.input = &self.input[2..];
116                self.pos.inc_newline(true);
117            } else {
118                self.input = &self.input[1..];
119                self.pos.inc_newline(false);
120            }
121            return Some('\n');
122        }
123        self.input.chars().next().inspect(|c| {
124            self.pos.inc_by(*c);
125            self.input = &self.input[c.len_utf8()..];
126        })
127    }
128
129    fn read_until_line_end(&mut self) -> (&'a str, P) {
130        if let Some(i) = memchr::memchr2(b'\r', b'\n', self.input.as_bytes()) {
131            if self.input.as_bytes()[i] == b'\r'
132                && self.input.as_bytes().get(i + 1).copied() == Some(b'\n')
133            {
134                let (l, r) = self.input.split_at(i);
135                self.input = &r[2..];
136                self.pos.inc_offset_by(l);
137                let pos = self.pos;
138                self.pos.inc_newline(true);
139                return (l, pos);
140            }
141            let (l, r) = self.input.split_at(i);
142            self.input = &r[1..];
143            self.pos.inc_offset_by(l);
144            let pos = self.pos;
145            self.pos.inc_newline(false);
146            (l, pos)
147        } else {
148            let ret = self.input;
149            self.pos.inc_offset_by(ret);
150            self.input = "";
151            (ret, self.pos)
152        }
153    }
154
155    fn read_until_byte(&mut self, b: u8) -> Self::Str {
156        if let Some(i) = memchr::memchr(b, self.input.as_bytes()) {
157            let (l, r) = self.input.split_at(i);
158            self.input = r;
159            self.pos += P::len(l);
160            l
161        } else {
162            let ret = self.input;
163            self.pos += P::len(ret);
164            self.input = "";
165            ret
166        }
167    }
168    fn read_until_char(&mut self, c: char) -> Self::Str {
169        let bytes = c.into_bytes();
170        let del = bytes[0];
171        for i in memchr::memchr_iter(del, self.input.as_bytes()) {
172            if self.input.as_bytes()[i..].starts_with(&bytes) {
173                let (l, r) = self.input.split_at(i);
174                self.input = r;
175                self.pos += P::len(l);
176                return l;
177            }
178        }
179        let ret = self.input;
180        self.pos += P::len(ret);
181        self.input = "";
182        ret
183    }
184
185    fn read_until_byte_with_brackets(&mut self, needle: u8, open: u8, close: u8) -> Self::Str {
186        let mut in_brackets = 0;
187        let mut curroff = 0;
188        let bytes = self.input.as_bytes();
189        loop {
190            if in_brackets == 0 {
191                if let Some(i) = memchr::memchr2(needle, open, &bytes[curroff..]) {
192                    curroff += i;
193                    let b = bytes[curroff];
194                    if b == needle {
195                        let (l, r) = self.input.split_at(curroff);
196                        self.input = r;
197                        self.pos += P::len(l);
198                        return l;
199                    }
200                    curroff += 1;
201                    in_brackets += 1;
202                } else {
203                    let ret = self.input;
204                    self.input = "";
205                    self.pos += P::len(ret);
206                    return ret;
207                }
208            } else if let Some(i) = memchr::memchr2(open, close, &bytes[curroff..]) {
209                curroff += i;
210                let b = bytes[curroff];
211                curroff += 1;
212                if b == open {
213                    in_brackets += 1;
214                } else {
215                    in_brackets -= 1;
216                }
217            } else {
218                let ret = self.input;
219                self.input = "";
220                self.pos += P::len(ret);
221                return ret;
222            }
223        }
224    }
225
226    fn read_until_inclusive(&mut self, pred: impl FnMut(char) -> bool) -> &'a str {
227        let i = self.input.find(pred).unwrap_or(self.input.len());
228        let (l, r) = self.input.split_at(i + 1);
229        self.input = r;
230        self.pos += P::len(l);
231        l
232    }
233
234    fn trim_start(&mut self) {
235        if P::KIND == PositionKind::None {
236            self.input = self.input.trim_start();
237            return;
238        }
239        if P::KIND == PositionKind::Byte {
240            let old = self.input;
241            self.input = self.input.trim_start();
242            let trimmed = &old[..old.len() - self.input.len()];
243            self.pos += P::len(trimmed);
244            return;
245        }
246        while let Some(c) = self.input.chars().next() {
247            if c == '\n' {
248                self.input = &self.input[1..];
249                self.pos.inc_newline(false);
250            } else if c == '\r' {
251                self.input = &self.input[1..];
252                if self.input.starts_with('\n') {
253                    self.input = &self.input[1..];
254                    self.pos.inc_newline(true);
255                } else {
256                    self.pos.inc_newline(false);
257                }
258            } else if c.is_whitespace() {
259                self.input = &self.input[c.len_utf8()..];
260                self.pos.inc_by(c);
261            } else {
262                break;
263            }
264        }
265    }
266    fn starts_with(&mut self, c: char) -> bool {
267        self.input.starts_with(c)
268    }
269    fn read_while(&mut self, mut pred: impl FnMut(char) -> bool) -> Self::Str {
270        let i = self.input.find(|c| !pred(c)).unwrap_or(self.input.len());
271        let (l, r) = self.input.split_at(i);
272        self.input = r;
273        self.pos += P::len(l);
274        l
275    }
276    fn read_until_with_brackets(
277        &mut self,
278        open: char,
279        close: char,
280        mut pred: impl FnMut(char) -> bool,
281    ) -> Self::Str {
282        let mut depth = 0;
283        let i = self
284            .input
285            .find(|c| {
286                if c == close && depth > 0 {
287                    depth -= 1;
288                    false
289                } else if c == open {
290                    depth += 1;
291                    false
292                } else {
293                    depth == 0 && pred(c)
294                }
295            })
296            .unwrap_or(self.input.len());
297        let (l, r) = self.input.split_at(i);
298        self.input = r;
299        self.pos += P::len(l);
300        l
301    }
302    fn peek_head(&mut self) -> Option<char> {
303        self.input.chars().next()
304    }
305    fn read_n(&mut self, i: usize) -> Self::Str {
306        let (l, mut r) = self.input.split_at(i);
307        if l.ends_with('\r') && r.starts_with('\n') {
308            r = &r[1..];
309        }
310        self.input = r;
311        self.pos += P::len(l);
312        l
313    }
314
315    fn read_until_str(&mut self, s: &str) -> Self::Str {
316        if let Some(i) = self.input.find(s) {
317            let (l, r) = self.input.split_at(i);
318            self.input = r;
319            self.pos += P::len(l);
320            l
321        } else {
322            let ret = self.input;
323            self.input = "";
324            self.pos += P::len(ret);
325            ret
326        }
327    }
328
329    fn read_until_needle(&mut self, s: &super::Needle) -> Self::Str {
330        if let Some(i) = s.find_in(self.input) {
331            let (l, r) = self.input.split_at(i);
332            self.input = r;
333            self.pos += P::len(l);
334            l
335        } else {
336            let ret = self.input;
337            self.input = "";
338            self.pos += P::len(ret);
339            ret
340        }
341    }
342
343    fn skip(&mut self, i: usize) {
344        let (a, b) = self.input.split_at(i);
345        self.input = b;
346        self.pos += P::len(a);
347    }
348}