css_lexer/
kind.rs

1use core::fmt;
2
3use crate::KindSet;
4
5/// Kind represents the token "Type", categorised mostly by the token types within the CSS Syntax spec.
6///
7/// Maintaining parity with the spec makes it easier to reason about logica round the parser, despite it being possible to
8/// group a bunch of these tokens into a single "delimiter" token.
9///
10/// Importantly, `Kind` is represented as `u8` and must only use the 5 low bits, because the upper 3 bits get used to
11/// house details about each kind, that a token would be interested in learning about.
12#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub enum Kind {
14	// Trivias (mask as 0b0_00XX)
15	/// Represents the [<eof-token>][1] defined in CSS. While CSS stipulates that this token is never produced by a
16	/// tokenizer, this [Lexer][crate::Lexer] _will_ produce [<eof-token>s][1] if the underlying source has been
17	/// fully consumed.
18	///
19	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-eof-token
20	Eof = 0b0000,
21
22	/// Represents the [<whitespace-token>][1] defined in CSS.
23	///
24	/// ```md
25	/// <newline>
26	///  │├──╮─ "\n" ───╭──┤│
27	///      ├─ "\r\n" ─┤
28	///      ├─ "\r" ───┤
29	///      ╰─ "\f" ───╯
30	///
31	/// <whitespace>
32	///  │├──╮─ " " ───────╭──┤│
33	///      ├─ "\t" ──────┤
34	///      ╰─ <newline> ─╯
35	///
36	/// <whitespace-token>
37	///  │├─╭─ <whitespace> ─╮─┤│
38	///     ╰────────────────╯
39	/// ```
40	///
41	/// While CSS stipulates that this token represents collapsed whitespace, it is possible for [Lexer][crate::Lexer]
42	/// to produce multiple consecutive [Kind::Whitespace] tokens if the
43	/// [Feature::SeparateWhitespace][crate::Feature::SeparateWhitespace] runtime feature is enabled. In this case,
44	/// `<whitespace-token>` becomes:
45	///
46	/// ```md
47	/// <whitespace-token>
48	///  │├──╮─╭─ " " ───────╮─╭──┤│
49	///      │ ╰─────────────╯ │
50	///      ├─╭─ "\t" ──────╮─┤
51	///      │ ╰─────────────╯ │
52	///      ╰─╭─ <newline> ─╮─╯
53	///        ╰─────────────╯
54	/// ```
55	///
56	/// [1]: https://drafts.csswg.org/css-syntax/#whitespace-token-diagram
57	#[default]
58	Whitespace = 0b0001,
59
60	/// Represents the [&lt;comment>][1] defined in CSS. While CSS stipulates comment tokens are not produced during
61	/// tokenization, they are for this [Lexer][crate::Lexer] as they're needed in order to preserve them.
62	///
63	/// ```md
64	/// <comment>
65	///            ╭──────────────────────────────────────────╮
66	///  │├─ "/*" ─╯-╭─ (anything but "*" followed by "/") ─╮─╰─ "*/" ─┤│
67	///              ╰──────────────────────────────────────╯
68	/// ```
69	///
70	/// It is possible for [Lexer][crate::Lexer] to produce [Kind::Whitespace] tokens that begin `//` if the
71	/// [Feature::SingleLineComments][crate::Feature::SingleLineComments] runtime feature is enabled. In this mode,
72	/// `<comment>` becomes:
73	///
74	/// ```md
75	/// <comment>
76	///               ╭──────────────────────────────────────────╮
77	///  │├──╮─ "/*" ─╯-╭─ (anything but "*" followed by "/") ─╮─╰─ "*/" ─╭─┤│
78	///      │          ╰──────────────────────────────────────╯          │
79	///      │              ╭───────────────────────────╮                 │
80	///      ╰─ "//" ───────╯-╭─ (anything but "\n") ─╮─╰─ "\n" ──────────╯
81	///                       ╰───────────────────────╯
82	/// ```
83	///
84	/// [1]: https://drafts.csswg.org/css-syntax/#comment-diagram
85	Comment = 0b0010,
86
87	/// Represents both the [&lt;cdc-token>][1] and [&lt;cdo-token>][2]s defined in CSS. While CSS separates these tokens,
88	/// they're only useful representations at the top-level stylesheet, anywhere else they represent a parse error, and
89	/// it's a little pointless to define two tokens types for what amounts to a parse error.
90	///
91	/// ```md
92	/// <cdo-token>
93	///  │├─ "<!--" ─┤│
94	///
95	/// <cdc-token>
96	///  │├─ "-->" ─┤│
97	///
98	/// <cdc-or-cdo-token> (Not part of the CSS specification)
99	///  │├──╮─ <cdo-token> ─╭──┤│
100	///      ╰─ <crc-token> ─╯
101	/// ```
102	///
103	/// [1]: https://drafts.csswg.org/css-syntax/#CDC-token-diagram
104	/// [2]: https://drafts.csswg.org/css-syntax/#CDO-token-diagram
105	CdcOrCdo = 0b0011,
106
107	// Numerics (mask as 0b0_010X)
108	/// Represents the [&lt;number-token>][1].
109	///
110	/// ```md
111	///
112	/// <number-token>
113	///     ╭─ "+" ─╮
114	///  │├─├───────┤───╭─ [digit] ─╮─ "." ─╭─ [digit] ─╮──╭───╮──────────────────────────────────╭──┤│
115	///     ╰─ "-" ─╯ │ ╰───────────╯       ╰───────────╯  │   │         ╭─ "+" ─╮                │
116	///               ├───────── ╭─ [digit] ─╮─────────────┤   ├─ "e" ─╭─├───────┤──╭─ [digit] ─╮─╯
117	///               │          ╰───────────╯             │   ╰─ "E" ─╯ ╰─ "-" ─╯  ╰───────────╯
118	///               ╰──── "." ─╭─ [digit] ─╮─────────────╯
119	///                          ╰───────────╯
120	/// ```
121	///
122	/// [1]: https://drafts.csswg.org/css-syntax/#number-token-diagram
123	Number = 0b0100,
124
125	/// Represents the [&lt;dimension-token>][1].
126	///
127	/// Here we deviate from the spec slightly, which has both [&lt;dimension-token>][1] and [&lt;percentage-token>][2].
128	/// `<percentage-token>` represents a dimension with a `%` symbol, but having this as a separate token results in more
129	/// work in the parser for little gain in the Lexer. So instead this lexer does not have a `<percentage-token>` and
130	/// instead folds the grammar for it inside of `<dimension-token>`.
131	///
132	/// ```md
133	///
134	/// <newline>
135	///  │├──╮─ "\n" ───╭──┤│
136	///      ├─ "\r\n" ─┤
137	///      ├─ "\r" ───┤
138	///      ╰─ "\f" ───╯
139	///
140	/// <whitespace>
141	///  │├──╮─ " " ───────╭──┤│
142	///      ├─ "\t" ──────┤
143	///      ╰─ <newline> ─╯
144	///
145	/// <hexdigit>
146	///  │├─ [ 0-9, A-F, a-f ] ─┤│
147	///
148	///
149	/// <escape>
150	///  │├─ "\" ─╮───── [not <newline> or <hexdigit>] ───╭─┤│
151	///           ╰─╭── <hexdigit> ─╮──╮────────────────╭─╯
152	///             ╰─ (1-6 times) ─╯  ╰─ <whitespace> ─╯
153	///
154	/// <ident-token>
155	///     ╭───────────────── "--" ─────────────────────╮  ╭───────────────────────────────────────────╮
156	///  │├─╯─╮───────╭─╮─ [a-z, A-Z, "_", non-ASCII] ─╭─╰──╯─╭─╮─ [a-z, A-Z, 0-9, "_", non-ASCII] ─╭─╮─╰──┤│
157	///       ╰─ "-" ─╯ ╰──────── <escape> ────────────╯      │ ╰──────────── <escape> ─────────────╯ │
158	///                                                       ╰───────────────────────────────────────╯
159	///
160	/// <number-token>
161	///     ╭─ "+" ─╮
162	///  │├─├───────┤─╮─╭─ [digit] ─╮─ "." ─╭─ [digit] ─╮──╭───╮──────────────────────────────────╭──┤│
163	///     ╰─ "-" ─╯ │ ╰───────────╯       ╰───────────╯  │   │         ╭─ "+" ─╮                │
164	///               ├───────── ╭─ [digit] ─╮─────────────┤   ├─ "e" ─╭─├───────┤──╭─ [digit] ─╮─╯
165	///               │          ╰───────────╯             │   ╰─ "E" ─╯ ╰─ "-" ─╯  ╰───────────╯
166	///               ╰──── "." ─╭─ [digit] ─╮─────────────╯
167	///                          ╰───────────╯
168	///
169	/// <dimension-token>
170	///  │├─ <number-token> ─ <ident-token> ─┤│
171	///
172	/// ```
173	///
174	/// ```md
175	///
176	/// <dimension-token> // Refined for this lexer, not true to the standard.
177	///  │├─ <number-token> ─╮─ <ident-token> ─╭──┤│
178	///                      ╰────── "%" ──────╯
179	/// ```
180	///
181	/// [1]: https://drafts.csswg.org/css-syntax/#dimension-token-diagram
182	/// [2]: https://drafts.csswg.org/css-syntax/#percentage-token-diagram
183	Dimension = 0b0101,
184
185	// Errors (mask as 0b0_011X)
186	/// Represents the [&lt;bad-string-token>][1]. This token is a failure to fully lex the [&lt;string-token>][2].
187	///
188	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-bad-string-token
189	/// [2]: https://drafts.csswg.org/css-syntax/#typedef-string-token
190	BadString = 0b0110,
191
192	/// Represents the [&lt;bad-url-token>][1]. This token is a failure to fully lex the [&lt;url-token>][2].
193	///
194	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-bad-url-token
195	/// [2]: https://drafts.csswg.org/css-syntax/#typedef-url-token
196	BadUrl = 0b0111,
197
198	// Variable length Ident-like Tokens (mask: 0b0_1XXX)
199	/// Represents the [&lt;ident-token>][1].
200	///
201	/// ```md
202	///
203	/// <newline>
204	///  │├──╮─ "\n" ───╭──┤│
205	///      ├─ "\r\n" ─┤
206	///      ├─ "\r" ───┤
207	///      ╰─ "\f" ───╯
208	///
209	/// <whitespace>
210	///  │├──╮─ " " ─────╭──┤│
211	///      ├─ "\t" ────┤
212	///      ╰─ newline ─╯
213	///
214	/// <hexdigit>
215	///  │├─ [ 0-9, A-F, a-f ] ─┤│
216	///
217	///
218	/// <escape>
219	///  │├─ "\" ─╮───── [not <newline> or <hexdigit>] ───╭─┤│
220	///           ╰─╭── <hexdigit> ─╮──╮────────────────╭─╯
221	///             ╰─ (1-6 times) ─╯  ╰─ <whitespace> ─╯
222	///
223	/// <ident-token>
224	///     ╭───────────────── "--" ─────────────────────╮  ╭───────────────────────────────────────────╮
225	///  │├─╯─╮───────╭─╮─ [a-z, A-Z, "_", non-ASCII] ─╭─╰──╯─╭─╮─ [a-z, A-Z, 0-9, "_", non-ASCII] ─╭─╮─╰──┤│
226	///       ╰─ "-" ─╯ ╰──────── <escape> ────────────╯      │ ╰──────────── <escape> ─────────────╯ │
227	///                                                       ╰───────────────────────────────────────╯
228	///
229	/// ```
230	///
231	/// [1]: https://drafts.csswg.org/css-syntax/#ident-token-diagram
232	Ident = 0b1000,
233
234	/// Represents the [&lt;function-token>][1].
235	///
236	/// ```md
237	///
238	/// <newline>
239	///  │├──╮─ "\n" ───╭──┤│
240	///      ├─ "\r\n" ─┤
241	///      ├─ "\r" ───┤
242	///      ╰─ "\f" ───╯
243	///
244	/// <whitespace>
245	///  │├──╮─ " " ───────╭──┤│
246	///      ├─ "\t" ──────┤
247	///      ╰─ <newline> ─╯
248	///
249	/// <hexdigit>
250	///  │├─ [ 0-9, A-F, a-f ] ─┤│
251	///
252	///
253	/// <escape>
254	///  │├─ "\" ─╮───── [not <newline> or <hexdigit>] ───╭─┤│
255	///           ╰─╭── <hexdigit> ─╮──╮────────────────╭─╯
256	///             ╰─ (1-6 times) ─╯  ╰─ <whitespace> ─╯
257	///
258	/// <ident-token>
259	///     ╭───────────────── "--" ─────────────────────╮  ╭───────────────────────────────────────────╮
260	///  │├─╯─╮───────╭─╮─ [a-z, A-Z, "_", non-ASCII] ─╭─╰──╯─╭─╮─ [a-z, A-Z, 0-9, "_", non-ASCII] ─╭─╮─╰──┤│
261	///       ╰─ "-" ─╯ ╰──────── <escape> ────────────╯      │ ╰──────────── <escape> ─────────────╯ │
262	///                                                       ╰───────────────────────────────────────╯
263	///
264	/// <function-token>
265	///  │├─ <ident-token> ─ "(" ─┤│
266	///
267	/// ```
268	///
269	/// [1]: https://drafts.csswg.org/css-syntax/#function-token-diagram
270	Function = 0b1001,
271
272	/// Represents the [&lt;at-keyword-token>][1].
273	///
274	/// ```md
275	///
276	/// <newline>
277	///  │├──╮─ "\n" ───╭──┤│
278	///      ├─ "\r\n" ─┤
279	///      ├─ "\r" ───┤
280	///      ╰─ "\f" ───╯
281	///
282	/// <whitespace>
283	///  │├──╮─ " " ───────╭──┤│
284	///      ├─ "\t" ──────┤
285	///      ╰─ <newline> ─╯
286	///
287	/// <hexdigit>
288	///  │├─ [ 0-9, A-F, a-f ] ─┤│
289	///
290	///
291	/// <escape>
292	///  │├─ "\" ─╮───── [not <newline> or <hexdigit>] ───╭─┤│
293	///           ╰─╭── <hexdigit> ─╮──╮────────────────╭─╯
294	///             ╰─ (1-6 times) ─╯  ╰─ <whitespace> ─╯
295	///
296	/// <ident-token>
297	///     ╭───────────────── "--" ─────────────────────╮  ╭───────────────────────────────────────────╮
298	///  │├─╯─╮───────╭─╮─ [a-z, A-Z, "_", non-ASCII] ─╭─╰──╯─╭─╮─ [a-z, A-Z, 0-9, "_", non-ASCII] ─╭─╮─╰──┤│
299	///       ╰─ "-" ─╯ ╰──────── <escape> ────────────╯      │ ╰──────────── <escape> ─────────────╯ │
300	///                                                       ╰───────────────────────────────────────╯
301	///
302	/// <at-keyword-token>
303	///  │├─ "@" ─ <ident-token> ─┤│
304	///
305	/// ```
306	///
307	/// [1]: https://drafts.csswg.org/css-syntax/#hash-token-diagram
308	AtKeyword = 0b1010,
309
310	/// Represents the [&lt;hash-token>][1].
311	///
312	/// ```md
313	///
314	/// <newline>
315	///  │├──╮─ "\n" ───╭──┤│
316	///      ├─ "\r\n" ─┤
317	///      ├─ "\r" ───┤
318	///      ╰─ "\f" ───╯
319	///
320	/// <whitespace>
321	///  │├──╮─ " " ───────╭──┤│
322	///      ├─ "\t" ──────┤
323	///      ╰─ <newline> ─╯
324	///
325	/// <hexdigit>
326	///  │├─ [ 0-9, A-F, a-f ] ─┤│
327	///
328	///
329	/// <escape>
330	///  │├─ "\" ─╮───── [not <newline> or <hexdigit>] ───╭─┤│
331	///           ╰─╭── <hexdigit> ─╮──╮────────────────╭─╯
332	///             ╰─ (1-6 times) ─╯  ╰─ <whitespace> ─╯
333	///
334	/// <hash-token>
335	///  │├─ "#" ──╭─╮─ [a-z, A-Z, 0-9, "_", "-", non-ASCII] ─╭─╮─┤│
336	///            │ ╰─────────────── <escape> ───────────────╯ │
337	///            ╰────────────────────────────────────────────╯
338	///
339	/// ```
340	///
341	/// [1]: https://drafts.csswg.org/css-syntax/#at-keyword-token-diagram
342	Hash = 0b1011,
343
344	/// Represents the [&lt;string-token>][1].
345	///
346	/// ```md
347	///
348	/// <newline>
349	///  │├──╮─ "\n" ───╭──┤│
350	///      ├─ "\r\n" ─┤
351	///      ├─ "\r" ───┤
352	///      ╰─ "\f" ───╯
353	///
354	/// <escape>
355	///  │├─ "\" ─╮───── [not <newline> or <hexdigit>] ───╭─┤│
356	///           ╰─╭── <hexdigit> ─╮──╮────────────────╭─╯
357	///             ╰─ (1-6 times) ─╯  ╰─ <whitespace> ─╯
358	///
359	/// <string-token>
360	///             ╭───────────────────────────────────╮
361	///  │├─╮─ """ ─╯─╭─╮─ [not """, "\", newline] ─╭─╮─╰── """ ─╭─┤│
362	///     │         │ ├──────── <escape> ─────────┤ │          │
363	///     │         │ ╰───── "\" ─ <newline> ─────╯ │          │
364	///     │         ╰───────────────────────────────╯          │
365	///     │       ╭───────────────────────────────────╮        │
366	///     ╰─ "'" ─╯─╭─╮─ [not """, "\", newline] ─╭─╮─╰── "'" ─╯
367	///               │ ├──────── <escape> ─────────┤ │
368	///               │ ╰───── "\" ─ <newline> ─────╯ │
369	///               ╰───────────────────────────────╯
370	///
371	/// ```
372	///
373	/// [1]: https://drafts.csswg.org/css-syntax/#string-token-diagram
374	String = 0b1100,
375
376	/// Represents the [&lt;url-token>][1].
377	///
378	/// ```md
379	///
380	/// <newline>
381	///  │├──╮─ "\n" ───╭──┤│
382	///      ├─ "\r\n" ─┤
383	///      ├─ "\r" ───┤
384	///      ╰─ "\f" ───╯
385	///
386	/// <whitespace>
387	///  │├──╮─ " " ───────╭──┤│
388	///      ├─ "\t" ──────┤
389	///      ╰─ <newline> ─╯
390	///
391	/// <whitespace-token>
392	///  │├─╭─ <whitespace> ─╮─┤│
393	///     ╰────────────────╯
394	///
395	/// <ws*>
396	///     ╭──────────────────────────╮
397	///  │├─╯─╭─ <whitespace-token> ─╮─╰─┤│
398	///       ╰──────────────────────╯
399	///
400	/// <hexdigit>
401	///  │├─ [ 0-9, A-F, a-f ] ─┤│
402	///
403	///
404	/// <escape>
405	///  │├─ "\" ─╮───── [not <newline> or <hexdigit>] ───╭─┤│
406	///           ╰─╭── <hexdigit> ─╮──╮────────────────╭─╯
407	///             ╰─ (1-6 times) ─╯  ╰─ <whitespace> ─╯
408	///
409	/// <ident-token>
410	///     ╭───────────────── "--" ─────────────────────╮  ╭───────────────────────────────────────────╮
411	///  │├─╯─╮───────╭─╮─ [a-z, A-Z, "_", non-ASCII] ─╭─╰──╯─╭─╮─ [a-z, A-Z, 0-9, "_", non-ASCII] ─╭─╮─╰──┤│
412	///       ╰─ "-" ─╯ ╰──────── <escape> ────────────╯      │ ╰──────────── <escape> ─────────────╯ │
413	///                                                       ╰───────────────────────────────────────╯
414	///
415	/// <url-token>
416	///                                         ╭───────────────────────────────────────────────────────────────────╮
417	///  │├─ <ident-token "url"> ─ "(" ─ <ws*> ─╯─╭─╮─ [not """ "'" "(" ")" "\" <whitespace> or non-printable] ─╭─╮─╰─ <ws*> ─ ")" ─┤│
418	///                                           │ ╰──────────────────────── <escape> ─────────────────────────╯ │
419	///                                           ╰───────────────────────────────────────────────────────────────╯
420	///
421	/// ```
422	///
423	/// [1]: https://drafts.csswg.org/css-syntax/#url-token-diagram
424	Url = 0b1101,
425
426	// Single character Tokens (mask 0b1_XXXX)
427	/// Represents the [&lt;delim-token>][1]. The `<delim-token>` has a value composed of a single code point.
428	///
429	/// ```md
430	/// <delim-token>
431	///  │├─ [codepoint] ─┤│
432	/// ```
433	///
434	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-delim-token
435	Delim = 0b1_0000,
436
437	/// Represents the [&lt;colon-token>][1].
438	///
439	/// ```md
440	/// <colon-token>
441	///  │├─ ":" ─┤│
442	/// ```
443	///
444	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-colon-token
445	Colon = 0b1_0001,
446
447	/// Represents the [&lt;semicolon-token>][1].
448	///
449	/// ```md
450	/// <semicolon-token>
451	///  │├─ ";" ─┤│
452	/// ```
453	///
454	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-semicolon-token
455	Semicolon = 0b1_0010,
456
457	/// Represents the [&lt;comma-token>][1].
458	///
459	/// ```md
460	/// <comma-token>
461	///  │├─ "," ─┤│
462	/// ```
463	///
464	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-comma-token
465	Comma = 0b1_0011,
466
467	/// Represents the [&lt;\[-token>][1].
468	///
469	/// ```md
470	/// <[-token>
471	///  │├─ "[" ─┤│
472	/// ```
473	///
474	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-open-square
475	LeftSquare = 0b1_0100,
476
477	/// Represents the [&lt;\]-token>][1].
478	///
479	/// ```md
480	/// <]-token>
481	///  │├─ "]" ─┤│
482	/// ```
483	///
484	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-close-square
485	RightSquare = 0b1_0101,
486
487	/// Represents the [&lt;(-token>][1].
488	///
489	/// ```md
490	/// <(-token>
491	///  │├─ "(" ─┤│
492	/// ```
493	///
494	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-open-paren
495	LeftParen = 0b1_0110,
496
497	/// Represents the [&lt;)-token>][1].
498	///
499	/// ```md
500	/// <)-token>
501	///  │├─ ")" ─┤│
502	/// ```
503	///
504	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-close-paren
505	RightParen = 0b1_0111,
506
507	/// Represents the [&lt;{-token>][1].
508	///
509	/// ```md
510	/// <{-token>
511	///  │├─ "{" ─┤│
512	/// ```
513	///
514	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-open-curly
515	LeftCurly = 0b1_1000,
516
517	/// Represents the [&lt;}-token>][1].
518	///
519	/// ```md
520	/// <}-token>
521	///  │├─ "}" ─┤│
522	/// ```
523	///
524	/// [1]: https://drafts.csswg.org/css-syntax/#typedef-close-curly
525	RightCurly = 0b1_1001,
526}
527
528impl Kind {
529	pub(crate) const fn from_bits(bits: u8) -> Self {
530		match bits {
531			0b0001 => Self::Whitespace,
532			0b0010 => Self::Comment,
533			0b0011 => Self::CdcOrCdo,
534			0b0100 => Self::Number,
535			0b0101 => Self::Dimension,
536			0b0110 => Self::BadString,
537			0b0111 => Self::BadUrl,
538			0b1000 => Self::Ident,
539			0b1001 => Self::Function,
540			0b1010 => Self::AtKeyword,
541			0b1011 => Self::Hash,
542			0b1100 => Self::String,
543			0b1101 => Self::Url,
544			0b1_0000 => Self::Delim,
545			0b1_0001 => Self::Colon,
546			0b1_0010 => Self::Semicolon,
547			0b1_0011 => Self::Comma,
548			0b1_0100 => Self::LeftSquare,
549			0b1_0101 => Self::RightSquare,
550			0b1_0110 => Self::LeftParen,
551			0b1_0111 => Self::RightParen,
552			0b1_1000 => Self::LeftCurly,
553			0b1_1001 => Self::RightCurly,
554			_ => Self::Eof,
555		}
556	}
557
558	#[doc(hidden)]
559	pub const fn as_str(&self) -> &str {
560		match *self {
561			Kind::Eof => "Eof",
562			Kind::Whitespace => "Whitespace",
563			Kind::Comment => "Comment",
564			Kind::CdcOrCdo => "CdcOrCdo",
565			Kind::Number => "Number",
566			Kind::Dimension => "Dimension",
567			Kind::BadString => "BadString",
568			Kind::BadUrl => "BadUrl",
569			Kind::Ident => "Ident",
570			Kind::Function => "Function",
571			Kind::AtKeyword => "AtKeyword",
572			Kind::Hash => "Hash",
573			Kind::String => "String",
574			Kind::Url => "Url",
575			Kind::Delim => "Delim",
576			Kind::Colon => "Colon",
577			Kind::Semicolon => "Semicolon",
578			Kind::Comma => "Comma",
579			Kind::LeftSquare => "LeftSquare",
580			Kind::RightSquare => "RightSquare",
581			Kind::LeftParen => "LeftParen",
582			Kind::RightParen => "RightParen",
583			Kind::LeftCurly => "LeftCurly",
584			Kind::RightCurly => "RightCurly",
585		}
586	}
587}
588
589impl fmt::Debug for Kind {
590	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591		write!(f, "Kind::{}", self.as_str())
592	}
593}
594
595impl fmt::Display for Kind {
596	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
597		write!(f, "Kind::{}", self.as_str())
598	}
599}
600
601impl PartialEq<KindSet> for Kind {
602	fn eq(&self, other: &KindSet) -> bool {
603		other.contains_bits(*self as u8)
604	}
605}
606
607#[test]
608fn test_from_bits() {
609	assert_eq!(Kind::from_bits(Kind::Eof as u8), Kind::Eof);
610	assert_eq!(Kind::from_bits(Kind::Whitespace as u8), Kind::Whitespace);
611	assert_eq!(Kind::from_bits(Kind::Comment as u8), Kind::Comment);
612	assert_eq!(Kind::from_bits(Kind::CdcOrCdo as u8), Kind::CdcOrCdo);
613	assert_eq!(Kind::from_bits(Kind::Number as u8), Kind::Number);
614	assert_eq!(Kind::from_bits(Kind::Dimension as u8), Kind::Dimension);
615	assert_eq!(Kind::from_bits(Kind::BadString as u8), Kind::BadString);
616	assert_eq!(Kind::from_bits(Kind::BadUrl as u8), Kind::BadUrl);
617	assert_eq!(Kind::from_bits(Kind::Ident as u8), Kind::Ident);
618	assert_eq!(Kind::from_bits(Kind::Function as u8), Kind::Function);
619	assert_eq!(Kind::from_bits(Kind::AtKeyword as u8), Kind::AtKeyword);
620	assert_eq!(Kind::from_bits(Kind::Hash as u8), Kind::Hash);
621	assert_eq!(Kind::from_bits(Kind::String as u8), Kind::String);
622	assert_eq!(Kind::from_bits(Kind::Url as u8), Kind::Url);
623	assert_eq!(Kind::from_bits(Kind::Delim as u8), Kind::Delim);
624	assert_eq!(Kind::from_bits(Kind::Colon as u8), Kind::Colon);
625	assert_eq!(Kind::from_bits(Kind::Semicolon as u8), Kind::Semicolon);
626	assert_eq!(Kind::from_bits(Kind::Comma as u8), Kind::Comma);
627	assert_eq!(Kind::from_bits(Kind::LeftSquare as u8), Kind::LeftSquare);
628	assert_eq!(Kind::from_bits(Kind::RightSquare as u8), Kind::RightSquare);
629	assert_eq!(Kind::from_bits(Kind::LeftParen as u8), Kind::LeftParen);
630	assert_eq!(Kind::from_bits(Kind::RightParen as u8), Kind::RightParen);
631	assert_eq!(Kind::from_bits(Kind::LeftCurly as u8), Kind::LeftCurly);
632	assert_eq!(Kind::from_bits(Kind::RightCurly as u8), Kind::RightCurly);
633}
634
635#[test]
636fn size_test() {
637	assert_eq!(::std::mem::size_of::<Kind>(), 1);
638}