1use logos::Logos;
2use std::fmt::Display;
3
4#[derive(Debug, Clone, Logos)]
5pub enum Token<'a> {
6 #[token("if")]
7 If,
8 #[token("then")]
9 Then,
10 #[token("else")]
11 Else,
12 #[token("rec")]
13 Rec,
14 #[token("let")]
15 Let,
16 #[token("in")]
17 In,
18 #[token("true")]
19 True,
20 #[token("false")]
21 False,
22 #[token("match")]
23 Match,
24
25 #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice())]
26 Ident(&'a str),
27
28 #[regex(r"[0-9]+\.[0-9]+", |lex| lex.slice().parse::<f64>().unwrap())]
29 Float(f64),
30
31 #[regex(r"[0-9]+", |lex| lex.slice().parse::<i64>().unwrap())]
32 Int(i64),
33
34 #[token("==")]
36 EqEq,
37 #[token("!=")]
38 BangEq,
39 #[token("<=")]
40 LtEq,
41 #[token(">=")]
42 GtEq,
43 #[token("<")]
44 Lt,
45 #[token(">")]
46 Gt,
47
48 #[token("&&")]
50 AndAnd,
51 #[token("||")]
52 PipePipe,
53 #[token("!")]
54 Bang,
55
56 #[token("+")]
58 Plus,
59 #[token("-")]
60 Minus,
61 #[token("*")]
62 Star,
63 #[token("/")]
64 Slash,
65 #[token("^")]
66 Caret,
67
68 #[token("|")]
70 Pipe,
71 #[token("=")]
72 Eq,
73 #[token("(")]
74 LParen,
75 #[token(")")]
76 RParen,
77 #[token("=>")]
78 StrongArrow,
79
80 #[regex(r"[ \t\r\n]+", logos::skip)]
81 WhiteSpace,
82
83 Error,
84}
85
86impl Display for Token<'_> {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 match self {
89 Token::If => write!(f, "if"),
90 Token::Then => write!(f, "then"),
91 Token::Else => write!(f, "else"),
92 Token::Rec => write!(f, "rec"),
93 Token::Let => write!(f, "let"),
94 Token::In => write!(f, "in"),
95 Token::True => write!(f, "true"),
96 Token::False => write!(f, "false"),
97 Token::Ident(v) => write!(f, "{v}"),
98 Token::Float(n) => write!(f, "{n}"),
99 Token::Int(n) => write!(f, "{n}"),
100 Token::EqEq => write!(f, "=="),
101 Token::BangEq => write!(f, "!="),
102 Token::LtEq => write!(f, "<="),
103 Token::GtEq => write!(f, ">="),
104 Token::Lt => write!(f, "<"),
105 Token::Gt => write!(f, ">"),
106 Token::AndAnd => write!(f, "&&"),
107 Token::PipePipe => write!(f, "||"),
108 Token::Bang => write!(f, "!"),
109 Token::Plus => write!(f, "+"),
110 Token::Minus => write!(f, "-"),
111 Token::Star => write!(f, "*"),
112 Token::Slash => write!(f, "/"),
113 Token::Caret => write!(f, "^"),
114 Token::Pipe => write!(f, "|"),
115 Token::Eq => write!(f, "="),
116 Token::LParen => write!(f, "("),
117 Token::RParen => write!(f, ")"),
118 Token::WhiteSpace => write!(f, "<whitespace>"),
119 Token::Error => write!(f, "<error>"),
120 Token::Match => write!(f, "match"),
121 Token::StrongArrow => write!(f, "=>"),
122 }
123 }
124}
125
126impl PartialEq for Token<'_> {
127 fn eq(&self, other: &Self) -> bool {
128 match (self, other) {
129 (Self::Ident(l), Self::Ident(r)) => l == r,
130 (Self::Float(l), Self::Float(r)) => (l.is_nan() && r.is_nan()) || l == r,
131 (Self::Int(l), Self::Int(r)) => l == r,
132 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
133 }
134 }
135}
136
137impl Eq for Token<'_> {}