use std::marker::PhantomData;
use crate::BoxDynLexerParseFn;
use crate::{CharStream, Lexer, LexerError, LexerParseResult};
use crate::{ParserIterator, PosnInCharStream, StreamCharSpan};
#[derive(Debug)]
pub struct LexerOfStr<'a, P, T, E>
where
P: PosnInCharStream,
{
text: &'a str,
end: usize,
_phantom_posn: PhantomData<&'a P>,
_phantom_token: PhantomData<&'a T>,
_phantom_error: PhantomData<&'a E>,
}
impl<'a, P, T, E> Copy for LexerOfStr<'a, P, T, E> where P: PosnInCharStream {}
impl<'a, P, T, E> Clone for LexerOfStr<'a, P, T, E>
where
P: PosnInCharStream,
{
fn clone(&self) -> Self {
*self
}
}
impl<'a, P, T, E> LexerOfStr<'a, P, T, E>
where
P: PosnInCharStream,
{
pub fn new(text: &'a str) -> Self {
let end = text.as_bytes().len();
Self {
text,
end,
_phantom_posn: PhantomData,
_phantom_token: PhantomData,
_phantom_error: PhantomData,
}
}
#[inline(always)]
unsafe fn peek_at_offset(&self, byte_ofs: usize) -> Option<char> {
if byte_ofs >= self.end {
None
} else {
let text = self.text.get_unchecked(byte_ofs..self.end);
text.chars().next()
}
}
#[inline(always)]
fn remaining_text(&self, p: &P) -> &str {
unsafe { self.text.get_unchecked(p.byte_ofs()..self.end) }
}
}
impl<'a, P, T, E> Lexer for LexerOfStr<'a, P, T, E>
where
P: PosnInCharStream,
T: std::fmt::Debug + Clone,
E: LexerError<P>,
{
type Token = T;
type Error = E;
type State = P;
fn parse<'iter>(
&'iter self,
state: Self::State,
parsers: &[BoxDynLexerParseFn<'iter, Self>],
) -> LexerParseResult<Self::State, Self::Token, Self::Error> {
if let Some(ch) = self.peek_at(&state) {
for p in parsers {
let result = p(self, state, ch)?;
if result.is_some() {
return Ok(result);
}
}
return Err(E::failed_to_parse(state, ch));
}
Ok(None)
}
fn iter<'iter>(
&'iter self,
parsers: &'iter [BoxDynLexerParseFn<'iter, Self>],
) -> Box<dyn Iterator<Item = Result<T, E>> + 'iter> {
let state = Default::default();
Box::new(ParserIterator::new(self, state, parsers))
}
}
impl<'a, P, T, E> CharStream<P> for LexerOfStr<'a, P, T, E>
where
P: PosnInCharStream,
{
fn range_as_bytes(&self, ofs: usize, n: usize) -> &[u8] {
assert!(ofs + n <= self.end);
&self.text.as_bytes()[ofs..ofs + n]
}
fn get_text_span(&self, span: &StreamCharSpan<P>) -> &str {
unsafe { self.text.get_unchecked(span.byte_range()) }
}
#[inline(always)]
fn get_text(&self, start: P, end: P) -> &str {
unsafe { self.text.get_unchecked(start.byte_ofs()..end.byte_ofs()) }
}
#[inline(always)]
fn peek_at(&self, state: &P) -> Option<char> {
unsafe { self.peek_at_offset(state.byte_ofs()) }
}
fn matches_bytes(&self, state: &P, s: &[u8]) -> bool {
let n = s.len();
let byte_ofs = state.byte_ofs();
if byte_ofs + n > self.end {
false
} else {
s == self.range_as_bytes(byte_ofs, n)
}
}
#[inline(always)]
fn matches_str(&self, pos: &P, pat: &str) -> bool {
self.remaining_text(pos).starts_with(pat)
}
#[inline(always)]
fn consumed(&self, mut state: P, mut n: usize) -> P {
for ch in self.remaining_text(&state).chars() {
if n == 0 {
break;
}
if ch == '\n' {
state = state.advance_line(1)
} else {
state = state.advance_cols(ch.len_utf8(), 1)
}
n -= 1;
}
state
}
fn do_while<F: Fn(usize, char) -> bool>(
&self,
mut state: P,
ch: char,
f: &F,
) -> (P, Option<(P, usize)>) {
if !f(0, ch) {
return (state, None);
}
let start = state;
let mut n = 1;
let mut ofs = state.byte_ofs() + ch.len_utf8();
while let Some(ch) = unsafe { self.peek_at_offset(ofs) } {
if !f(n, ch) {
break;
}
n += 1;
ofs += ch.len_utf8();
}
state = unsafe { self.consumed_chars(state, ofs - start.byte_ofs(), n) };
(state, Some((start, n)))
}
}