use core::fmt::{self, Display, Formatter};
use nom::{
error::{Error, ErrorKind, ParseError},
Err as NomErr, InputLength, Offset, Parser,
};
use nom::error::VerboseError;
use crate::parser_ext::ParserExt;
pub trait RecreateContext<I>: Sized {
fn recreate_context(original_input: I, tail: I) -> Self;
}
impl<I> RecreateContext<I> for I {
fn recreate_context(_original_input: I, tail: I) -> Self {
tail
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ByteOffset(pub usize);
impl<I: Offset> RecreateContext<I> for ByteOffset {
fn recreate_context(original_input: I, tail: I) -> Self {
ByteOffset(original_input.offset(&tail))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Location {
pub line: usize,
pub column: usize,
}
impl Location {
pub fn locate_tail<'a>(original_input: &'a str, tail: &'a str) -> Self {
let offset = original_input.offset(tail);
let input_bytes = original_input.as_bytes();
let prefix = &input_bytes[..offset];
let line_number = memchr::memchr_iter(b'\n', prefix).count() + 1;
let last_line_start = memchr::memrchr(b'\n', prefix).map(|i| i + 1).unwrap_or(0);
let last_line = &prefix[last_line_start..];
let column_number = last_line.len() + 1;
Location {
line: line_number,
column: column_number,
}
}
}
impl Display for Location {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "line {}, column {}", self.line, self.column)
} else {
write!(f, "{}:{}", self.line, self.column)
}
}
}
impl RecreateContext<&str> for Location {
fn recreate_context(original_input: &str, tail: &str) -> Self {
Location::locate_tail(original_input, tail)
}
}
pub trait ExtractContext<I, T> {
fn extract_context(self, original_input: I) -> T;
}
impl<I, T> ExtractContext<I, ()> for T {
fn extract_context(self, _original_input: I) {}
}
impl<I, T> ExtractContext<I, (T, ErrorKind)> for (I, ErrorKind)
where
T: RecreateContext<I>,
{
fn extract_context(self, original_input: I) -> (T, ErrorKind) {
let (tail, kind) = self;
(T::recreate_context(original_input, tail), kind)
}
}
impl<I, T> ExtractContext<I, Error<T>> for Error<I>
where
T: RecreateContext<I>,
{
fn extract_context(self, original_input: I) -> Error<T> {
Error::new(T::recreate_context(original_input, self.input), self.code)
}
}
impl<I, T> ExtractContext<I, VerboseError<T>> for VerboseError<I>
where
T: RecreateContext<I>,
I: Clone,
{
fn extract_context(self, original_input: I) -> VerboseError<T> {
VerboseError {
errors: self
.errors
.into_iter()
.map(|(input, kind)| (T::recreate_context(original_input.clone(), input), kind))
.collect(),
}
}
}
impl<T, E1, E2, I> ExtractContext<I, Result<T, E2>> for Result<T, E1>
where
E1: ExtractContext<I, E2>,
{
fn extract_context(self, original_input: I) -> Result<T, E2> {
self.map_err(move |err| err.extract_context(original_input))
}
}
pub fn final_parser<I, O, E, E2>(parser: impl Parser<I, O, E>) -> impl FnMut(I) -> Result<O, E2>
where
E: ParseError<I> + ExtractContext<I, E2>,
I: InputLength + Clone,
{
let mut parser = parser.complete().all_consuming();
move |input| match parser.parse(input.clone()) {
Ok((_, parsed)) => Ok(parsed),
Err(NomErr::Error(err)) | Err(NomErr::Failure(err)) => Err(err.extract_context(input)),
Err(NomErr::Incomplete(..)) => {
unreachable!("Complete combinator should make this impossible")
}
}
}