kodept-parse 0.3.0

Simple compiler with dependent types support in mind
Documentation
use crate::common::TokenProducer;
use crate::lexer::{DefaultLexer, Ignore::*, Token::Ignore};
use crate::token_match::TokenMatch;
use crate::token_stream::TokenStream;
use derive_more::Display;
use kodept_core::code_point::CodePoint;
use peg::str::LineCol;
use peg::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult};

#[derive(Display, Copy, Clone, Debug)]
#[display("{line}:{col}")]
pub struct Position {
    line: usize,
    col: u32,
    length: u32,
    offset: u32,
}

impl From<Position> for CodePoint {
    fn from(value: Position) -> Self {
        CodePoint::new(value.length, value.offset)
    }
}

impl From<LineCol> for Position {
    fn from(value: LineCol) -> Self {
        Position {
            line: value.line,
            col: value.column as u32,
            length: 1,
            offset: value.offset as u32,
        }
    }
}

impl<'t> Parse for TokenStream<'t> {
    type PositionRepr = Position;

    #[inline(always)]
    fn start(&self) -> usize {
        self.slice.first().map_or(0, |it| it.span.point.offset) as usize
    }

    #[inline(always)]
    fn is_eof(&self, pos: usize) -> bool {
        pos >= self.len()
    }

    #[inline(always)]
    fn position_repr(&self, pos: usize) -> Self::PositionRepr {
        let (before, point) = match self.slice.split_at(pos) {
            (a, [b, ..]) => (a, b.span.point),
            (a @ [.., last], []) => (a, last.span.point),
            ([], []) => panic!("Cannot slice empty stream"),
        };
        let line = before
            .iter()
            .filter(|it| matches!(it.token, Ignore(Newline)))
            .count()
            + 1;
        let col = before
            .iter()
            .rev()
            .take_while(|it| !matches!(it.token, Ignore(Newline)))
            .map(|it| it.span.point.length)
            .sum::<u32>()
            + 1;

        Position {
            line,
            col,
            length: point.length,
            offset: point.offset,
        }
    }
}

impl<'input> ParseElem<'input> for TokenStream<'input> {
    type Element = TokenMatch<'input>;

    #[inline(always)]
    fn parse_elem(&'input self, pos: usize) -> RuleResult<Self::Element> {
        let slice = &self.slice[pos..];
        match slice.first() {
            None => RuleResult::Failed,
            Some(x) => RuleResult::Matched(pos + 1, *x),
        }
    }
}

impl<'input> ParseLiteral for TokenStream<'input> {
    #[inline(always)]
    fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()> {
        let token_match = DefaultLexer::new()
            .parse_token(literal, 0)
            .expect("Unexpected token received in grammar");
        debug_assert_eq!(token_match.span.point.length, literal.len() as u32);

        match (self.slice.get(pos), token_match.token) {
            (Some(a), b) if a.token == b => RuleResult::Matched(pos + 1, ()),
            _ => RuleResult::Failed,
        }
    }
}

impl<'input> ParseSlice<'input> for TokenStream<'input> {
    type Slice = TokenStream<'input>;

    #[inline(always)]
    fn parse_slice(&'input self, p1: usize, p2: usize) -> Self::Slice {
        TokenStream::new(&self.slice[p1..p2])
    }
}