#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use core::fmt::Debug;
use notification::{Notification, NotificationAcceptor, NotificationList};
use token::Token;
#[cfg(feature = "common")]
pub mod common;
pub mod notification;
mod scanner;
pub mod span;
pub mod token;
pub use scanner::SourceCodeScanner;
#[derive(Debug)]
pub struct LexerResult<TokenData, N = ()> {
notifications: NotificationList<N>,
tokens: Vec<Token<TokenData>>,
}
impl<T, N> NotificationAcceptor<N> for LexerResult<T, N> {
#[inline]
fn report(&mut self, notification: Notification<N>) {
self.notifications.push(notification);
}
}
impl<T, N> Default for LexerResult<T, N> {
fn default() -> Self {
Self {
notifications: NotificationList::new(),
tokens: vec![],
}
}
}
impl<T, N> LexerResult<T, N> {
#[must_use]
pub const fn new() -> Self {
Self {
notifications: NotificationList::new(),
tokens: vec![],
}
}
#[inline]
pub fn push_token(&mut self, token: Token<T>) {
self.tokens.push(token);
}
#[inline]
#[must_use]
pub fn finalize(self) -> FinalizedLexerResult<T, N> {
FinalizedLexerResult {
notifications: self.notifications,
tokens: self.tokens,
}
}
}
#[derive(Debug)]
pub struct FinalizedLexerResult<TokenData, N = ()> {
notifications: NotificationList<N>,
tokens: Vec<Token<TokenData>>,
}
impl<T, N> FinalizedLexerResult<T, N> {
#[inline]
#[must_use]
pub const fn notifications(&self) -> &NotificationList<N> {
&self.notifications
}
#[inline]
#[must_use]
pub fn tokens(&self) -> Option<&Vec<Token<T>>> {
self.notifications.is_valid().then_some(&self.tokens)
}
#[inline]
#[must_use]
pub fn into_pair(self) -> (NotificationList<N>, Option<Vec<Token<T>>>) {
let valid = self.notifications.is_valid();
(self.notifications, valid.then_some(self.tokens))
}
}
#[cfg(test)]
mod tests {
use crate::{span::Span, token::Token, LexerResult, SourceCodeScanner};
pub fn common() -> SourceCodeScanner<'static> {
SourceCodeScanner::new("Testing.")
}
#[test]
fn next() {
let code = common();
assert_eq!(code.next(), Some('T'));
assert_eq!(code.next(), Some('e'));
assert_eq!(code.next(), Some('s'));
assert_eq!(code.next(), Some('t'));
assert_eq!(code.next(), Some('i'));
assert_eq!(code.next(), Some('n'));
assert_eq!(code.next(), Some('g'));
assert_eq!(code.next(), Some('.'));
assert_eq!(code.next(), None);
}
#[test]
fn next_span() {
let code = common();
unsafe {
assert_eq!(code.next_span(), Some(Span::new(0, 1).wrap('T')));
assert_eq!(code.next_span(), Some(Span::new(1, 1).wrap('e')));
assert_eq!(code.next_span(), Some(Span::new(2, 1).wrap('s')));
assert_eq!(code.next_span(), Some(Span::new(3, 1).wrap('t')));
assert_eq!(code.next_span(), Some(Span::new(4, 1).wrap('i')));
assert_eq!(code.next_span(), Some(Span::new(5, 1).wrap('n')));
assert_eq!(code.next_span(), Some(Span::new(6, 1).wrap('g')));
assert_eq!(code.next_span(), Some(Span::new(7, 1).wrap('.')));
assert_eq!(code.next_span(), None);
}
}
#[test]
fn peek() {
let code = common();
assert_eq!(code.peek(), Some('T'));
assert_eq!(code.next(), Some('T'));
assert_eq!(code.next(), Some('e'));
assert_eq!(code.next(), Some('s'));
assert_eq!(code.next(), Some('t'));
assert_eq!(code.peek(), Some('i'));
assert_eq!(code.next(), Some('i'));
assert_eq!(code.next(), Some('n'));
assert_eq!(code.next(), Some('g'));
assert_eq!(code.peek(), Some('.'));
assert_eq!(code.next(), Some('.'));
assert_eq!(code.peek(), None);
assert_eq!(code.next(), None);
assert_eq!(code.peek(), None);
}
#[test]
fn has_next() {
let code = common();
assert_eq!(code.next(), Some('T'));
assert_eq!(code.next(), Some('e'));
assert!(code.has_next());
assert_eq!(code.next(), Some('s'));
assert_eq!(code.next(), Some('t'));
assert!(code.has_next());
assert_eq!(code.next(), Some('i'));
assert_eq!(code.next(), Some('n'));
assert_eq!(code.next(), Some('g'));
assert!(code.has_next());
assert_eq!(code.next(), Some('.'));
assert!(!code.has_next());
assert_eq!(code.next(), None);
assert!(!code.has_next());
}
#[test]
fn skip() {
let code = common();
assert_eq!(code.next(), Some('T'));
assert_eq!(code.next(), Some('e'));
code.skip();
assert_eq!(code.next(), Some('t'));
assert_eq!(code.next(), Some('i'));
code.skip();
assert_eq!(code.next(), Some('g'));
code.skip();
assert_eq!(code.next(), None);
}
#[test]
fn peek_is() {
let code = common();
assert_eq!(code.next(), Some('T'));
assert_eq!(code.next(), Some('e'));
assert!(code.peek_is('s'));
assert_eq!(code.next(), Some('s'));
assert_eq!(code.next(), Some('t'));
assert_eq!(code.next(), Some('i'));
assert!(code.peek_is('n'));
assert_eq!(code.next(), Some('n'));
assert!(code.peek_is_not('P'));
assert_eq!(code.next(), Some('g'));
assert!(code.peek_is('.'));
assert_eq!(code.next(), Some('.'));
assert!(code.peek_is_not('P'));
assert_eq!(code.next(), None);
assert!(code.peek_is_not('P'));
}
#[test]
fn peek_is_map() {
let code = common();
assert!(code.peek_is_map(|x| x.is_uppercase()));
assert_eq!(code.next(), Some('T'));
assert_eq!(code.next(), Some('e'));
assert!(!code.peek_is_map(|x| x.is_uppercase()));
assert_eq!(code.next(), Some('s'));
assert_eq!(code.next(), Some('t'));
assert_eq!(code.next(), Some('i'));
assert!(code.peek_is_map(|x| x.is_lowercase()));
assert_eq!(code.next(), Some('n'));
assert_eq!(code.next(), Some('g'));
assert!(!code.peek_is_map(|x| x.is_lowercase()));
assert_eq!(code.next(), Some('.'));
assert!(!code.peek_is_map(|_| true));
assert_eq!(code.next(), None);
assert!(!code.peek_is_map(|_| true));
}
#[test]
fn span() {
let code = common();
unsafe {
assert_eq!(code.next(), Some('T'));
assert_eq!(code.next(), Some('e'));
assert_eq!(code.span(), Span::new_single(2));
assert_eq!(code.next(), Some('s'));
assert_eq!(code.next(), Some('t'));
assert_eq!(code.next(), Some('i'));
assert_eq!(code.span(), Span::new_single(5));
assert_eq!(code.next(), Some('n'));
assert_eq!(code.next(), Some('g'));
assert_eq!(code.span(), Span::new_single(7));
assert_eq!(code.span(), Span::new_single(7));
assert_eq!(code.next(), Some('.'));
assert_eq!(code.span(), Span::new_empty(8));
assert_eq!(code.next(), None);
assert_eq!(code.span(), Span::new_empty(8));
}
}
#[test]
fn meta() {
let mut result = LexerResult::<_, ()>::new();
unsafe {
let bloo = Token::new("bloo", Span::new(0, 4));
let ploo = Token::new("ploo", Span::new(4, 4));
result.push_token(bloo.clone());
result.push_token(ploo.clone());
let result = result.finalize();
assert_eq!(result.notifications.into_sorted_vec(), vec![]);
assert_eq!(result.tokens, vec![bloo, ploo]);
}
}
}