use crate::{
ast::{ErrorToken, Expression},
parser::{
identifier,
utils::{LocatedSpan, ToRange},
IResult,
},
};
use nom::{branch::alt, bytes::complete::take_till1, combinator::map};
use std::ops::Range;
#[derive(Debug, PartialEq)]
pub struct Error(pub Range<usize>, pub String);
pub(crate) fn expect<'a, F, E, T>(
parser: F,
error_msg: E,
) -> impl Fn(LocatedSpan<'a>) -> IResult<Option<T>>
where
F: Fn(LocatedSpan<'a>) -> IResult<T>,
E: ToString,
{
move |input| match parser(input) {
Ok((remaining, out)) => Ok((remaining, Some(out))),
Err(nom::Err::Error(err)) | Err(nom::Err::Failure(err)) => {
let input = err.input;
let err = Error(input.to_range(), error_msg.to_string());
input.extra.report_error(err);
Ok((input, None))
}
Err(err) => Err(err),
}
}
pub(crate) fn error(input: LocatedSpan) -> IResult<Expression> {
alt((
map(identifier, |span: LocatedSpan| {
span.extra.report_error(Error(
span.to_range(),
format!("unexpected `{}`", span.fragment()),
));
Expression::Error(ErrorToken::Identifier(span.to_string()))
}),
map(take_till1(|c| c == ')' || c == ' '), |span: LocatedSpan| {
span.extra.report_error(Error(
span.to_range(),
format!("unexpected `{}`", span.fragment()),
));
Expression::Error(ErrorToken::Unexpected)
}),
))(input)
}