1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! The [`TokenKind`] trait: the language-agnostic classification a parser reads.
use Symbol;
/// The classification a token kind exposes so that generic, language-agnostic
/// code can reason about a token stream without knowing the concrete kind.
///
/// A language defines its own kind type — an `enum` of keywords, punctuation,
/// literals, an end-of-input marker, and so on — and implements `TokenKind` for
/// it. token-lang stays language-agnostic by owning only this seam: a parser's
/// token cursor, a trivia filter, or a pretty-printer written against `TokenKind`
/// works for *any* language's kind, while [`Token<K>`](crate::Token) carries the
/// span.
///
/// Every method has a default, so a kind that has no trivia, no end marker, and
/// carries no interned text satisfies the trait with an empty `impl` block.
/// Override only the queries that apply to the language.
///
/// # Why a trait, not a fixed enum
///
/// The set of keywords and operators differs in every language, so token-lang
/// cannot enumerate them once and freeze them. What *is* universal is the handful
/// of questions a parser asks of any token regardless of language: should I skip
/// this as trivia, have I reached the end, and what interned text (if any) does it
/// carry. Those three questions are the whole trait.
///
/// # Examples
///
/// A small kind for a calculator language. Whitespace is trivia; identifiers carry
/// an interned [`Symbol`]; the rest are plain markers.
///
/// ```
/// use intern_lang::Interner;
/// use token_lang::{Symbol, TokenKind};
///
/// #[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// enum Kind {
/// Ident(Symbol),
/// Plus,
/// Whitespace,
/// Eof,
/// }
///
/// impl TokenKind for Kind {
/// fn is_trivia(&self) -> bool {
/// matches!(self, Kind::Whitespace)
/// }
/// fn is_eof(&self) -> bool {
/// matches!(self, Kind::Eof)
/// }
/// fn symbol(&self) -> Option<Symbol> {
/// match self {
/// Kind::Ident(sym) => Some(*sym),
/// _ => None,
/// }
/// }
/// }
///
/// let mut interner = Interner::new();
/// let total = Kind::Ident(interner.intern("total"));
///
/// assert!(Kind::Whitespace.is_trivia());
/// assert!(Kind::Eof.is_eof());
/// assert_eq!(total.symbol().and_then(|s| interner.resolve(s)), Some("total"));
/// assert_eq!(Kind::Plus.symbol(), None);
/// ```
///
/// A kind with no trivia or interned text needs no method bodies at all:
///
/// ```
/// use token_lang::TokenKind;
///
/// #[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// enum Op {
/// Add,
/// Sub,
/// }
///
/// impl TokenKind for Op {}
///
/// assert!(!Op::Add.is_trivia());
/// assert!(!Op::Add.is_eof());
/// assert_eq!(Op::Add.symbol(), None);
/// ```