1use crate::span::Span;
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct Token<'a> {
5 pub kind: TokenKind<'a>,
6 pub span: Span,
7}
8
9#[derive(Debug, Clone, PartialEq)]
11pub enum TokenKind<'a> {
12 Ident(&'a str),
14 Int(i64),
15 Float(f64),
16 Str(&'a str),
18 InterpStr(Vec<StrPart<'a>>),
19 ImportPath {
21 path: &'a str,
22 version: &'a str,
23 },
24 True,
25 False,
26 Null,
27 Import,
29 As,
30 Type,
31 Enum,
32 Def,
33 End,
34 Domain,
35 New,
36 Assert,
37 Shadow,
38 Pub,
39 Cond,
40 Else,
41 Newline,
43 LParen,
44 RParen,
45 LBracket,
46 RBracket,
47 Colon,
48 Comma,
49 Dot,
50 Assign,
51 Arrow,
52 Question,
53 Plus,
55 Minus,
56 Star,
57 Slash,
58 Percent,
59 EqEq,
60 NotEq,
61 Lt,
62 Gt,
63 LtEq,
64 GtEq,
65 And,
66 Or,
67 Not,
68 Eof,
69}
70
71#[derive(Debug, Clone, PartialEq)]
72pub enum StrPart<'a> {
73 Lit(&'a str),
74 Interp(&'a str),
76}
77
78pub const KEYWORDS: &[&str] = &[
83 "import", "as", "type", "enum", "def", "end", "domain", "new", "assert", "shadow", "pub",
84 "cond", "else", "true", "false", "null",
85];
86
87impl TokenKind<'_> {
88 pub(crate) fn keyword(ident: &str) -> Option<TokenKind<'static>> {
89 Some(match ident {
90 "import" => TokenKind::Import,
91 "as" => TokenKind::As,
92 "type" => TokenKind::Type,
93 "enum" => TokenKind::Enum,
94 "def" => TokenKind::Def,
95 "end" => TokenKind::End,
96 "domain" => TokenKind::Domain,
97 "new" => TokenKind::New,
98 "assert" => TokenKind::Assert,
99 "shadow" => TokenKind::Shadow,
100 "pub" => TokenKind::Pub,
101 "cond" => TokenKind::Cond,
102 "else" => TokenKind::Else,
103 "true" => TokenKind::True,
104 "false" => TokenKind::False,
105 "null" => TokenKind::Null,
106 _ => return None,
107 })
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn keywords_const_matches_the_recognizer() {
117 for kw in KEYWORDS {
120 assert!(
121 TokenKind::keyword(kw).is_some(),
122 "`{kw}` is in KEYWORDS but not recognized by keyword()"
123 );
124 }
125 assert!(TokenKind::keyword("text").is_none(), "text is contextual");
126 assert!(TokenKind::keyword("nope").is_none());
127 }
128}