1use std::iter::Peekable;
4use std::ops::RangeInclusive;
5
6pub trait Chomper {
7 fn accept(&self, ch: char) -> bool;
8}
9
10pub fn chomp<Iter>(chomper: &dyn Chomper, peekable: &mut Peekable<Iter>) -> usize
11where
12 Iter: Iterator<Item = (usize, char)>,
13{
14 let mut cur = 0;
15 while let Some((idx, ch)) = peekable.peek() {
16 cur = *idx;
17
18 if !chomper.accept(*ch) {
19 return cur;
20 }
21
22 peekable.next();
23 }
24
25 cur + 1
26}
27
28pub fn chomp_until<Iter>(chomper: &dyn Chomper, peekable: &mut Peekable<Iter>) -> usize
29where
30 Iter: Iterator<Item = (usize, char)>,
31{
32 let mut cur = 0;
33 while let Some((idx, ch)) = peekable.peek() {
34 cur = *idx;
35
36 if chomper.accept(*ch) {
37 return cur;
38 }
39
40 peekable.next();
41 }
42
43 cur + 1
44}
45
46pub fn chomp_str<Iter>(chomper: &dyn Chomper, peekable: &mut Peekable<Iter>) -> String
47where
48 Iter: Iterator<Item = (usize, char)>,
49{
50 let mut accepted = String::new();
51
52 while let Some((_, ch)) = peekable.peek() {
53 if chomper.accept(*ch) {
54 accepted.push(*ch);
55 peekable.next();
56 } else {
57 break;
58 }
59 }
60
61 accepted
62}
63
64pub struct Multi<'a, C: Chomper>(pub &'a [&'a C]);
65
66impl Chomper for RangeInclusive<char> {
67 fn accept(&self, ch: char) -> bool {
68 self.contains(&ch)
69 }
70}
71
72impl Chomper for [char] {
73 fn accept(&self, ch: char) -> bool {
74 self.contains(&ch)
75 }
76}
77
78impl Chomper for &[char; 1] {
79 fn accept(&self, ch: char) -> bool {
80 self.contains(&ch)
81 }
82}
83
84impl Chomper for &[char; 2] {
85 fn accept(&self, ch: char) -> bool {
86 self.contains(&ch)
87 }
88}
89
90impl Chomper for &[char; 3] {
91 fn accept(&self, ch: char) -> bool {
92 self.contains(&ch)
93 }
94}
95
96impl<C: Chomper> Chomper for Multi<'_, C> {
97 fn accept(&self, ch: char) -> bool {
98 for sub in self.0 {
99 if sub.accept(ch) {
100 return true;
101 }
102 }
103
104 false
105 }
106}
107
108impl<A: Chomper, B: Chomper> Chomper for (A, B) {
109 fn accept(&self, ch: char) -> bool {
110 self.0.accept(ch) || self.1.accept(ch)
111 }
112}
113
114#[inline]
119pub fn chomp_until_escaped<T: Iterator<Item = (usize, char)>>(
120 iter: &mut Peekable<T>,
121 terminator: char,
122 escapable: &[char], ) -> Result<String, String> {
124 let mut accepted = String::new();
125
126 while let Some((_, ch)) = &mut iter.peek() {
127 let owned: char = *ch;
128
129 if owned == '\\' {
130 iter.next();
131 match iter.next() {
132 Some((_, escaped)) if escaped == terminator => accepted.push(escaped),
133 Some((_, escaped)) if escapable.contains(&escaped) => {
134 accepted.push('\\');
135 accepted.push(escaped);
136 }
137
138 Some((_, 'n')) => accepted.push('\n'),
139 Some((_, 't')) => accepted.push('\t'),
140 Some((_, 'r')) => accepted.push('\r'),
141 Some((_, '\\')) => accepted.push('\\'),
142 Some((_, escaped)) => return Err(format!("cannot escape {}", escaped)),
143 None => return Err(format!("found EOF when searching for {}", &terminator)),
144 }
145 } else if owned != terminator {
146 accepted.push(owned);
147 iter.next();
148 } else {
149 break;
150 }
151 }
152
153 Ok(accepted)
154}
155
156#[inline]
158pub fn get_number(vec: &str) -> i64 {
159 let mut buffer = 0;
160 for ch in vec.chars() {
161 let digit = ch.to_string().parse::<i64>().unwrap();
162
163 buffer = buffer * 10 + digit;
164 }
165
166 buffer
167}