1use crate::{Parse, Span, Parser};
2use crate::error::{ParseErrorKind, ParseError};
3
4pub fn any_char<'a>() -> impl Parse<'a, char> {
12 move |span: Span<'a>| {
13 let c = span.left
14 .chars()
15 .next()
16 .ok_or_else(|| ParseError::new(span, ParseErrorKind::Starving { found: 0, required: 1 }))?;
17 Ok((span.incremented(1), c))
18 }
19}
20
21pub fn literal<'a>(expected: &'static str) -> impl Parse<'a, &'a str> {
27 move |span: Span<'a>| {
28 if span.left.len() < expected.len() {
29 Err(ParseError::new(span, ParseErrorKind::Starving { found: span.left.len(), required: expected.len() }))
30 } else {
31 let sub = &span.left[..expected.len()];
32 if sub == expected {
33 Ok((span.incremented(expected.len()), sub))
34 } else {
35 Err(ParseError::new(span.until(expected.len()), ParseErrorKind::Unexpected { found: String::from(sub), expected: String::from(expected) }))
36 }
37 }
38 }
39}
40
41pub fn one_of<'a, R: 'a, const N: usize>(parsers: [Parser<'a, R>; N]) -> impl Parse<'a, R> {
47 move |span: Span<'a>| {
48 let mut errors = Vec::with_capacity(N / 2);
49 for parser in parsers.iter() {
50 match parser.parse(span) {
51 ok @ Ok(_) => return ok,
52 Err(error) => errors.push(error),
53 }
54 }
55
56 Err(ParseError::new(span, ParseErrorKind::Neither(errors)))
57 }
58}
59
60pub fn seq<'a, R: 'a, const N: usize>(parsers: [Parser<'a, R>; N]) -> impl Parse<'a, Vec<R>> {
66 move |mut span: Span<'a>| {
67 let mut results = Vec::with_capacity(N);
68 for parser in parsers.iter() {
69 let (new_span, res) = parser.parse(span)?;
70 results.push(res);
71 span = new_span;
72 }
73 Ok((span, results))
74 }
75}
76
77pub fn uint<'a>() -> impl Parse<'a, u32> {
79 any_char().only_if(|c| c.is_digit(10)).n_or_more(1).map(|digits| {
80 let digits_as_string: String = digits.into_iter().collect();
81 digits_as_string.parse().unwrap()
82 })
83}
84
85pub fn int<'a>() -> impl Parse<'a, i32> {
87 let sign = literal("+").or(literal("-")).or_value("+");
88 sign.and(uint()).map(|(sign, uint)| {
89 match sign {
90 "+" => uint as i32,
91 "-" => -(uint as i32),
92 _ => unreachable!(),
93 }
94 })
95}