use crate::{shex_parser_error::ParseError as ShExParseError, IRes, Span};
use colored::*;
use nom::{
branch::alt,
bytes::complete::{is_not, tag, tag_no_case},
character::complete::multispace1,
combinator::value,
multi::many0,
sequence::{delimited, pair},
Err,
};
use std::fmt::Debug;
pub(crate) fn map_error<'a, T: 'a>(
mut parser: impl FnMut(Span<'a>) -> IRes<'a, T> + 'a,
mut error: impl FnMut() -> ShExParseError + 'a,
) -> impl FnMut(Span<'a>) -> IRes<'a, T> + 'a {
move |input| {
parser(input).map_err(|e| match e {
Err::Incomplete(_) => e,
Err::Error(context) => {
let mut err = error().at(input);
err.append(context);
Err::Error(err)
}
Err::Failure(context) => {
let mut err = error().at(input);
err.append(context);
Err::Failure(err)
}
})
}
}
#[inline(always)]
pub(crate) fn traced<'a, T, P>(
fun: &'static str,
mut parser: P,
) -> impl FnMut(Span<'a>) -> IRes<'a, T>
where
T: Debug,
P: FnMut(Span<'a>) -> IRes<'a, T>,
{
move |input| {
tracing::trace!(target: "parser", "{fun}({input:?})");
let result = parser(input);
match &result {
Ok(res) => {
tracing::trace!(target: "parser", "{}", format!("{fun}({input:?}) -> {res:?}").green());
}
Err(e) => {
tracing::trace!(target: "parser", "{}", format!("{fun}({input:?}) -> {e:?}").red());
}
}
result
}
}
fn comment(input: Span) -> IRes<()> {
alt((
value((), pair(tag("#"), is_not("\n\r"))),
value((), tag("#")),
value((), multi_comment),
))(input)
}
fn multi_comment(i: Span) -> IRes<()> {
value((), delimited(tag("/*"), is_not("*/"), tag("*/")))(i)
}
pub(crate) fn tws0(input: Span) -> IRes<()> {
value((), many0(alt((value((), multispace1), comment))))(input)
}
pub(crate) fn token<'a>(token: &'a str) -> impl FnMut(Span<'a>) -> IRes<Span<'a>> {
map_error(tag(token), || {
ShExParseError::ExpectedToken(token.to_string())
})
}
pub(crate) fn token_tws<'a>(token: &'a str) -> impl FnMut(Span<'a>) -> IRes<Span<'a>> {
map_error(delimited(tws0, tag(token), tws0), || {
ShExParseError::ExpectedToken(token.to_string())
})
}
pub(crate) fn tag_no_case_tws<'a>(token: &'a str) -> impl FnMut(Span<'a>) -> IRes<Span<'a>> {
map_error(delimited(tws0, tag_no_case(token), tws0), || {
ShExParseError::ExpectedToken(token.to_string())
})
}