use crate::internal::{ast::Response, errors::ParseError, lexer::Token};
pub fn parse_response<'a>(
tokens: &'a [(Token, &'a str)],
pos: &mut usize,
) -> Result<Response, ParseError> {
let (token, name) = crate::internal::expect::expect(
tokens,
pos,
|t| matches!(t, Token::ColumnName | Token::Bind),
"ColumnName or Bind",
)?;
match token {
Token::ColumnName => {
Ok(Response::Single(name.to_string()))
}
Token::Bind => {
crate::internal::expect::expect(
tokens,
pos,
|t| matches!(t, Token::FunctionStart),
"(",
)?;
let mut variables = Vec::new();
let (_, first_var) = crate::internal::expect::expect(
tokens,
pos,
|t| matches!(t, Token::ColumnName),
"ColumnName",
)?;
variables.push(first_var.to_string());
while crate::internal::matches::matches(tokens, pos, |t| matches!(t, Token::Comma)) {
let (_, var_name) = crate::internal::expect::expect(
tokens,
pos,
|t| matches!(t, Token::ColumnName),
"ColumnName",
)?;
variables.push(var_name.to_string());
}
crate::internal::expect::expect(tokens, pos, |t| matches!(t, Token::FunctionEnd), ")")?;
if variables.len() < 2 {
return Err(ParseError::Syntax(
"bind() requires at least 2 variables".into(),
));
}
Ok(Response::Multivariate(variables))
}
_ => unreachable!(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::internal::lexer::Token;
#[test]
fn test_parse_response_simple() {
let tokens = vec![
(Token::ColumnName, "y"),
(Token::Tilde, "~"),
(Token::ColumnName, "x"),
];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_ok());
match result.unwrap() {
Response::Single(name) => assert_eq!(name, "y"),
_ => panic!("Expected single response"),
}
assert_eq!(pos, 1); }
#[test]
fn test_parse_response_with_long_name() {
let tokens = vec![
(Token::ColumnName, "response_variable"),
(Token::Tilde, "~"),
(Token::ColumnName, "x"),
];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_ok());
match result.unwrap() {
Response::Single(name) => assert_eq!(name, "response_variable"),
_ => panic!("Expected single response"),
}
assert_eq!(pos, 1);
}
#[test]
fn test_parse_response_failure_wrong_token() {
let tokens = vec![(Token::Tilde, "~"), (Token::ColumnName, "y")];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_err());
assert_eq!(pos, 0); }
#[test]
fn test_parse_response_failure_end_of_input() {
let tokens: Vec<(Token, &str)> = vec![];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_err());
assert_eq!(pos, 0); }
#[test]
fn test_parse_response_with_numeric_name() {
let tokens = vec![
(Token::ColumnName, "y1"),
(Token::Tilde, "~"),
(Token::ColumnName, "x"),
];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_ok());
match result.unwrap() {
Response::Single(name) => assert_eq!(name, "y1"),
_ => panic!("Expected single response"),
}
assert_eq!(pos, 1);
}
#[test]
fn test_parse_response_with_underscore_name() {
let tokens = vec![
(Token::ColumnName, "target_variable"),
(Token::Tilde, "~"),
(Token::ColumnName, "feature"),
];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_ok());
match result.unwrap() {
Response::Single(name) => assert_eq!(name, "target_variable"),
_ => panic!("Expected single response"),
}
assert_eq!(pos, 1);
}
#[test]
fn test_parse_response_preserves_position_on_failure() {
let tokens = vec![(Token::Plus, "+"), (Token::ColumnName, "y")];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_err());
assert_eq!(pos, 0); }
#[test]
fn test_parse_response_with_single_token() {
let tokens = vec![(Token::ColumnName, "z")];
let mut pos = 0;
let result = parse_response(&tokens, &mut pos);
assert!(result.is_ok());
match result.unwrap() {
Response::Single(name) => assert_eq!(name, "z"),
_ => panic!("Expected single response"),
}
assert_eq!(pos, 1);
}
}