use super::{
cursor::Cursor,
token::{Token, TokenKind},
};
macro_rules! separator {
(
$( $value:ident => $tag:literal ),*
) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Separator { $( $value ),* }
impl Separator {
pub fn as_str(&self) -> &'static str {
match self {
$( Separator::$value => $tag ),*
}
}
}
};
}
separator! {
Semicolon => ";",
Comma => ",",
NewLine => "\n"
}
pub fn scan_separator<'b>(cursor: &mut Cursor<'b>) -> Option<Token<'b>> {
let start_pos = cursor.pos();
let start_line = cursor.line();
let start_column = cursor.column();
let sep = match cursor.peek()? {
';' => Separator::Semicolon,
',' => Separator::Comma,
'\n' => Separator::NewLine,
_ => return None,
};
cursor.consume();
Some(Token {
kind: TokenKind::Separator(sep),
fragment: cursor.make_fragment(start_pos, start_line, start_column),
})
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::{bump::Bump, token::tokenize};
#[test]
fn test_parse_separator_invalid() {
let bump = Bump::new();
let tokens = tokenize(&bump, "foobar rest").unwrap();
assert_eq!(tokens[0].kind, TokenKind::Identifier);
}
fn check_separator(op: Separator, symbol: &str) {
let bump = Bump::new();
let input_str = format!("{symbol} rest");
let tokens = tokenize(&bump, &input_str).unwrap();
assert!(tokens.len() >= 2);
assert_eq!(TokenKind::Separator(op), tokens[0].kind, "type mismatch for symbol: {}", symbol);
assert_eq!(tokens[0].fragment.text(), symbol);
assert_eq!(tokens[0].fragment.column().0, 1);
assert_eq!(tokens[0].fragment.line().0, 1);
}
macro_rules! generate_test {
($($name:ident => ($variant:ident, $symbol:literal)),*) => {
$(
#[test]
fn $name() {
check_separator(Separator::$variant, $symbol);
}
)*
};
}
generate_test! {
test_separator_semicolon => (Semicolon, ";"),
test_separator_comma => (Comma, ",")
}
#[test]
fn test_separator_new_line() {
let bump = Bump::new();
let tokens = tokenize(&bump, "\n rest").unwrap();
assert_eq!(tokens.len(), 1);
assert_eq!(tokens[0].kind, TokenKind::Identifier);
assert_eq!(tokens[0].fragment.text(), "rest");
assert_eq!(tokens[0].fragment.line().0, 2);
assert_eq!(tokens[0].fragment.column().0, 2);
}
}