use crate::token::Token;
use crate::utils::{
ParseResult,
accumulate_while,
is_identifier_end,
};
pub fn parse_identifier_or_keyword<'a>(input: &'a str) -> ParseResult<'a> {
let (identifier, next_input) = accumulate_while(input, is_identifier_end);
let token = match identifier {
"and" | "break" | "do" | "else" | "elseif" | "end" | "false"
| "for" | "function" | "if" | "in" | "local" | "nil"
| "not" | "or" | "repeat" | "return" | "then" | "true"
| "until" | "while" => Token::new_keyword(identifier),
_ => Token::new_identifier(identifier),
};
Ok((token, next_input))
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! test_identifier {
($($input:literal),+) => {
#[test]
fn parse_identifiers() {
$(
let (token, rest) = parse_identifier_or_keyword($input).unwrap();
assert_eq!(token, Token::new_identifier($input));
assert_eq!(rest, "");
)+
}
};
}
macro_rules! test_keyword {
($($name:ident : $input:literal),+) => {
$(
#[test]
fn $name() {
let (token, rest) = parse_identifier_or_keyword($input).unwrap();
assert_eq!(token, Token::new_keyword($input));
assert_eq!(rest, "");
}
)+
};
}
test_identifier!(
"i",
"_",
"identifier",
"CONSTANT",
"mixedCASE",
"snake_case",
"numbers123",
"_variable",
"_123abc"
);
test_keyword!(
keyword_and: "and",
keyword_break: "break",
keyword_do: "do",
keyword_else: "else",
keyword_elseif: "elseif",
keyword_end: "end",
keyword_false: "false",
keyword_for: "for",
keyword_function: "function",
keyword_if: "if",
keyword_in: "in",
keyword_local: "local",
keyword_nil: "nil",
keyword_not: "not",
keyword_or: "or",
keyword_repeat: "repeat",
keyword_return: "return",
keyword_then: "then",
keyword_true: "true",
keyword_until: "until",
keyword_while: "while"
);
}