1use error::Error;
4mod types;
5
6pub mod error;
7
8pub struct Parser<'input> {
10 input: &'input str,
11 cursor: usize,
12}
13
14impl<'input> Parser<'input> {
15 pub fn new(input: &'input str) -> Self {
17 Self { input, cursor: 0 }
18 }
19
20 pub fn cursor(&self) -> usize {
22 self.cursor
23 }
24
25 pub fn read(&mut self) -> Result<char, Error<'input>> {
31 let current = self.current()?;
32 self.advance();
33 Ok(current)
34 }
35
36 pub fn advance(&mut self) {
38 self.cursor += 1;
39 }
40
41 pub fn rewind(&mut self, n: usize) {
43 self.cursor -= n;
44 }
45
46 pub fn done(&mut self) {
48 self.cursor = self.input.len();
49 }
50
51 pub fn try_parse<T, E, F: FnOnce(&mut Self) -> Result<T, E>>(&mut self, f: F) -> Result<T, E> {
57 let cursor = self.cursor;
58 let result = f(self);
59 if result.is_err() {
60 self.cursor = cursor;
61 }
62 result
63 }
64
65 pub fn slice(&self) -> &'input str {
67 &self.input[self.cursor..]
68 }
69
70 pub fn take_slice(&mut self) -> &'input str {
72 let slice = &self.input[self.cursor..];
73 self.done();
74 slice
75 }
76
77 pub fn slice_from(&self, start: usize) -> &'input str {
79 let end = self.cursor.min(self.input.len());
80 &self.input[start..end]
81 }
82
83 pub fn len(&self) -> usize {
85 self.input.len() - self.cursor
86 }
87
88 pub fn is_empty(&self) -> bool {
90 self.len() == 0
91 }
92
93 pub fn current(&self) -> Result<char, Error<'input>> {
99 self.slice().chars().next().ok_or(Error::EndOfInput)
100 }
101
102 pub fn take_matches<F: FnMut(char) -> bool>(&mut self, f: F) -> &'input str {
106 let cursor = self.cursor();
107 self.skip_matches(f);
108 let result = self.slice_from(cursor);
109 result
110 }
111
112 pub fn skip_matches<F: FnMut(char) -> bool>(&mut self, pat: F) {
114 self.skip_internal(self.slice().trim_start_matches(pat).len());
115 }
116
117 pub fn skip_char(&mut self, char: char) {
119 self.skip_internal(self.slice().trim_matches(char).len());
120 }
121
122 pub fn skip_whitespace(&mut self) {
124 self.skip_matches(char::is_whitespace);
125 }
126
127 fn skip_internal(&mut self, trim: usize) {
128 let offset = self.len() - trim;
129 self.cursor += offset;
130 }
131
132 pub fn expect_done(&self) -> Result<(), Error<'input>> {
138 if self.cursor < self.input.len() {
139 Err(Error::ExpectedDone)
140 } else {
141 Ok(())
142 }
143 }
144
145 pub fn expect_char(&mut self, expected: char) -> Result<(), Error<'input>> {
151 let received = self.read()?;
152 if received == expected {
153 Ok(())
154 } else {
155 Err(Error::ExpectedChar { expected, received })
156 }
157 }
158
159 pub fn expect_matches<F: Fn(char) -> Result<bool, &'static str>>(
167 &mut self,
168 expected: &'static str,
169 f: F,
170 ) -> Result<&'input str, Error<'input>> {
171 let cursor = self.cursor;
172 let mut result = Ok(());
173 self.skip_matches(|char| match f(char) {
174 Ok(bool) => bool,
175 Err(expected) => {
176 result = Err(expected);
177 false
178 }
179 });
180 match result {
181 Ok(()) => match self.slice_from(cursor) {
182 "" => Err(Error::ExpectedMatch {
183 expected,
184 received: "nothing",
185 }),
186 result => Ok(result),
187 },
188 Err(expected) => Err(Error::ExpectedMatch {
189 expected,
190 received: self.slice_from(cursor),
191 }),
192 }
193 }
194
195 pub fn expect_whitespace(&mut self) -> Result<(), Error<'input>> {
201 self.expect_matches("a whitespace character", |char| Ok(char.is_whitespace()))?;
202 Ok(())
203 }
204
205 pub fn expect_str(&mut self, expected: &'static str) -> Result<(), Error<'input>> {
211 let cursor = self.cursor;
212 self.cursor += expected.len();
213 let received = self.slice_from(cursor);
214 if received == expected {
215 Ok(())
216 } else {
217 Err(Error::ExpectedString { expected, received })
218 }
219 }
220
221 pub fn expect_ident(&mut self) -> Result<&'input str, Error<'input>> {
227 let cursor = self.cursor;
228 let name_start_char = self.read()?;
229 if !is_name_start_char(name_start_char) {
230 return Err(Error::ExpectedIdent {
231 expected: "valid ident starting character",
232 received: self.slice_from(cursor),
233 });
234 }
235 self.skip_matches(is_name_char);
236 Ok(self.slice_from(cursor))
237 }
238
239 pub fn expect_ident_matching(&mut self, expected: &'static str) -> Result<(), Error<'input>> {
245 let received = self.expect_ident()?;
246 if received == expected {
247 Ok(())
248 } else {
249 Err(Error::ExpectedIdent { expected, received })
250 }
251 }
252}
253fn is_name_start_char(char: char) -> bool {
254 char.is_ascii_alphabetic()
255 || matches!(char, ':' | '_' | '\u{C0}'..'\u{D6}' | '\u{D8}'..='\u{F6}' | '\u{F8}'..='\u{2FF}' | '\u{370}'..='\u{37D}' | '\u{37F}'..='\u{1FFF}' | '\u{200C}'..='\u{200D}' | '\u{2070}'..='\u{218F}' | '\u{2C00}'..='\u{2FEF}' | '\u{3001}'..='\u{D7FF}' | '\u{F900}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' | '\u{10000}'..='\u{EFFFF}')
256}
257fn is_name_char(char: char) -> bool {
258 is_name_start_char(char)
259 || char.is_ascii_digit()
260 || matches!(char, '-' | '.' | '\u{B7}' | '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}')
261}
262
263pub trait Parse<'input>: Sized {
265 fn parse(input: &mut Parser<'input>) -> Result<Self, Error<'input>>;
270
271 fn parse_string(input: &'input str) -> Result<Self, Error<'input>> {
276 let parser = &mut Parser::new(input);
277 parser.skip_whitespace();
278 let result = Self::parse(parser)?;
279 parser.skip_whitespace();
280 parser.expect_done()?;
281 Ok(result)
282 }
283}