Add token reader and access to last token in checker function
Signed-off-by: trivernis <trivernis@protonmail.com>master
parent
652045becb
commit
8cb21fcaca
@ -1,3 +1,4 @@
|
||||
mod test_input;
|
||||
mod test_lexer;
|
||||
mod test_token;
|
||||
mod test_token_reader;
|
||||
|
@ -0,0 +1,57 @@
|
||||
use crate::token::{EOFToken, Token};
|
||||
use crate::token_reader::TokenReader;
|
||||
|
||||
struct AToken;
|
||||
struct BToken;
|
||||
struct CToken;
|
||||
|
||||
fn get_reader() -> TokenReader {
|
||||
let tokens = vec![
|
||||
Token::new(AToken),
|
||||
Token::new(BToken),
|
||||
Token::new(AToken),
|
||||
Token::new(CToken),
|
||||
Token::new(CToken),
|
||||
Token::new(EOFToken),
|
||||
];
|
||||
|
||||
TokenReader::new(tokens)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek_does_not_consume() {
|
||||
let reader = get_reader();
|
||||
|
||||
assert!(reader.peek_is::<AToken>());
|
||||
assert!(!reader.peek_is::<BToken>());
|
||||
assert!(reader.peek_is::<AToken>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consume_does_consume() {
|
||||
let mut reader = get_reader();
|
||||
assert!(reader.consume_as::<AToken>().is_some());
|
||||
assert!(reader.consume_as::<BToken>().is_some());
|
||||
assert!(reader.consume_as::<AToken>().is_some());
|
||||
assert!(reader.consume_as::<CToken>().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_eof_works() {
|
||||
let mut reader = get_reader();
|
||||
reader.seek(4);
|
||||
assert!(!reader.check_eof());
|
||||
reader.seek(5);
|
||||
assert!(reader.check_eof());
|
||||
}
|
||||
#[test]
|
||||
fn peek_and_consume_returns_eof_on_input_end() {
|
||||
let mut reader = get_reader();
|
||||
reader.seek(4);
|
||||
assert!(reader.consume_as::<EOFToken>().is_none());
|
||||
assert!(reader.consume_as::<EOFToken>().is_some());
|
||||
assert!(reader.consume_as::<EOFToken>().is_some());
|
||||
assert!(reader.consume_as::<EOFToken>().is_some());
|
||||
reader.seek(0);
|
||||
assert!(reader.consume_as::<EOFToken>().is_none());
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
use crate::token::{EOFToken, Token};
|
||||
|
||||
pub struct TokenReader {
|
||||
tokens: Vec<Token>,
|
||||
index: usize,
|
||||
eof: Token,
|
||||
}
|
||||
|
||||
impl TokenReader {
|
||||
/// Creates a new token reader
|
||||
pub fn new(mut tokens: Vec<Token>) -> Self {
|
||||
if tokens.last().is_none() || !tokens.last().unwrap().is::<EOFToken>() {
|
||||
// ensure that the last token always is an EOF Token
|
||||
tokens.push(Token::new(EOFToken));
|
||||
}
|
||||
Self {
|
||||
tokens,
|
||||
index: 0,
|
||||
eof: Token::new(EOFToken),
|
||||
}
|
||||
}
|
||||
|
||||
/// Peeks the next token
|
||||
#[inline]
|
||||
pub fn peek(&self) -> &Token {
|
||||
self.tokens.get(self.index).unwrap_or(&self.eof)
|
||||
}
|
||||
|
||||
/// Checks if the next token is of a specific type without consuming it
|
||||
#[inline]
|
||||
pub fn peek_is<T: 'static>(&self) -> bool {
|
||||
self.peek().is::<T>()
|
||||
}
|
||||
|
||||
/// Peeks the next token and tries to return is as a concrete type
|
||||
#[inline]
|
||||
pub fn peek_as<T: 'static>(&self) -> Option<&T> {
|
||||
self.peek().try_as::<T>()
|
||||
}
|
||||
|
||||
/// Consumes the next token and returns it
|
||||
pub fn consume(&mut self) -> &Token {
|
||||
self.index += 1;
|
||||
self.tokens.get(self.index - 1).unwrap_or(&self.eof)
|
||||
}
|
||||
|
||||
/// Consumes the next token and tries to return it as the specified type
|
||||
#[inline]
|
||||
pub fn consume_as<T: 'static>(&mut self) -> Option<&T> {
|
||||
self.consume().try_as::<T>()
|
||||
}
|
||||
|
||||
/// Seeks to the given index
|
||||
#[inline]
|
||||
pub fn seek(&mut self, to_index: usize) {
|
||||
self.index = to_index
|
||||
}
|
||||
|
||||
/// Returns if EOF has been reached
|
||||
#[inline]
|
||||
pub fn check_eof(&self) -> bool {
|
||||
self.peek_is::<EOFToken>()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue