1use crate::span::Span;
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq)]
8pub struct Token {
9 pub kind: TokenKind,
11 pub span: Span,
13}
14
15impl Token {
16 pub const fn new(kind: TokenKind, span: Span) -> Self {
18 Self { kind, span }
19 }
20}
21
22impl fmt::Display for Token {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 write!(f, "{:?} @ {}", self.kind, self.span)
25 }
26}
27
28#[derive(Debug, Clone, PartialEq)]
30pub enum TokenKind {
31 Datasource,
33 Generator,
35 Model,
37 Enum,
39 Type,
41 True,
43 False,
45
46 Ident(String),
48 String(String),
50 Number(String),
52
53 At,
55 AtAt,
57
58 LBrace,
60 RBrace,
62 LBracket,
64 RBracket,
66 LParen,
68 RParen,
70 Comma,
72 Colon,
74 Equal,
76 Question,
78 Bang,
80 Dot,
82
83 Star,
85 Plus,
87 Minus,
89 Slash,
91 Pipe,
93 DoublePipe,
95 LAngle,
97 RAngle,
99 Percent,
101 LessEqual,
103 GreaterEqual,
105 BangEqual,
107
108 Newline,
110 Eof,
112}
113
114impl TokenKind {
115 pub fn is_keyword(&self) -> bool {
117 matches!(
118 self,
119 TokenKind::Datasource
120 | TokenKind::Generator
121 | TokenKind::Model
122 | TokenKind::Enum
123 | TokenKind::Type
124 | TokenKind::True
125 | TokenKind::False
126 )
127 }
128
129 pub fn from_ident(ident: &str) -> Self {
131 match ident {
132 "datasource" => TokenKind::Datasource,
133 "generator" => TokenKind::Generator,
134 "model" => TokenKind::Model,
135 "enum" => TokenKind::Enum,
136 "type" => TokenKind::Type,
137 "true" => TokenKind::True,
138 "false" => TokenKind::False,
139 _ => TokenKind::Ident(ident.to_string()),
140 }
141 }
142}
143
144impl fmt::Display for TokenKind {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 match self {
147 TokenKind::Datasource => write!(f, "datasource"),
148 TokenKind::Generator => write!(f, "generator"),
149 TokenKind::Model => write!(f, "model"),
150 TokenKind::Enum => write!(f, "enum"),
151 TokenKind::Type => write!(f, "type"),
152 TokenKind::True => write!(f, "true"),
153 TokenKind::False => write!(f, "false"),
154 TokenKind::Ident(s) => write!(f, "identifier '{}'", s),
155 TokenKind::String(s) => write!(f, "string \"{}\"", s),
156 TokenKind::Number(s) => write!(f, "number {}", s),
157 TokenKind::At => write!(f, "@"),
158 TokenKind::AtAt => write!(f, "@@"),
159 TokenKind::LBrace => write!(f, "{{"),
160 TokenKind::RBrace => write!(f, "}}"),
161 TokenKind::LBracket => write!(f, "["),
162 TokenKind::RBracket => write!(f, "]"),
163 TokenKind::LParen => write!(f, "("),
164 TokenKind::RParen => write!(f, ")"),
165 TokenKind::Comma => write!(f, ","),
166 TokenKind::Colon => write!(f, ":"),
167 TokenKind::Equal => write!(f, "="),
168 TokenKind::Question => write!(f, "?"),
169 TokenKind::Bang => write!(f, "!"),
170 TokenKind::Dot => write!(f, "."),
171 TokenKind::Star => write!(f, "*"),
172 TokenKind::Plus => write!(f, "+"),
173 TokenKind::Minus => write!(f, "-"),
174 TokenKind::Slash => write!(f, "/"),
175 TokenKind::Pipe => write!(f, "|"),
176 TokenKind::DoublePipe => write!(f, "||"),
177 TokenKind::LAngle => write!(f, "<"),
178 TokenKind::RAngle => write!(f, ">"),
179 TokenKind::Percent => write!(f, "%"),
180 TokenKind::LessEqual => write!(f, "<="),
181 TokenKind::GreaterEqual => write!(f, ">="),
182 TokenKind::BangEqual => write!(f, "!="),
183 TokenKind::Newline => write!(f, "newline"),
184 TokenKind::Eof => write!(f, "end of file"),
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_keyword_detection() {
195 assert!(TokenKind::Datasource.is_keyword());
196 assert!(TokenKind::Model.is_keyword());
197 assert!(!TokenKind::Ident("foo".to_string()).is_keyword());
198 }
199
200 #[test]
201 fn test_from_ident() {
202 assert_eq!(TokenKind::from_ident("model"), TokenKind::Model);
203 assert_eq!(TokenKind::from_ident("datasource"), TokenKind::Datasource);
204 assert_eq!(
205 TokenKind::from_ident("User"),
206 TokenKind::Ident("User".to_string())
207 );
208 }
209
210 #[test]
211 fn test_token_display() {
212 let token = Token::new(TokenKind::Model, Span::new(0, 5));
213 let display = token.to_string();
214 assert!(display.contains("Model"));
215 }
216}