Skip to main content

nifty_syntax/
token.rs

1use std::borrow::Cow;
2
3use crate::span::Span;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum TokenKind {
7    Ident,
8    Int,
9    Float,
10
11    /// A string is `StringStart (StringText | InterpolationStart … InterpolationEnd)* StringEnd`.
12    StringStart,
13    StringText,
14    InterpolationStart,
15    InterpolationEnd,
16    StringEnd,
17
18    State,
19    Let,
20    Fn,
21    View,
22    Struct,
23    If,
24    Else,
25    For,
26    In,
27    Return,
28    True,
29    False,
30
31    LParen,
32    RParen,
33    LBrace,
34    RBrace,
35    LBracket,
36    RBracket,
37    Comma,
38    Colon,
39    Dot,
40    DotDot,
41    Arrow,
42    Dollar,
43
44    Plus,
45    Minus,
46    Star,
47    Slash,
48    Percent,
49    Bang,
50    Eq,
51    EqEq,
52    BangEq,
53    Lt,
54    LtEq,
55    Gt,
56    GtEq,
57    AndAnd,
58    OrOr,
59    PlusEq,
60    MinusEq,
61    StarEq,
62    SlashEq,
63
64    Newline,
65    Eof,
66}
67
68/// Every keyword; [`TokenKind::text`] spells them.
69pub const KEYWORDS: &[TokenKind] = &[
70    TokenKind::State,
71    TokenKind::Let,
72    TokenKind::Fn,
73    TokenKind::View,
74    TokenKind::Struct,
75    TokenKind::If,
76    TokenKind::Else,
77    TokenKind::For,
78    TokenKind::In,
79    TokenKind::Return,
80    TokenKind::True,
81    TokenKind::False,
82];
83
84/// Every punctuation and operator token; [`TokenKind::text`] spells them.
85pub const SYMBOLS: &[TokenKind] = &[
86    TokenKind::LParen,
87    TokenKind::RParen,
88    TokenKind::LBrace,
89    TokenKind::RBrace,
90    TokenKind::LBracket,
91    TokenKind::RBracket,
92    TokenKind::Comma,
93    TokenKind::Colon,
94    TokenKind::Dot,
95    TokenKind::DotDot,
96    TokenKind::Arrow,
97    TokenKind::Dollar,
98    TokenKind::Plus,
99    TokenKind::Minus,
100    TokenKind::Star,
101    TokenKind::Slash,
102    TokenKind::Percent,
103    TokenKind::Bang,
104    TokenKind::Eq,
105    TokenKind::EqEq,
106    TokenKind::BangEq,
107    TokenKind::Lt,
108    TokenKind::LtEq,
109    TokenKind::Gt,
110    TokenKind::GtEq,
111    TokenKind::AndAnd,
112    TokenKind::OrOr,
113    TokenKind::PlusEq,
114    TokenKind::MinusEq,
115    TokenKind::StarEq,
116    TokenKind::SlashEq,
117];
118
119impl TokenKind {
120    pub(crate) fn keyword(text: &str) -> Option<Self> {
121        KEYWORDS
122            .iter()
123            .copied()
124            .find(|kind| kind.text() == Some(text))
125    }
126
127    /// How a keyword, punctuation or operator token is spelled, or `None` for tokens
128    /// whose text varies, such as names and numbers.
129    #[must_use]
130    pub const fn text(self) -> Option<&'static str> {
131        match self.spelling() {
132            Spelling::Fixed(text) => Some(text),
133            Spelling::Varies(_) => None,
134        }
135    }
136
137    /// How the token reads in an error message.
138    #[must_use]
139    pub fn describe(self) -> Cow<'static, str> {
140        match self.spelling() {
141            Spelling::Fixed(text) => Cow::Owned(format!("`{text}`")),
142            Spelling::Varies(description) => Cow::Borrowed(description),
143        }
144    }
145
146    const fn spelling(self) -> Spelling {
147        use Spelling::{Fixed, Varies};
148        match self {
149            Self::Ident => Varies("a name"),
150            Self::Int | Self::Float => Varies("a number"),
151            Self::StringStart => Varies("a string"),
152            Self::StringText | Self::StringEnd => Varies("string text"),
153            Self::InterpolationStart => Varies("`{` in a string"),
154            Self::InterpolationEnd => Varies("`}` in a string"),
155            Self::Newline => Varies("end of line"),
156            Self::Eof => Varies("end of file"),
157            Self::State => Fixed("state"),
158            Self::Let => Fixed("let"),
159            Self::Fn => Fixed("fn"),
160            Self::View => Fixed("view"),
161            Self::Struct => Fixed("struct"),
162            Self::If => Fixed("if"),
163            Self::Else => Fixed("else"),
164            Self::For => Fixed("for"),
165            Self::In => Fixed("in"),
166            Self::Return => Fixed("return"),
167            Self::True => Fixed("true"),
168            Self::False => Fixed("false"),
169            Self::LParen => Fixed("("),
170            Self::RParen => Fixed(")"),
171            Self::LBrace => Fixed("{"),
172            Self::RBrace => Fixed("}"),
173            Self::LBracket => Fixed("["),
174            Self::RBracket => Fixed("]"),
175            Self::Comma => Fixed(","),
176            Self::Colon => Fixed(":"),
177            Self::Dot => Fixed("."),
178            Self::DotDot => Fixed(".."),
179            Self::Arrow => Fixed("->"),
180            Self::Dollar => Fixed("$"),
181            Self::Plus => Fixed("+"),
182            Self::Minus => Fixed("-"),
183            Self::Star => Fixed("*"),
184            Self::Slash => Fixed("/"),
185            Self::Percent => Fixed("%"),
186            Self::Bang => Fixed("!"),
187            Self::Eq => Fixed("="),
188            Self::EqEq => Fixed("=="),
189            Self::BangEq => Fixed("!="),
190            Self::Lt => Fixed("<"),
191            Self::LtEq => Fixed("<="),
192            Self::Gt => Fixed(">"),
193            Self::GtEq => Fixed(">="),
194            Self::AndAnd => Fixed("&&"),
195            Self::OrOr => Fixed("||"),
196            Self::PlusEq => Fixed("+="),
197            Self::MinusEq => Fixed("-="),
198            Self::StarEq => Fixed("*="),
199            Self::SlashEq => Fixed("/="),
200        }
201    }
202}
203
204/// A token's text, or for tokens whose text varies, how an error message names them.
205enum Spelling {
206    Fixed(&'static str),
207    Varies(&'static str),
208}
209
210#[derive(Clone, Copy, Debug, PartialEq, Eq)]
211pub struct Token {
212    pub kind: TokenKind,
213    pub span: Span,
214}