1use crate::Span;
5use crate::tokens::from_logos::from_logos;
6use crate::tokens::logos::NormalToken;
7use ::logos::Lexer;
8use std::borrow::Cow;
9use std::fmt::{Display, Formatter};
10use thiserror::Error;
11
12mod from_logos;
13mod logos;
14
15#[derive(Debug, PartialEq, Clone)]
17pub struct SpannedToken<T> {
18 pub span: Span,
20 pub token: T,
22}
23
24impl SpannedToken<Token<'_>> {
25 pub fn into_owned(self) -> SpannedToken<Token<'static>> {
27 SpannedToken {
28 span: self.span,
29 token: self.token.into_owned(),
30 }
31 }
32}
33
34impl<T> SpannedToken<T> {
35 pub fn new(span: Span, token: T) -> Self {
37 SpannedToken { span, token }
38 }
39}
40
41impl<T: PartialEq> PartialEq<T> for SpannedToken<T> {
42 fn eq(&self, other: &T) -> bool {
43 self.token.eq(other)
44 }
45}
46
47#[derive(Debug, Default, Clone, PartialEq, Error)]
49pub enum LexerError {
50 #[default]
52 #[error("No valid token")]
53 NoValidToken,
54 #[error("Unclosed format string")]
56 UnclosedStringFormat(Span),
57 #[error("Unclosed string")]
59 UnclosedString(Span),
60}
61
62impl LexerError {
63 pub fn kind(&self) -> &'static str {
65 match self {
66 LexerError::NoValidToken => "no valid token",
67 LexerError::UnclosedStringFormat(_) => "unclosed format string",
68 LexerError::UnclosedString(_) => "unclosed string",
69 }
70 }
71}
72
73impl LexerError {
74 pub fn span(&self) -> Option<Span> {
76 match self {
77 LexerError::UnclosedStringFormat(span) => Some(span.clone()),
78 LexerError::UnclosedString(span) => Some(span.clone()),
79 _ => None,
80 }
81 }
82}
83
84pub fn lex<'a>(input: &'a str) -> impl Iterator<Item = SpannedToken<Token<'a>>> {
86 from_logos(Lexer::<NormalToken>::new(input).spanned())
87}
88
89#[derive(Debug, PartialEq, Clone)]
91pub enum Token<'a> {
92 SingleLineComment(Cow<'a, str>),
94 MultiLineComment(Cow<'a, str>),
96 DocComment(Cow<'a, str>),
98
99 KeywordMod,
101 KeywordPart,
103 KeywordSketch,
105 KeywordOp,
107 KeywordFn,
109 KeywordIf,
111 KeywordElse,
113 KeywordUse,
115 KeywordAs,
117 KeywordReturn,
119 KeywordPub,
121 KeywordConst,
123 KeywordProp,
125 KeywordInit,
127
128 Identifier(Cow<'a, str>),
130 Unit(Cow<'a, str>),
132
133 LiteralInt(Cow<'a, str>),
135 LiteralFloat(Cow<'a, str>),
137 LiteralBool(bool),
139 LiteralString(Cow<'a, str>),
141
142 FormatStringStart,
144 FormatStringEnd,
146 StringContent(Cow<'a, str>),
148 Character(char),
150 StringFormatOpen,
152 StringFormatClose,
154 StringFormatPrecision(Cow<'a, str>),
156 StringFormatWidth(Cow<'a, str>),
158
159 SigilColon,
161 SigilSemiColon,
163 SigilDoubleColon,
165 SigilOpenBracket,
167 SigilCloseBracket,
169 SigilOpenSquareBracket,
171 SigilCloseSquareBracket,
173 SigilOpenCurlyBracket,
175 SigilCloseCurlyBracket,
177 SigilHash,
179 SigilDot,
181 SigilComma,
183 SigilDoubleDot,
185 SigilAt,
187 SigilSingleArrow,
189 SigilQuote,
191
192 OperatorAdd,
194 OperatorSubtract,
196 OperatorMultiply,
198 OperatorDivide,
200 OperatorUnion,
202 OperatorIntersect,
204 OperatorPowerXor,
206 OperatorGreaterThan,
208 OperatorLessThan,
210 OperatorGreaterEqual,
212 OperatorLessEqual,
214 OperatorNear,
216 OperatorEqual,
218 OperatorNotEqual,
220 OperatorAnd,
222 OperatorOr,
224 OperatorXor,
226 OperatorNot,
228 OperatorAssignment,
230
231 Error(LexerError),
235}
236
237impl Display for Token<'_> {
238 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
239 write!(f, "{}", self.kind())
240 }
241}
242
243impl Token<'_> {
244 pub fn into_owned(self) -> Token<'static> {
246 match self {
247 Token::SingleLineComment(c) => Token::SingleLineComment(c.into_owned().into()),
248 Token::MultiLineComment(c) => Token::MultiLineComment(c.into_owned().into()),
249 Token::DocComment(c) => Token::DocComment(c.into_owned().into()),
250 Token::Identifier(s) => Token::Identifier(s.into_owned().into()),
251 Token::Unit(s) => Token::Unit(s.into_owned().into()),
252 Token::LiteralInt(s) => Token::LiteralInt(s.into_owned().into()),
253 Token::LiteralFloat(s) => Token::LiteralFloat(s.into_owned().into()),
254 Token::LiteralString(s) => Token::LiteralString(s.into_owned().into()),
255
256 Token::KeywordMod => Token::KeywordMod,
257 Token::KeywordPart => Token::KeywordPart,
258 Token::KeywordSketch => Token::KeywordSketch,
259 Token::KeywordOp => Token::KeywordOp,
260 Token::KeywordFn => Token::KeywordFn,
261 Token::KeywordIf => Token::KeywordIf,
262 Token::KeywordElse => Token::KeywordElse,
263 Token::KeywordUse => Token::KeywordUse,
264 Token::KeywordAs => Token::KeywordAs,
265 Token::KeywordReturn => Token::KeywordReturn,
266 Token::KeywordPub => Token::KeywordPub,
267 Token::KeywordConst => Token::KeywordConst,
268 Token::KeywordProp => Token::KeywordProp,
269 Token::KeywordInit => Token::KeywordInit,
270 Token::LiteralBool(l) => Token::LiteralBool(l),
271 Token::SigilColon => Token::SigilColon,
272 Token::SigilSemiColon => Token::SigilSemiColon,
273 Token::SigilDoubleColon => Token::SigilDoubleColon,
274 Token::SigilOpenBracket => Token::SigilOpenBracket,
275 Token::SigilCloseBracket => Token::SigilCloseBracket,
276 Token::SigilOpenSquareBracket => Token::SigilOpenSquareBracket,
277 Token::SigilCloseSquareBracket => Token::SigilCloseSquareBracket,
278 Token::SigilOpenCurlyBracket => Token::SigilOpenCurlyBracket,
279 Token::SigilCloseCurlyBracket => Token::SigilCloseCurlyBracket,
280 Token::SigilHash => Token::SigilHash,
281 Token::SigilDot => Token::SigilDot,
282 Token::SigilComma => Token::SigilComma,
283 Token::SigilDoubleDot => Token::SigilDoubleDot,
284 Token::SigilAt => Token::SigilAt,
285 Token::SigilSingleArrow => Token::SigilSingleArrow,
286 Token::OperatorAdd => Token::OperatorAdd,
287 Token::OperatorSubtract => Token::OperatorSubtract,
288 Token::OperatorMultiply => Token::OperatorMultiply,
289 Token::OperatorDivide => Token::OperatorDivide,
290 Token::OperatorUnion => Token::OperatorUnion,
291 Token::OperatorIntersect => Token::OperatorIntersect,
292 Token::OperatorPowerXor => Token::OperatorPowerXor,
293 Token::OperatorGreaterThan => Token::OperatorGreaterThan,
294 Token::OperatorLessThan => Token::OperatorLessThan,
295 Token::OperatorGreaterEqual => Token::OperatorGreaterEqual,
296 Token::OperatorLessEqual => Token::OperatorLessEqual,
297 Token::OperatorNear => Token::OperatorNear,
298 Token::OperatorEqual => Token::OperatorEqual,
299 Token::OperatorNotEqual => Token::OperatorNotEqual,
300 Token::OperatorAnd => Token::OperatorAnd,
301 Token::OperatorOr => Token::OperatorOr,
302 Token::OperatorXor => Token::OperatorXor,
303 Token::OperatorNot => Token::OperatorNot,
304 Token::OperatorAssignment => Token::OperatorAssignment,
305 Token::FormatStringStart => Token::FormatStringStart,
306 Token::FormatStringEnd => Token::FormatStringEnd,
307 Token::StringContent(s) => Token::StringContent(s.into_owned().into()),
308 Token::Character(c) => Token::Character(c),
309 Token::StringFormatOpen => Token::StringFormatOpen,
310 Token::StringFormatClose => Token::StringFormatClose,
311 Token::SigilQuote => Token::SigilQuote,
312 Token::Error(e) => Token::Error(e),
313 Token::StringFormatPrecision(c) => Token::StringFormatPrecision(c.into_owned().into()),
314 Token::StringFormatWidth(c) => Token::StringFormatWidth(c.into_owned().into()),
315 }
316 }
317
318 pub fn kind(&self) -> &'static str {
320 match self {
321 Token::SingleLineComment(_) => "single-line comment",
322 Token::MultiLineComment(_) => "multi-line comment",
323 Token::DocComment(_) => "doc comment",
324 Token::KeywordMod => "mod",
325 Token::KeywordPart => "part",
326 Token::KeywordSketch => "sketch",
327 Token::KeywordOp => "op",
328 Token::KeywordFn => "fn",
329 Token::KeywordIf => "if",
330 Token::KeywordElse => "else",
331 Token::KeywordUse => "use",
332 Token::KeywordAs => "as",
333 Token::KeywordReturn => "return",
334 Token::KeywordPub => "pub",
335 Token::KeywordConst => "const",
336 Token::KeywordProp => "prop",
337 Token::KeywordInit => "init",
338 Token::Identifier(_) => "identifier",
339 Token::Unit(_) => "unit",
340 Token::LiteralInt(_) => "integer literal",
341 Token::LiteralFloat(_) => "float literal",
342 Token::LiteralBool(_) => "boolean literal",
343 Token::LiteralString(_) => "string literal",
344 Token::FormatStringStart => "start of string",
345 Token::FormatStringEnd => "end of string",
346 Token::StringContent(_) => "string content",
347 Token::Character(_) => "escaped character",
348 Token::StringFormatOpen => "string format start",
349 Token::StringFormatClose => "string format end",
350 Token::SigilColon => ":",
351 Token::SigilSemiColon => ";",
352 Token::SigilDoubleColon => "::",
353 Token::SigilOpenBracket => "(",
354 Token::SigilCloseBracket => ")",
355 Token::SigilOpenSquareBracket => "[",
356 Token::SigilCloseSquareBracket => "]",
357 Token::SigilOpenCurlyBracket => "{",
358 Token::SigilCloseCurlyBracket => "}",
359 Token::SigilHash => "#",
360 Token::SigilDot => ".",
361 Token::SigilComma => ",",
362 Token::SigilDoubleDot => "..",
363 Token::SigilAt => "@",
364 Token::SigilSingleArrow => "->",
365 Token::SigilQuote => "\"",
366 Token::OperatorAdd => "+",
367 Token::OperatorSubtract => "-",
368 Token::OperatorMultiply => "*",
369 Token::OperatorDivide => "/",
370 Token::OperatorUnion => "|",
371 Token::OperatorIntersect => "&",
372 Token::OperatorPowerXor => "^",
373 Token::OperatorGreaterThan => ">",
374 Token::OperatorLessThan => "<",
375 Token::OperatorGreaterEqual => ">=",
376 Token::OperatorLessEqual => "<=",
377 Token::OperatorNear => "!",
378 Token::OperatorEqual => "==",
379 Token::OperatorNotEqual => "!=",
380 Token::OperatorAnd => "and",
381 Token::OperatorOr => "or",
382 Token::OperatorXor => "xor",
383 Token::OperatorNot => "not",
384 Token::OperatorAssignment => "=",
385 Token::StringFormatPrecision(_) => "format precision",
386 Token::StringFormatWidth(_) => "format width",
387 Token::Error(e) => e.kind(),
388 }
389 }
390
391 pub fn is_error(&self) -> bool {
393 matches!(self, Token::Error(_))
394 }
395}