1mod cursor;
2mod lexer;
3mod token;
4
5pub use lexer::tokenize;
6pub use token::{Token, TokenKind};
7
8#[cfg(test)]
9mod tests {
10 use super::{TokenKind, tokenize};
11
12 #[test]
13 fn preserves_comments_and_newlines() {
14 let tokens = tokenize("project(example) # trailing\n");
15
16 assert!(matches!(tokens[0].kind, TokenKind::Identifier(_)));
17 assert!(matches!(tokens[1].kind, TokenKind::LeftParen));
18 assert!(matches!(tokens[2].kind, TokenKind::Identifier(_)));
19 assert!(matches!(tokens[3].kind, TokenKind::RightParen));
20 assert!(matches!(tokens[4].kind, TokenKind::Whitespace(_)));
21 assert!(matches!(tokens[5].kind, TokenKind::Comment(_)));
22 assert!(matches!(tokens[6].kind, TokenKind::Newline));
23 }
24
25 #[test]
26 fn tokenizes_bracket_arguments() {
27 let tokens = tokenize("message([=[hello]=])");
28 assert!(matches!(tokens[2].kind, TokenKind::BracketArgument(_)));
29 }
30
31 #[test]
32 fn normalizes_crlf_to_newline_tokens() {
33 let tokens = tokenize("project(example)\r\nmessage(STATUS hi)\r\n");
34 assert_eq!(
35 tokens
36 .iter()
37 .filter(|token| matches!(token.kind, TokenKind::Newline))
38 .count(),
39 2
40 );
41 }
42
43 #[test]
44 fn tokenizes_quoted_arguments_with_escapes() {
45 let tokens = tokenize("message(\"a \\\"quoted\\\" value\")");
46 let TokenKind::QuotedArgument(text) = &tokens[2].kind else {
47 panic!("expected quoted argument");
48 };
49 assert_eq!(text, "\"a \\\"quoted\\\" value\"");
50 }
51
52 #[test]
53 fn tokenizes_non_identifier_bare_words_as_unquoted_arguments() {
54 let tokens = tokenize("set(VAR foo-bar)");
55 assert!(matches!(tokens[4].kind, TokenKind::UnquotedArgument(_)));
56 }
57}