1use logos::Logos;
2use parse_display::Display;
3use std::str;
4
5#[derive(PartialEq, Debug, Logos, Display, Clone)]
7#[logos(skip r"[ \t\f\r\n]+")] #[logos(skip r"//[^\n]*")] pub enum Token {
10 #[token("{")]
12 #[display("start of group")]
13 GroupStart,
14 #[token("}")]
16 #[display("end of group")]
17 GroupEnd,
18 #[regex("[^# \t\n{}\"][^ \t\n\r{}]*", priority = 0)]
20 #[display("item")]
21 Item,
22 #[regex("\"([^\"\\\\]|\\\\.)*\"")]
24 #[display("quoted item")]
25 QuotedItem,
26 #[regex("#[^ \"\t\n\r{}]+")]
28 #[display("statement")]
29 Statement,
30 #[regex("\"#([^\"\\\\]|\\\\.)*\"")]
32 #[display("quoted statement")]
33 QuotedStatement,
34}
35
36#[cfg(test)]
37mod tests {
38 use super::Token;
39 use logos::Logos;
40
41 fn get_token(input: &str) -> Option<Result<Token, <Token as Logos>::Error>> {
42 let mut lex = Token::lexer(input);
43 lex.next()
44 }
45
46 fn get_tokens(input: &str) -> Result<Vec<(Token, &str)>, <Token as Logos>::Error> {
47 Token::lexer(input)
48 .spanned()
49 .map(|(res, span)| res.map(|token| (token, &input[span])))
50 .collect()
51 }
52
53 #[test]
54 fn next() {
55 assert_eq!(get_token("test"), Some(Ok(Token::Item)));
56 assert_eq!(get_token("\"test\""), Some(Ok(Token::QuotedItem)));
57 assert_eq!(get_token("\"\""), Some(Ok(Token::QuotedItem)));
58 assert_eq!(get_token("\"\" "), Some(Ok(Token::QuotedItem)));
59 assert_eq!(get_token("#test"), Some(Ok(Token::Statement)));
60 assert_eq!(get_token("\"#test\""), Some(Ok(Token::QuotedStatement)));
61 assert_eq!(get_token("{"), Some(Ok(Token::GroupStart)));
62 assert_eq!(get_token("}"), Some(Ok(Token::GroupEnd)));
63 assert_eq!(get_token("//test more"), None);
64
65 assert_eq!(get_token("test"), Some(Ok(Token::Item)));
66 assert_eq!(get_token("#test"), Some(Ok(Token::Statement)));
67
68 assert_eq!(get_token("lol wut"), Some(Ok(Token::Item)));
69 assert_eq!(get_token("#lol wut"), Some(Ok(Token::Statement)));
70
71 assert_eq!(get_token("lol{"), Some(Ok(Token::Item)));
72 assert_eq!(get_token("#lol{"), Some(Ok(Token::Statement)));
73
74 assert_eq!(get_token("lol}"), Some(Ok(Token::Item)));
75 assert_eq!(get_token("#lol}"), Some(Ok(Token::Statement)));
76
77 assert_eq!(get_token("\"test\""), Some(Ok(Token::QuotedItem)));
78 assert_eq!(get_token("\"#test\""), Some(Ok(Token::QuotedStatement)));
79
80 assert_eq!(get_token("\"te\\\"st\""), Some(Ok(Token::QuotedItem)));
81 assert_eq!(get_token("\"te\\st\""), Some(Ok(Token::QuotedItem)));
82 assert_eq!(get_token("\"#te\\\"st\""), Some(Ok(Token::QuotedStatement)));
83 }
84
85 #[test]
86 fn tokenize() {
87 assert_eq!(
88 get_tokens(
89 r#"foo { // eol comment
90 "asd" "bar"
91 // a comment
92 #include other
93 empty ""
94 \\"broken" comment
95 }"#
96 ),
97 Ok(vec![
98 (Token::Item, "foo"),
99 (Token::GroupStart, "{"),
100 (Token::QuotedItem, r#""asd""#),
101 (Token::QuotedItem, r#""bar""#),
102 (Token::Statement, r#"#include"#),
103 (Token::Item, r#"other"#),
104 (Token::Item, r#"empty"#),
105 (Token::QuotedItem, r#""""#),
106 (Token::Item, r#"\\"broken""#),
107 (Token::Item, r#"comment"#),
108 (Token::GroupEnd, "}")
109 ])
110 )
111 }
112}