kodept-parse 0.3.0

Simple compiler with dependent types support in mind
Documentation
use std::borrow::Cow;

use derive_more::Constructor;

use kodept_core::code_point::CodePoint;

use crate::lexer::Token;
use crate::token_stream::TokenStream;

#[derive(Debug, Constructor)]
pub struct ErrorLocation {
    pub in_stream: usize,
    pub in_code: CodePoint,
}

#[derive(Debug, Constructor)]
pub struct ParseError<A> {
    pub expected: Vec<Cow<'static, str>>,
    pub actual: A,
    pub location: ErrorLocation,
}

#[derive(Debug, Constructor)]
pub struct ParseErrors<A> {
    errors: Vec<ParseError<A>>,
}

pub trait Original<Actual> {
    fn point_pos(&self, point: impl Into<CodePoint>) -> usize;
    fn actual(&self, point: impl Into<CodePoint>) -> Actual;
}

impl<A> IntoIterator for ParseErrors<A> {
    type Item = ParseError<A>;
    type IntoIter = std::vec::IntoIter<ParseError<A>>;

    fn into_iter(self) -> Self::IntoIter {
        self.errors.into_iter()
    }
}

impl<'t> Original<Token<'t>> for TokenStream<'t> {
    fn point_pos(&self, point: impl Into<CodePoint>) -> usize {
        let stream = *self;
        let point1 = point.into();
        stream
            .slice
            .iter()
            .position(|it| it.span.point == point1)
            .unwrap()
    }

    fn actual(&self, point: impl Into<CodePoint>) -> Token<'t> {
        let pos = self.point_pos(point);
        self.slice[pos].token
    }
}

impl<'a, S: From<&'a str>> Original<S> for &'a str {
    fn point_pos(&self, point: impl Into<CodePoint>) -> usize {
        let point = point.into();
        point.offset as usize
    }

    fn actual(&self, point: impl Into<CodePoint>) -> S {
        let point = point.into();
        S::from(&self[point.as_range()])
    }
}

impl<A> ParseError<A> {
    pub fn map<B>(self, f: impl FnOnce(A) -> B) -> ParseError<B> {
        ParseError {
            expected: self.expected,
            actual: f(self.actual),
            location: self.location,
        }
    }
}

impl<A> ParseErrors<A> {
    pub fn map<B>(self, mut f: impl FnMut(A) -> B) -> ParseErrors<B> {
        ParseErrors::new(self.into_iter().map(move |it| it.map(&mut f)).collect())
    }
}