use crate::{Parse, Span, Parser};
use crate::error::{ParseErrorKind, ParseError};
pub fn any_char<'a>() -> impl Parse<'a, char> {
move |span: Span<'a>| {
let c = span.left
.chars()
.next()
.ok_or_else(|| ParseError::new(span, ParseErrorKind::Starving { found: 0, required: 1 }))?;
Ok((span.incremented(1), c))
}
}
pub fn literal<'a>(expected: &'static str) -> impl Parse<'a, &'a str> {
move |span: Span<'a>| {
if span.left.len() < expected.len() {
Err(ParseError::new(span, ParseErrorKind::Starving { found: span.left.len(), required: expected.len() }))
} else {
let sub = &span.left[..expected.len()];
if sub == expected {
Ok((span.incremented(expected.len()), sub))
} else {
Err(ParseError::new(span.until(expected.len()), ParseErrorKind::Unexpected { found: String::from(sub), expected: String::from(expected) }))
}
}
}
}
pub fn one_of<'a, R: 'a, const N: usize>(parsers: [Parser<'a, R>; N]) -> impl Parse<'a, R> {
move |span: Span<'a>| {
let mut errors = Vec::with_capacity(N / 2);
for parser in parsers.iter() {
match parser.parse(span) {
ok @ Ok(_) => return ok,
Err(error) => errors.push(error),
}
}
Err(ParseError::new(span, ParseErrorKind::Neither(errors)))
}
}
pub fn seq<'a, R: 'a, const N: usize>(parsers: [Parser<'a, R>; N]) -> impl Parse<'a, Vec<R>> {
move |mut span: Span<'a>| {
let mut results = Vec::with_capacity(N);
for parser in parsers.iter() {
let (new_span, res) = parser.parse(span)?;
results.push(res);
span = new_span;
}
Ok((span, results))
}
}
pub fn uint<'a>() -> impl Parse<'a, u32> {
any_char().only_if(|c| c.is_digit(10)).n_or_more(1).map(|digits| {
let digits_as_string: String = digits.into_iter().collect();
digits_as_string.parse().unwrap()
})
}
pub fn int<'a>() -> impl Parse<'a, i32> {
let sign = literal("+").or(literal("-")).or_value("+");
sign.and(uint()).map(|(sign, uint)| {
match sign {
"+" => uint as i32,
"-" => -(uint as i32),
_ => unreachable!(),
}
})
}