#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
pub mod prelude {
pub use crate::{error::Error as LexErr, utils::*, *};
}
pub mod error;
pub mod utils;
pub use char_lex_macro::token;
pub use traits::{TokenMatch, TokenTrait, TokenWrapper};
mod traits;
use error::Error;
use std::marker::PhantomData;
use utils::Context;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Lexer<'l, T, W>
where
T: TokenTrait,
W: TokenWrapper<T>,
{
cursor: usize,
content: &'l str,
pos: (usize, usize),
error: Option<Error>,
pd: PhantomData<(T, W)>,
}
impl<'l, T, W> Lexer<'l, T, W>
where
T: TokenTrait,
W: TokenWrapper<T>,
{
pub fn new(content: &'l str) -> Self {
Self {
content,
cursor: 0,
pos: (1, 0),
error: None,
pd: PhantomData,
}
}
pub fn next_ignored<M>(&mut self, m: M) -> Option<W>
where
M: TokenMatch<T>,
{
loop {
let (t, c) = self.next_token()?;
if !m.matches_token(&t) {
break Some(<W as TokenWrapper<T>>::wrap(t, Context::new(c, self.pos)));
}
}
}
pub fn get_error(&self) -> Option<&Error> {
self.error.as_ref()
}
pub fn get_cursor(&self) -> usize {
self.cursor
}
pub fn set_cursor(&mut self, cursor: usize) {
self.cursor = cursor
}
fn next_token(&mut self) -> Option<(T, char)> {
if let None = self.error {
self.cursor += 1;
if let Some(c) = next_char(self.content, self.cursor) {
self.pos.1 += 1;
if c == '\n' {
self.pos.0 += 1;
self.pos.1 = 0;
}
if let Some(t) = <T as TokenTrait>::match_char(c) {
Some((t, c))
} else {
self.error = Some(Error::Unexpected(Context::new(c, self.pos)));
None
}
} else {
self.error = Some(Error::EndOfFile);
None
}
} else {
None
}
}
}
impl<'l, T, W> Iterator for Lexer<'l, T, W>
where
T: TokenTrait,
W: TokenWrapper<T>,
{
type Item = W;
fn next(&mut self) -> Option<Self::Item> {
let (t, c) = self.next_token()?;
Some(<W as TokenWrapper<T>>::wrap(t, Context::new(c, self.pos)))
}
}
fn next_char<'l>(content: &'l str, cursor: usize) -> Option<char> {
if cursor <= content.len() {
let (c, _) = content.split_at(cursor);
Some(c.chars().last().unwrap())
} else {
None
}
}