kodept-parse 0.3.0

Simple compiler with dependent types support in mind
Documentation
use crate::common::ErrorAdapter;
use crate::error::{ErrorLocation, Original, ParseError, ParseErrors};
use crate::lexer::Token;
use crate::nom::TokenVerificationError;
use crate::token_stream::TokenStream;
use derive_more::Constructor;
use itertools::Itertools;
use kodept_core::code_point::CodePoint;
use nom_supreme::error::{BaseErrorKind, ErrorTree, Expectation};
use std::borrow::Cow;
use std::collections::VecDeque;

trait ExpectedError {
    fn expected(&self) -> Cow<'static, str>;
}

#[derive(Debug, Constructor)]
struct BaseError<'s, O, E> {
    location: O,
    kind: BaseErrorKind<&'s str, E>,
}

impl<'s, O, E> BaseError<'s, O, E>
where
    E: ExpectedError,
{
    pub fn into_expected(self) -> Cow<'static, str> {
        match self.kind {
            BaseErrorKind::Expected(Expectation::Something) => Cow::Borrowed("something"),
            BaseErrorKind::Expected(expectation) => Cow::Owned(expectation.to_string()),
            BaseErrorKind::Kind(kind) => Cow::Owned(kind.description().to_string()),
            BaseErrorKind::External(ext) => ext.expected(),
        }
    }
}

impl ExpectedError for TokenVerificationError {
    fn expected(&self) -> Cow<'static, str> {
        Cow::Borrowed(self.expected)
    }
}

impl<T: ?Sized + ToString> ExpectedError for Box<T> {
    fn expected(&self) -> Cow<'static, str> {
        Cow::Owned(self.to_string())
    }
}

impl<A> ErrorAdapter<A, &str> for ErrorTree<&str>
where
    for<'a> &'a str: Original<A>,
    for<'a> A: From<&'a str>,
{
    fn adapt(self, _: &str, position: usize) -> ParseErrors<A> {
        let mut current_errors = VecDeque::from([self]);
        let mut base_errors = vec![];

        loop {
            match current_errors.pop_front() {
                None => break,
                Some(ErrorTree::Base { location, kind }) => {
                    base_errors.push(BaseError::new(location, kind))
                }
                Some(ErrorTree::Stack { base, .. }) => current_errors.push_back(*base),
                Some(ErrorTree::Alt(es)) => current_errors.extend(es),
            }
        }

        let parse_errors = base_errors
            .into_iter()
            .chunk_by(|it| it.location)
            .into_iter()
            .map(|(key, group)| {
                let actual = A::from(&key[0..=1]);
                let expected = group.map(|it| it.into_expected()).collect();
                let location = ErrorLocation::new(position, CodePoint::single_point(position as u32));

                ParseError::new(expected, actual, location)
            })
            .collect();
        ParseErrors::new(parse_errors)
    }
}

impl<'t> ErrorAdapter<Token<'t>, TokenStream<'t>> for super::parser::ParseError<'t> {
    fn adapt(self, _: TokenStream<'t>, position: usize) -> ParseErrors<Token<'t>> {
        let mut current_errors = VecDeque::from([self]);
        let mut base_errors = vec![];

        loop {
            match current_errors.pop_front() {
                None => break,
                Some(super::parser::ParseError::Base { location, kind }) => {
                    base_errors.push(BaseError::new(location, kind))
                }
                Some(super::parser::ParseError::Stack { base, .. }) => {
                    current_errors.push_back(*base)
                }
                Some(super::parser::ParseError::Alt(es)) => current_errors.extend(es),
            }
        }

        let parse_errors = base_errors
            .into_iter()
            .chunk_by(|it| it.location)
            .into_iter()
            .map(|(key, group)| {
                let actual = key.slice[0].token;
                let expected = group.map(|it| it.into_expected()).collect();
                let location = ErrorLocation::new(position, CodePoint::single_point(position as u32));

                ParseError::new(expected, actual, location)
            })
            .collect();
        ParseErrors::new(parse_errors)
    }
}