1pub mod error;
2pub mod grammar;
3pub mod common;
4
5use error::{ParseError, ParseResult, ParseErrorKind};
6use std::fmt::Display;
7
8pub trait IntoParser<'a, R> {
10 fn into_parser(self) -> Parser<'a, R>;
11}
12
13impl<'a, R, P: Parse<'a, R> + 'a> IntoParser<'a, R> for P {
14 fn into_parser(self) -> Parser<'a, R> {
15 Parser { parser: Box::new(self) }
16 }
17}
18
19pub trait Parse<'a, R> {
23 fn parse(&self, span: Span<'a>) -> ParseResult<'a, R>;
24
25 fn map<F, M>(self, map_fn: F) -> Parser<'a, M>
27 where
28 F: Fn(R) -> M + 'a,
29 Self: Sized + 'a,
30 {
31 (move |span| {
32 self.parse(span).map(|(span, res)| (span, map_fn(res)))
33 }).into_parser()
34 }
35
36 fn skip<P, R2>(self, other_parser: P) -> Parser<'a, R>
38 where
39 P: Parse<'a, R2> + 'a,
40 Self: Sized + 'a,
41 {
42 (move |span| {
43 let (span, result) = self.parse(span)?;
44 let (span, _) = other_parser.parse(span)?;
45 Ok((span, result))
46 }).into_parser()
47 }
48
49 fn map_error<F>(self, map_fn: F) -> Parser<'a, R>
51 where
52 F: Fn(ParseError) -> ParseError + 'a,
53 Self: Sized + 'a,
54 {
55 (move |span| {
56 #[allow(clippy::redundant_closure)] self.parse(span).map_err(|err| map_fn(err))
58 }).into_parser()
59 }
60
61 fn only_if<F>(self, pred: F) -> Parser<'a, R>
63 where
64 F: Fn(&R) -> bool + 'a,
65 Self: Sized + 'a,
66 {
67 (move |old_span| {
68 let (span, parsed) = self.parse(old_span)?;
69 if pred(&parsed) {
70 Ok((span, parsed))
71 } else {
72 Err(ParseError::new(old_span, ParseErrorKind::ConditionFailed))
73 }
74 }).into_parser()
75 }
76
77 fn or_value(self, val: R) -> Parser<'a, R>
79 where
80 Self: Sized + 'a,
81 R: Clone + 'a,
82 {
83 (move |span| {
84 Ok(self.parse(span).unwrap_or((span, val.clone())))
85 }).into_parser()
86 }
87
88 fn or_else_value<F>(self, compute: F) -> Parser<'a, R>
90 where
91 Self: Sized + 'a,
92 F: Fn() -> R + 'a,
93 {
94 (move |span| {
95 Ok(self.parse(span).unwrap_or_else(|_| (span, compute())))
96 }).into_parser()
97 }
98
99 fn or<P: Parse<'a, R> + 'a>(self, other_parser: P) -> Parser<'a, R>
104 where
105 Self: Sized + 'a,
106 {
107 (move |span| {
108 match self.parse(span) {
109 ok @ Ok(_) => ok,
110 Err(error) => match other_parser.parse(span) {
111 ok @ Ok(_) => ok,
112 Err(second_error) => Err(ParseError::new(span, ParseErrorKind::Neither(vec![error, second_error])))
113 }
114 }
115 }).into_parser()
116 }
117
118 fn and<R2, P: Parse<'a, R2> + 'a>(self, other_parser: P) -> Parser<'a, (R, R2)>
123 where
124 Self: Sized + 'a,
125 {
126 (move |span| {
127 let (span, res0) = self.parse(span)?;
128 let (span, res1) = other_parser.parse(span)?;
129 Ok((span, (res0, res1)))
130 }).into_parser()
131 }
132
133 fn n_or_more(self, n: usize) -> Parser<'a, Vec<R>>
138 where
139 Self: Sized + 'a,
140 {
141 (move |mut span| {
142 let initial_span = span;
143 let mut results = Vec::with_capacity(n);
144 while let Ok((new_span, res)) = self.parse(span) {
145 results.push(res);
146 span = new_span;
147 }
148
149 if results.len() < n {
150 Err(ParseError::new(initial_span, ParseErrorKind::Starving { found: results.len(), required: n }))
151 } else {
152 Ok((span, results))
153 }
154 }).into_parser()
155 }
156}
157
158impl<'a, R, F> Parse<'a, R> for F
159where
160 F: Fn(Span<'a>) -> ParseResult<'a, R>,
161{
162 fn parse(&self, span: Span<'a>) -> ParseResult<'a, R> {
163 self(span)
164 }
165}
166
167impl<'a, R> Parse<'a, R> for Parser<'a, R> {
168 fn parse(&self, span: Span<'a>) -> ParseResult<'a, R> {
169 self.parser.parse(span)
170 }
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub struct Span<'a> {
198 src_idx: usize,
199 src: &'a str,
200 pub left: &'a str,
201}
202
203impl<'a> Span<'a> {
204 pub fn new(left: &'a str) -> Span<'a> {
205 Span { left, src: left, src_idx: 0 }
206 }
207
208 pub fn incremented(&self, n: usize) -> Span<'a> {
209 Span {
210 left: &self.left[n..],
211 src: self.src,
212 src_idx: self.src_idx + n,
213 }
214 }
215
216 pub fn until(&self, n: usize) -> Span<'a> {
217 Span { left: &self.left[..n], src: self.src, src_idx: self.src_idx }
218 }
219
220 pub fn until_span(&self, other: Span<'a>) -> Span<'a> {
221 Span { src_idx: self.src_idx, src: self.src, left: &self.src[self.src_idx..other.src_idx] }
222 }
223
224 pub fn empty() -> Span<'a> {
225 Span { left: "", src: "", src_idx: 0 }
226 }
227
228 pub fn frozen(&self) -> FrozenSpan {
229 let src = String::from(self.src);
230 let left = String::from(self.left);
231 FrozenSpan { src_idx: self.src_idx, src, left }
232 }
233}
234
235impl<'a> Default for Span<'a> {
236 fn default() -> Self {
237 Self::empty()
238 }
239}
240
241impl<'a> Display for Span<'a> {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 write!(f, "{}", self.left)
244 }
245}
246
247#[derive(Debug, Clone, PartialEq, Eq)]
250pub struct FrozenSpan {
251 src: String,
252 left: String,
253 src_idx: usize,
254}
255
256pub struct Parser<'a, R> {
258 parser: Box<dyn Parse<'a, R> + 'a>,
259}
260
261impl<'a, R> Parser<'a, R> {
262 pub fn new(parser: Box<dyn Parse<'a, R>>) -> Self {
263 Parser { parser }
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use std::fmt::Debug;
270 use crate::common::*;
271 use super::*;
272
273 fn assert_parses<'a, R: Debug + PartialEq, P: Parse<'a, R>>(parser: P, test: &'static str, expected: R) {
274 let parse_result = parser.parse(Span::new(test));
275 assert!(parse_result.is_ok(), "Failed to parse valid string.");
276 let success_result = parse_result.unwrap();
277 assert!(success_result.0.left == "", "Didn't parse the whole string.");
278 assert!(success_result.1 == expected, "Parsed the string but the result is wrong.");
279 }
280
281 fn assert_not_parses<'a, P: Parse<'a, R>, R>(parser: P, test: &'static str) {
282 assert!(parser.parse(Span::new(test)).is_err(), "Parses invalid string.")
283 }
284
285 #[test]
286 fn it_parses_numbers() {
287 assert_parses(uint(), "200", 200);
288 assert_not_parses(uint(), "not a number");
289 assert_parses(int(), "-5", -5);
290 assert_parses(int(), "5", 5);
291 assert_parses(int(), "+5", 5);
292 assert_not_parses(int(), "not a number");
293 assert_not_parses(int(), "+not a number");
294 assert_not_parses(int(), "-not a number");
295 }
296
297 #[test]
298 fn it_parses_literals() {
299 assert_parses(literal("hey"), "hey", "hey");
300 assert_not_parses(literal("hey"), "not hey");
301 }
302}