Skip to main content

rantlr_core/
token.rs

1use serde::Serialize;
2
3use crate::span::Span;
4
5/// Reserved words in the `.gr` surface language.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum Keyword {
8    Grammar,
9    Rule,
10    Token,
11    Match,
12    Repeat,
13    Optional,
14    Example,
15    Input,
16    Expect,
17    Skip,
18    Import,
19    Fragment,
20}
21
22impl Keyword {
23    pub fn as_str(self) -> &'static str {
24        match self {
25            Self::Grammar => "grammar",
26            Self::Rule => "rule",
27            Self::Token => "token",
28            Self::Match => "match",
29            Self::Repeat => "repeat",
30            Self::Optional => "optional",
31            Self::Example => "example",
32            Self::Input => "input",
33            Self::Expect => "expect",
34            Self::Skip => "skip",
35            Self::Import => "import",
36            Self::Fragment => "fragment",
37        }
38    }
39
40    pub fn from_ident(ident: &str) -> Option<Self> {
41        Some(match ident {
42            "grammar" => Self::Grammar,
43            "rule" => Self::Rule,
44            "token" => Self::Token,
45            "match" => Self::Match,
46            "repeat" => Self::Repeat,
47            "optional" => Self::Optional,
48            "example" => Self::Example,
49            "input" => Self::Input,
50            "expect" => Self::Expect,
51            "skip" => Self::Skip,
52            "import" => Self::Import,
53            "fragment" => Self::Fragment,
54            _ => return None,
55        })
56    }
57}
58
59/// Built-in lexical types available in `token Name = <Builtin>;`.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
61#[serde(rename_all = "PascalCase")]
62pub enum BuiltinType {
63    Email,
64    Url,
65    DateTime,
66    QuotedString,
67    Number,
68    /// `[A-Za-z_][A-Za-z0-9_]*` — names, keywords, and path segments in DSLs.
69    Identifier,
70}
71
72impl BuiltinType {
73    pub fn as_str(self) -> &'static str {
74        match self {
75            Self::Email => "Email",
76            Self::Url => "Url",
77            Self::DateTime => "DateTime",
78            Self::QuotedString => "QuotedString",
79            Self::Number => "Number",
80            Self::Identifier => "Identifier",
81        }
82    }
83
84    pub fn from_ident(ident: &str) -> Option<Self> {
85        Some(match ident {
86            "Email" => Self::Email,
87            "Url" => Self::Url,
88            "DateTime" => Self::DateTime,
89            "QuotedString" => Self::QuotedString,
90            "Number" => Self::Number,
91            "Identifier" => Self::Identifier,
92            _ => return None,
93        })
94    }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
98pub enum TokenKind {
99    /// End of input sentinel.
100    Eof,
101
102    Keyword(Keyword),
103    Builtin(BuiltinType),
104
105    /// Rule / token / grammar names (`expr`, `JsonMini`, …).
106    Ident(String),
107
108    /// Double-quoted string with escapes (`"import"`, `"{"`).
109    String(String),
110    /// Backtick raw string for example inputs (`` `{"a":1}` ``).
111    RawString(String),
112
113    /// Integer literal (e.g. range bounds in `repeat(0..)`).
114    Integer(u64),
115
116    // Punctuation / operators
117    LBrace,   // {
118    RBrace,   // }
119    LParen,   // (
120    RParen,   // )
121    LBracket, // [
122    RBracket, // ]
123    Pipe,     // |
124    Comma,    // ,
125    Semi,     // ;
126    Colon,    // :
127    Eq,       // =
128    DotDot,   // ..
129    Arrow,    // ->
130}
131
132impl TokenKind {
133    pub fn is_eof(&self) -> bool {
134        matches!(self, Self::Eof)
135    }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct Token {
140    pub kind: TokenKind,
141    pub span: Span,
142}
143
144impl Token {
145    pub fn new(kind: TokenKind, span: Span) -> Self {
146        Self { kind, span }
147    }
148}