use crate::{base_traits::Parsable, error::parse_error::ParseError, ConsumableToken};
pub struct TokenIter<Token> {
pub current: usize,
pub tokens: Vec<Token>,
size: usize,
pub stack: Vec<usize>,
}
impl<Token> TokenIter<Token>
where
Token: ConsumableToken,
{
pub fn new(tokens: Vec<Token>) -> TokenIter<Token> {
TokenIter {
current: 0,
size: tokens.len(),
tokens,
stack: vec![],
}
}
pub fn try_do<F, Q, E>(&mut self, f: F) -> Result<Q, E>
where
F: FnOnce(&mut TokenIter<Token>) -> Result<Q, E>,
{
self.stack.push(self.current);
let result = f(self);
if result.is_ok() {
let _ = self.stack.pop();
} else if let Some(c) = self.stack.pop() {
self.current = c;
}
result
}
pub fn parse<P>(&mut self) -> Result<P, ParseError<Token>>
where
P: Parsable<Token>,
{
self.try_do(|token_iter| P::parse(token_iter))
}
pub fn parse_if_match<F, P>(&mut self, matcher: F, pattern: Option<&'static str>) -> Result<P, ParseError<Token>>
where
P: Parsable<Token>,
F: Fn(&P::ApplyMatchTo) -> bool,
{
self.try_do(|token_iter| P::parse_if_match(token_iter, matcher, pattern))
}
pub fn parse_while<I, F, Q>(&mut self, _keep_going: F) -> I
where
I: FromIterator<Q>,
F: Fn(&Q) -> bool,
Q: Parsable<Token>,
{
todo!("Parse while not yet implemented")
}
pub fn consume(&mut self) -> Option<Token> {
match self.get(self.current) {
Some(element) => {
self.current += 1;
Some(element)
}
None => None,
}
}
pub fn get(&self, position: usize) -> Option<Token> {
if position < self.size {
Some(self.tokens[position].clone())
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use crate::test_common::TestStruct;
use crate::{t, Parsable, ParseError, Token, TokenIter};
#[test]
fn parse_if_match_match_enum_token() {
let mut iter: TokenIter<Token> = TokenIter::new(vec![
Token::Comma,
Token::Identifier("Some identifier".to_string()),
]);
let result = iter.parse_if_match(|t| matches!(t, Token::Comma), None);
assert_eq!(result, Ok(Token::Comma));
let result = iter.parse_if_match(|t| matches!(t, Token::Identifier(_)), None);
assert_eq!(result, Ok(Token::Identifier("Some identifier".to_string())));
let result: Result<Token, _> = iter.parse_if_match(|t| matches!(t, Token::Identifier(_)), None);
assert_eq!(result, Err(ParseError::no_more_tokens::<Token>(1)));
let mut iter: TokenIter<Token> =
TokenIter::new(vec![Token::Identifier("Some identifier".to_string())]);
let result: Result<Token, _> = iter.parse_if_match(|t| matches!(t, Token::Comma), None);
assert!(result.is_err());
}
#[test]
fn failed_parse_if_match() {
let tokens = vec![t!(litint 32)];
let mut iter = TokenIter::new(tokens);
let result: Result<Token, _> = iter.parse_if_match(|tok| matches!(tok, t!(return)), None);
let expected = Err(ParseError::parsed_but_unmatching(iter.current, &t!(litint 32), None));
assert_eq!(expected, result);
assert!(iter.current == 0);
}
#[test]
fn failed_parse() {
let tokens = vec![
t!(int),
t!( = ),
t!(litint 3),
];
let mut iter = TokenIter::new(tokens);
let result = TestStruct::parse(&mut iter);
assert!(result.is_err());
assert!(iter.current == 0)
}
#[test]
fn successful_parse() {
let parse_if_matched_var_name = "variable1";
let parse_if_matched_value = 3;
let tokens = vec![
t!(int),
t!(ident parse_if_matched_var_name),
t!( = ),
t!(litint parse_if_matched_value),
Token::LiteralInt(parse_if_matched_value),
t!( ; ),
];
let mut iter = TokenIter::new(tokens);
let parse_if_matched_struct = TestStruct {
var_type: t!(int),
var_name: parse_if_matched_var_name.to_string(),
equals_sign: t!( = ),
value: parse_if_matched_value,
};
let result = TestStruct::parse(&mut iter)
.expect("Should succeed, since tokens represent a valid TestStruct");
assert_eq!(result, parse_if_matched_struct);
}
#[test]
fn test_parse_if_match_empty_token_list() {
let tokens = vec![];
let mut iter = TokenIter::new(tokens);
let result: Result<Token, _> = iter.parse_if_match(|tok| matches!(tok, t!(l_paren)), None);
assert!(result.is_err());
assert!(iter.current == 0);
}
#[test]
fn test_parse_if_match() {
let tokens = vec![t!(l_paren), t!(r_paren), t!(,), t!(litint 4)];
let mut iter = TokenIter::new(tokens);
let lparen_r: Token = iter
.parse_if_match(|tok| matches!(tok, t!(l_paren)), None)
.unwrap();
assert!(lparen_r == t!(l_paren));
let rparen_r: Token = iter
.parse_if_match(|tok| matches!(tok, t!(r_paren)), None)
.unwrap();
assert!(rparen_r == t!(r_paren));
let comma_r: Token = iter.parse_if_match(|tok| matches!(tok, t!( , )), None).unwrap();
assert_eq!(comma_r, t!( , ));
let litint_r: Token = iter
.parse_if_match(|tok| matches!(tok, t!(litint 4)), None)
.unwrap();
assert!(litint_r == t!(litint 4));
assert!(iter.current == 4)
}
#[test]
fn test_new() {
let tokens = vec![
t!(l_paren),
t!(litint 21),
t!(,),
t!(litint 2),
t!(,),
t!(litint 21),
t!(,),
t!(litint 2),
t!(,),
t!(r_paren),
];
let iter = TokenIter::new(tokens);
assert_eq!(iter.current, 0);
assert_eq!(iter.tokens.len(), 10);
assert_eq!(iter.stack.len(), 0);
}
#[test]
fn test_new_empty() {
let max = usize::MAX;
println!("{max}");
let tokens = vec![];
let iter = TokenIter::<Token>::new(tokens);
assert_eq!(iter.current, 0);
assert_eq!(iter.tokens.len(), 0);
assert_eq!(iter.stack.len(), 0);
}
}