use crate::internal::errors::ParseError;
pub fn expect<'a>(
tokens: &'a [(crate::internal::lexer::Token, &'a str)],
pos: &mut usize,
expect_fn: fn(&crate::internal::lexer::Token) -> bool,
expected: &'static str,
) -> Result<(crate::internal::lexer::Token, &'a str), ParseError> {
if let Some((tok, slice)) = tokens.get(*pos).cloned() {
if expect_fn(&tok) {
*pos += 1;
Ok((tok, slice))
} else {
Err(ParseError::Unexpected {
expected,
found: Some(tok),
})
}
} else {
Err(ParseError::Unexpected {
expected,
found: None,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::internal::lexer::Token;
#[test]
fn test_expect_success() {
let tokens = vec![
(Token::ColumnName, "y"),
(Token::Tilde, "~")
];
let mut pos = 0;
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::ColumnName), "ColumnName");
assert!(result.is_ok());
let (token, slice) = result.unwrap();
assert_eq!(token, Token::ColumnName);
assert_eq!(slice, "y");
assert_eq!(pos, 1); }
#[test]
fn test_expect_failure_wrong_token() {
let tokens = vec![
(Token::Tilde, "~"),
(Token::ColumnName, "y")
];
let mut pos = 0;
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::ColumnName), "ColumnName");
assert!(result.is_err());
if let ParseError::Unexpected { expected, found } = result.unwrap_err() {
assert_eq!(expected, "ColumnName");
assert_eq!(found, Some(Token::Tilde));
} else {
panic!("Expected ParseError::Unexpected");
}
assert_eq!(pos, 0); }
#[test]
fn test_expect_failure_end_of_input() {
let tokens = vec![
(Token::ColumnName, "y")
];
let mut pos = 1;
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::Tilde), "~");
assert!(result.is_err());
if let ParseError::Unexpected { expected, found } = result.unwrap_err() {
assert_eq!(expected, "~");
assert_eq!(found, None);
} else {
panic!("Expected ParseError::Unexpected");
}
assert_eq!(pos, 1); }
#[test]
fn test_expect_with_complex_predicate() {
let tokens = vec![
(Token::ColumnName, "x"),
(Token::Integer, "42"),
(Token::One, "1")
];
let mut pos = 0;
let numeric_predicate = |t: &Token| matches!(t, Token::Integer | Token::One);
let result = expect(&tokens, &mut pos, numeric_predicate, "numeric token");
assert!(result.is_err()); assert_eq!(pos, 0);
pos = 1;
let result = expect(&tokens, &mut pos, numeric_predicate, "numeric token");
assert!(result.is_ok()); assert_eq!(pos, 2);
}
#[test]
fn test_expect_advances_position_on_success() {
let tokens = vec![
(Token::ColumnName, "y"),
(Token::Tilde, "~"),
(Token::ColumnName, "x")
];
let mut pos = 0;
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::ColumnName), "ColumnName");
assert!(result.is_ok());
assert_eq!(pos, 1);
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::Tilde), "~");
assert!(result.is_ok());
assert_eq!(pos, 2);
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::ColumnName), "ColumnName");
assert!(result.is_ok());
assert_eq!(pos, 3);
}
#[test]
fn test_expect_with_empty_tokens() {
let tokens: Vec<(Token, &str)> = vec![];
let mut pos = 0;
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::ColumnName), "ColumnName");
assert!(result.is_err());
if let ParseError::Unexpected { expected, found } = result.unwrap_err() {
assert_eq!(expected, "ColumnName");
assert_eq!(found, None);
} else {
panic!("Expected ParseError::Unexpected");
}
assert_eq!(pos, 0); }
#[test]
fn test_expect_preserves_string_slice() {
let tokens = vec![
(Token::ColumnName, "response_variable"),
(Token::Integer, "12345")
];
let mut pos = 0;
let result = expect(&tokens, &mut pos, |t| matches!(t, Token::ColumnName), "ColumnName");
assert!(result.is_ok());
let (_, slice) = result.unwrap();
assert_eq!(slice, "response_variable");
}
}