Skip to main content

leo_parser_rowan/
syntax_kind.rs

1// Copyright (C) 2019-2026 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17//! Syntax kind definitions for the rowan-based Leo parser.
18//!
19//! This module defines a flat `SyntaxKind` enum containing all token and node
20//! types used in the Leo syntax tree. The enum is `#[repr(u16)]` for
21//! compatibility with rowan's internal representation.
22
23// Re-export the variants to make the `SyntaxKind` helper method implementations
24// a bit less noisey.
25use SyntaxKind::*;
26
27/// All syntax kinds for Leo tokens and nodes.
28///
29/// This enum is intentionally flat (not nested) to satisfy rowan's requirement
30/// for a `#[repr(u16)]` type. Categories are indicated by comments and helper
31/// methods like `is_trivia()` and `is_keyword()`.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33#[repr(u16)]
34#[allow(non_camel_case_types)]
35pub enum SyntaxKind {
36    // ==========================================================================
37    // Special
38    // ==========================================================================
39    /// Error node for wrapping parse errors and invalid tokens.
40    ERROR = 0,
41    /// End of file marker.
42    EOF,
43
44    // ==========================================================================
45    // Trivia (whitespace and comments)
46    // ==========================================================================
47    /// Horizontal whitespace: spaces, tabs, form feeds.
48    WHITESPACE,
49    /// Line breaks: \n or \r\n.
50    LINEBREAK,
51    /// Line comment: // ...
52    COMMENT_LINE,
53    /// Block comment: /* ... */
54    COMMENT_BLOCK,
55
56    // ==========================================================================
57    // Literals
58    // ==========================================================================
59    /// Integer literal: 123, 0xFF, 0b101, 0o77
60    INTEGER,
61    /// String literal: "..."
62    STRING,
63    /// Address literal: aleo1...
64    ADDRESS_LIT,
65
66    // ==========================================================================
67    // Identifiers
68    // ==========================================================================
69    /// Identifier: foo, Bar, _baz
70    /// Note: Complex identifiers (paths, program IDs, locators) are deferred
71    /// to Phase 2. The lexer produces simple IDENT tokens; the parser handles
72    /// disambiguation of foo::bar, foo.aleo, foo.aleo/bar patterns.
73    IDENT,
74
75    // ==========================================================================
76    // Keywords - Literals
77    // ==========================================================================
78    /// `true`
79    KW_TRUE,
80    /// `false`
81    KW_FALSE,
82    /// `none`
83    KW_NONE,
84
85    // ==========================================================================
86    // Keywords - Types
87    // ==========================================================================
88    /// `address`
89    KW_ADDRESS,
90    /// `bool`
91    KW_BOOL,
92    /// `field`
93    KW_FIELD,
94    /// `group`
95    KW_GROUP,
96    /// `scalar`
97    KW_SCALAR,
98    /// `signature`
99    KW_SIGNATURE,
100    /// `string`
101    KW_STRING,
102    /// `record`
103    KW_RECORD,
104    /// `Future`
105    KW_FUTURE,
106    /// `i8`
107    KW_I8,
108    /// `i16`
109    KW_I16,
110    /// `i32`
111    KW_I32,
112    /// `i64`
113    KW_I64,
114    /// `i128`
115    KW_I128,
116    /// `u8`
117    KW_U8,
118    /// `u16`
119    KW_U16,
120    /// `u32`
121    KW_U32,
122    /// `u64`
123    KW_U64,
124    /// `u128`
125    KW_U128,
126
127    // ==========================================================================
128    // Keywords - Control Flow
129    // ==========================================================================
130    /// `if`
131    KW_IF,
132    /// `else`
133    KW_ELSE,
134    /// `for`
135    KW_FOR,
136    /// `in`
137    KW_IN,
138    /// `return`
139    KW_RETURN,
140
141    // ==========================================================================
142    // Keywords - Declarations
143    // ==========================================================================
144    /// `let`
145    KW_LET,
146    /// `const`
147    KW_CONST,
148    /// `constant`
149    KW_CONSTANT,
150    /// `function`
151    KW_FUNCTION,
152    /// `transition`
153    KW_TRANSITION,
154    /// `inline`
155    KW_INLINE,
156    /// `async`
157    KW_ASYNC,
158    /// `Fn`
159    KW_FN,
160    /// `struct`
161    KW_STRUCT,
162    /// `constructor`
163    KW_CONSTRUCTOR,
164
165    // ==========================================================================
166    // Keywords - Program Structure
167    // ==========================================================================
168    /// `program`
169    KW_PROGRAM,
170    /// `import`
171    KW_IMPORT,
172    /// `mapping`
173    KW_MAPPING,
174    /// `storage`
175    KW_STORAGE,
176    /// `network`
177    KW_NETWORK,
178    /// `aleo`
179    KW_ALEO,
180    /// `script`
181    KW_SCRIPT,
182    /// `block`
183    KW_BLOCK,
184
185    // ==========================================================================
186    // Keywords - Visibility & Assertions
187    // ==========================================================================
188    /// `public`
189    KW_PUBLIC,
190    /// `private`
191    KW_PRIVATE,
192    /// `as`
193    KW_AS,
194    /// `self`
195    KW_SELF,
196    /// `assert`
197    KW_ASSERT,
198    /// `assert_eq`
199    KW_ASSERT_EQ,
200    /// `assert_neq`
201    KW_ASSERT_NEQ,
202
203    // ==========================================================================
204    // Punctuation - Delimiters
205    // ==========================================================================
206    /// `(`
207    L_PAREN,
208    /// `)`
209    R_PAREN,
210    /// `[`
211    L_BRACKET,
212    /// `]`
213    R_BRACKET,
214    /// `{`
215    L_BRACE,
216    /// `}`
217    R_BRACE,
218
219    // ==========================================================================
220    // Punctuation - Separators
221    // ==========================================================================
222    /// `,`
223    COMMA,
224    /// `.`
225    DOT,
226    /// `..`
227    DOT_DOT,
228    /// `;`
229    SEMICOLON,
230    /// `:`
231    COLON,
232    /// `::`
233    COLON_COLON,
234    /// `?`
235    QUESTION,
236    /// `->`
237    ARROW,
238    /// `=>`
239    FAT_ARROW,
240    /// `_`
241    UNDERSCORE,
242    /// `@`
243    AT,
244
245    // ==========================================================================
246    // Operators - Assignment
247    // ==========================================================================
248    /// `=`
249    EQ,
250    /// `+=`
251    PLUS_EQ,
252    /// `-=`
253    MINUS_EQ,
254    /// `*=`
255    STAR_EQ,
256    /// `/=`
257    SLASH_EQ,
258    /// `%=`
259    PERCENT_EQ,
260    /// `**=`
261    STAR2_EQ,
262    /// `&&=`
263    AMP2_EQ,
264    /// `||=`
265    PIPE2_EQ,
266    /// `&=`
267    AMP_EQ,
268    /// `|=`
269    PIPE_EQ,
270    /// `^=`
271    CARET_EQ,
272    /// `<<=`
273    SHL_EQ,
274    /// `>>=`
275    SHR_EQ,
276
277    // ==========================================================================
278    // Operators - Arithmetic
279    // ==========================================================================
280    /// `+`
281    PLUS,
282    /// `-`
283    MINUS,
284    /// `*`
285    STAR,
286    /// `/`
287    SLASH,
288    /// `%`
289    PERCENT,
290    /// `**`
291    STAR2,
292
293    // ==========================================================================
294    // Operators - Comparison
295    // ==========================================================================
296    /// `==`
297    EQ2,
298    /// `!=`
299    BANG_EQ,
300    /// `<`
301    LT,
302    /// `<=`
303    LT_EQ,
304    /// `>`
305    GT,
306    /// `>=`
307    GT_EQ,
308
309    // ==========================================================================
310    // Operators - Logical
311    // ==========================================================================
312    /// `&&`
313    AMP2,
314    /// `||`
315    PIPE2,
316    /// `!`
317    BANG,
318
319    // ==========================================================================
320    // Operators - Bitwise
321    // ==========================================================================
322    /// `&`
323    AMP,
324    /// `|`
325    PIPE,
326    /// `^`
327    CARET,
328    /// `<<`
329    SHL,
330    /// `>>`
331    SHR,
332
333    // ==========================================================================
334    // Composite Nodes - Top Level
335    // ==========================================================================
336    /// Root node of the syntax tree.
337    ROOT,
338    /// Program declaration: `program foo.aleo { ... }`
339    PROGRAM_DECL,
340    /// Import statement: `import foo.aleo;`
341    IMPORT,
342    /// Main file contents.
343    MAIN_CONTENTS,
344    /// Module file contents.
345    MODULE_CONTENTS,
346
347    // ==========================================================================
348    // Composite Nodes - Declarations
349    // ==========================================================================
350    /// Function definition.
351    FUNCTION_DEF,
352    /// Constructor definition.
353    CONSTRUCTOR_DEF,
354    /// Struct definition.
355    STRUCT_DEF,
356    /// Record definition.
357    RECORD_DEF,
358    /// Struct member declaration.
359    STRUCT_MEMBER,
360    /// Mapping definition.
361    MAPPING_DEF,
362    /// Storage definition.
363    STORAGE_DEF,
364    /// Global constant definition.
365    GLOBAL_CONST,
366
367    // ==========================================================================
368    // Composite Nodes - Function Parts
369    // ==========================================================================
370    /// Annotation: `@foo`
371    ANNOTATION,
372    /// Parameter in a function signature.
373    PARAM,
374    /// Parameter list: `(a: u32, b: u32)`
375    PARAM_LIST,
376    /// Function output type.
377    RETURN_TYPE,
378    /// Const generic parameter.
379    CONST_PARAM,
380    /// Const generic parameter list.
381    CONST_PARAM_LIST,
382    /// Const generic argument list.
383    CONST_ARG_LIST,
384
385    // ==========================================================================
386    // Composite Nodes - Statements
387    // ==========================================================================
388    /// Let statement: `let x = ...;`
389    LET_STMT,
390    /// Const statement: `const x = ...;`
391    CONST_STMT,
392    /// Return statement: `return ...;`
393    RETURN_STMT,
394    /// Expression statement: `foo();`
395    EXPR_STMT,
396    /// Assignment statement: `x = ...;`
397    ASSIGN_STMT,
398    /// If statement: `if ... { } else { }`
399    IF_STMT,
400    /// For loop: `for i in 0..10 { }`
401    FOR_STMT,
402    /// Block: `{ ... }`
403    BLOCK,
404    /// Assert statement: `assert(...);`
405    ASSERT_STMT,
406    /// Assert equals statement: `assert_eq(...);`
407    ASSERT_EQ_STMT,
408    /// Assert not equals statement: `assert_neq(...);`
409    ASSERT_NEQ_STMT,
410
411    // ==========================================================================
412    // Composite Nodes - Patterns
413    // ==========================================================================
414    /// Identifier pattern: `x`
415    IDENT_PATTERN,
416    /// Tuple pattern: `(a, b, c)`
417    TUPLE_PATTERN,
418    /// Wildcard pattern: `_`
419    WILDCARD_PATTERN,
420
421    // ==========================================================================
422    // Composite Nodes - Expressions
423    // ==========================================================================
424    /// Binary expression: `a + b`
425    BINARY_EXPR,
426    /// Unary expression: `!a`, `-a`
427    UNARY_EXPR,
428    /// Function call: `foo(a, b)`
429    CALL_EXPR,
430    /// Method call: `a.foo(b)`
431    METHOD_CALL_EXPR,
432    /// Member access: `a.b`
433    FIELD_EXPR,
434    /// Array/tuple index: `a[0]`
435    INDEX_EXPR,
436    /// Cast expression: `a as u32`
437    CAST_EXPR,
438    /// Ternary expression: `a ? b : c`
439    TERNARY_EXPR,
440    /// Array literal: `[1, 2, 3]`
441    ARRAY_EXPR,
442    /// Tuple literal: `(1, 2, 3)`
443    TUPLE_EXPR,
444    /// Struct literal: `Foo { a: 1, b: 2 }`
445    STRUCT_EXPR,
446    /// Struct field initializer: `a: 1`
447    STRUCT_FIELD_INIT,
448    /// Path expression: `foo::bar`
449    PATH_EXPR,
450    /// Parenthesized expression: `(a + b)`
451    PAREN_EXPR,
452    /// Literal expression (wraps INTEGER, STRING, ADDRESS_LIT, or keywords).
453    LITERAL,
454    /// Repeat expression: `[0u8; 32]`
455    REPEAT_EXPR,
456    /// Async expression: `async foo()`
457    ASYNC_EXPR,
458    /// Associated function call: `Foo::bar()`
459    ASSOC_FN_EXPR,
460    /// Associated constant: `Foo::BAR`
461    ASSOC_CONST_EXPR,
462    /// Locator expression: `foo.aleo/bar`
463    LOCATOR_EXPR,
464    /// Tuple access: `a.0`
465    TUPLE_ACCESS_EXPR,
466    /// Intrinsic expression: `_foo()`
467    INTRINSIC_EXPR,
468    /// Unit expression: `()`
469    UNIT_EXPR,
470
471    // ==========================================================================
472    // Composite Nodes - Types
473    // ==========================================================================
474    /// Named/path type: `u32`, `Foo`, `foo::Bar`
475    TYPE_PATH,
476    /// Array type: `[u32; 10]`
477    TYPE_ARRAY,
478    /// Tuple type: `(u32, u32)`
479    TYPE_TUPLE,
480    /// Optional type: `u32?` (Future feature)
481    TYPE_OPTIONAL,
482    /// Future type: `Future<Foo>`
483    TYPE_FUTURE,
484    /// Mapping type in storage.
485    TYPE_MAPPING,
486
487    // ==========================================================================
488    // Composite Nodes - Other
489    // ==========================================================================
490    /// Argument list: `(a, b, c)`
491    ARG_LIST,
492    /// Name reference (identifier in expression context).
493    NAME_REF,
494    /// Name definition (identifier in binding context).
495    NAME,
496    /// Visibility modifier: `public`, `private`
497    VISIBILITY,
498
499    // Sentinel for bounds checking (must be last)
500    #[doc(hidden)]
501    __LAST,
502}
503
504impl SyntaxKind {
505    /// Check if this is a trivia token (whitespace or comment).
506    pub fn is_trivia(self) -> bool {
507        matches!(self, WHITESPACE | LINEBREAK | COMMENT_LINE | COMMENT_BLOCK)
508    }
509
510    /// Check if this is a keyword.
511    pub fn is_keyword(self) -> bool {
512        matches!(
513            self,
514            KW_TRUE
515                | KW_FALSE
516                | KW_NONE
517                | KW_ADDRESS
518                | KW_BOOL
519                | KW_FIELD
520                | KW_GROUP
521                | KW_SCALAR
522                | KW_SIGNATURE
523                | KW_STRING
524                | KW_RECORD
525                | KW_FUTURE
526                | KW_I8
527                | KW_I16
528                | KW_I32
529                | KW_I64
530                | KW_I128
531                | KW_U8
532                | KW_U16
533                | KW_U32
534                | KW_U64
535                | KW_U128
536                | KW_IF
537                | KW_ELSE
538                | KW_FOR
539                | KW_IN
540                | KW_RETURN
541                | KW_LET
542                | KW_CONST
543                | KW_CONSTANT
544                | KW_FUNCTION
545                | KW_TRANSITION
546                | KW_INLINE
547                | KW_ASYNC
548                | KW_FN
549                | KW_STRUCT
550                | KW_CONSTRUCTOR
551                | KW_PROGRAM
552                | KW_IMPORT
553                | KW_MAPPING
554                | KW_STORAGE
555                | KW_NETWORK
556                | KW_ALEO
557                | KW_SCRIPT
558                | KW_BLOCK
559                | KW_PUBLIC
560                | KW_PRIVATE
561                | KW_AS
562                | KW_SELF
563                | KW_ASSERT
564                | KW_ASSERT_EQ
565                | KW_ASSERT_NEQ
566        )
567    }
568
569    /// Check if this is a type keyword.
570    pub fn is_type_keyword(self) -> bool {
571        matches!(
572            self,
573            KW_ADDRESS
574                | KW_BOOL
575                | KW_FIELD
576                | KW_GROUP
577                | KW_SCALAR
578                | KW_SIGNATURE
579                | KW_STRING
580                | KW_FUTURE
581                | KW_I8
582                | KW_I16
583                | KW_I32
584                | KW_I64
585                | KW_I128
586                | KW_U8
587                | KW_U16
588                | KW_U32
589                | KW_U64
590                | KW_U128
591        )
592    }
593
594    /// Check if this is a literal token.
595    pub fn is_literal(self) -> bool {
596        matches!(self, INTEGER | STRING | ADDRESS_LIT | KW_TRUE | KW_FALSE | KW_NONE)
597    }
598
599    /// Check if this is a punctuation token.
600    pub fn is_punctuation(self) -> bool {
601        matches!(
602            self,
603            L_PAREN
604                | R_PAREN
605                | L_BRACKET
606                | R_BRACKET
607                | L_BRACE
608                | R_BRACE
609                | COMMA
610                | DOT
611                | DOT_DOT
612                | SEMICOLON
613                | COLON
614                | COLON_COLON
615                | QUESTION
616                | ARROW
617                | FAT_ARROW
618                | UNDERSCORE
619                | AT
620        )
621    }
622
623    /// Check if this is an operator token.
624    pub fn is_operator(self) -> bool {
625        matches!(
626            self,
627            EQ | PLUS_EQ
628                | MINUS_EQ
629                | STAR_EQ
630                | SLASH_EQ
631                | PERCENT_EQ
632                | STAR2_EQ
633                | AMP2_EQ
634                | PIPE2_EQ
635                | AMP_EQ
636                | PIPE_EQ
637                | CARET_EQ
638                | SHL_EQ
639                | SHR_EQ
640                | PLUS
641                | MINUS
642                | STAR
643                | SLASH
644                | PERCENT
645                | STAR2
646                | EQ2
647                | BANG_EQ
648                | LT
649                | LT_EQ
650                | GT
651                | GT_EQ
652                | AMP2
653                | PIPE2
654                | BANG
655                | AMP
656                | PIPE
657                | CARET
658                | SHL
659                | SHR
660        )
661    }
662}
663
664impl From<SyntaxKind> for rowan::SyntaxKind {
665    fn from(kind: SyntaxKind) -> Self {
666        Self(kind as u16)
667    }
668}
669
670/// Lookup table for converting raw u16 values back to SyntaxKind.
671/// This avoids unsafe transmute by using an explicit array.
672const SYNTAX_KIND_TABLE: &[SyntaxKind] = &[
673    ERROR,
674    EOF,
675    WHITESPACE,
676    LINEBREAK,
677    COMMENT_LINE,
678    COMMENT_BLOCK,
679    INTEGER,
680    STRING,
681    ADDRESS_LIT,
682    IDENT,
683    KW_TRUE,
684    KW_FALSE,
685    KW_NONE,
686    KW_ADDRESS,
687    KW_BOOL,
688    KW_FIELD,
689    KW_GROUP,
690    KW_SCALAR,
691    KW_SIGNATURE,
692    KW_STRING,
693    KW_RECORD,
694    KW_FUTURE,
695    KW_I8,
696    KW_I16,
697    KW_I32,
698    KW_I64,
699    KW_I128,
700    KW_U8,
701    KW_U16,
702    KW_U32,
703    KW_U64,
704    KW_U128,
705    KW_IF,
706    KW_ELSE,
707    KW_FOR,
708    KW_IN,
709    KW_RETURN,
710    KW_LET,
711    KW_CONST,
712    KW_CONSTANT,
713    KW_FUNCTION,
714    KW_TRANSITION,
715    KW_INLINE,
716    KW_ASYNC,
717    KW_FN,
718    KW_STRUCT,
719    KW_CONSTRUCTOR,
720    KW_PROGRAM,
721    KW_IMPORT,
722    KW_MAPPING,
723    KW_STORAGE,
724    KW_NETWORK,
725    KW_ALEO,
726    KW_SCRIPT,
727    KW_BLOCK,
728    KW_PUBLIC,
729    KW_PRIVATE,
730    KW_AS,
731    KW_SELF,
732    KW_ASSERT,
733    KW_ASSERT_EQ,
734    KW_ASSERT_NEQ,
735    L_PAREN,
736    R_PAREN,
737    L_BRACKET,
738    R_BRACKET,
739    L_BRACE,
740    R_BRACE,
741    COMMA,
742    DOT,
743    DOT_DOT,
744    SEMICOLON,
745    COLON,
746    COLON_COLON,
747    QUESTION,
748    ARROW,
749    FAT_ARROW,
750    UNDERSCORE,
751    AT,
752    EQ,
753    PLUS_EQ,
754    MINUS_EQ,
755    STAR_EQ,
756    SLASH_EQ,
757    PERCENT_EQ,
758    STAR2_EQ,
759    AMP2_EQ,
760    PIPE2_EQ,
761    AMP_EQ,
762    PIPE_EQ,
763    CARET_EQ,
764    SHL_EQ,
765    SHR_EQ,
766    PLUS,
767    MINUS,
768    STAR,
769    SLASH,
770    PERCENT,
771    STAR2,
772    EQ2,
773    BANG_EQ,
774    LT,
775    LT_EQ,
776    GT,
777    GT_EQ,
778    AMP2,
779    PIPE2,
780    BANG,
781    AMP,
782    PIPE,
783    CARET,
784    SHL,
785    SHR,
786    ROOT,
787    PROGRAM_DECL,
788    IMPORT,
789    MAIN_CONTENTS,
790    MODULE_CONTENTS,
791    FUNCTION_DEF,
792    CONSTRUCTOR_DEF,
793    STRUCT_DEF,
794    RECORD_DEF,
795    STRUCT_MEMBER,
796    MAPPING_DEF,
797    STORAGE_DEF,
798    GLOBAL_CONST,
799    ANNOTATION,
800    PARAM,
801    PARAM_LIST,
802    RETURN_TYPE,
803    CONST_PARAM,
804    CONST_PARAM_LIST,
805    CONST_ARG_LIST,
806    LET_STMT,
807    CONST_STMT,
808    RETURN_STMT,
809    EXPR_STMT,
810    ASSIGN_STMT,
811    IF_STMT,
812    FOR_STMT,
813    BLOCK,
814    ASSERT_STMT,
815    ASSERT_EQ_STMT,
816    ASSERT_NEQ_STMT,
817    IDENT_PATTERN,
818    TUPLE_PATTERN,
819    WILDCARD_PATTERN,
820    BINARY_EXPR,
821    UNARY_EXPR,
822    CALL_EXPR,
823    METHOD_CALL_EXPR,
824    FIELD_EXPR,
825    INDEX_EXPR,
826    CAST_EXPR,
827    TERNARY_EXPR,
828    ARRAY_EXPR,
829    TUPLE_EXPR,
830    STRUCT_EXPR,
831    STRUCT_FIELD_INIT,
832    PATH_EXPR,
833    PAREN_EXPR,
834    LITERAL,
835    REPEAT_EXPR,
836    ASYNC_EXPR,
837    ASSOC_FN_EXPR,
838    ASSOC_CONST_EXPR,
839    LOCATOR_EXPR,
840    TUPLE_ACCESS_EXPR,
841    INTRINSIC_EXPR,
842    UNIT_EXPR,
843    TYPE_PATH,
844    TYPE_ARRAY,
845    TYPE_TUPLE,
846    TYPE_OPTIONAL,
847    TYPE_FUTURE,
848    TYPE_MAPPING,
849    ARG_LIST,
850    NAME_REF,
851    NAME,
852    VISIBILITY,
853    __LAST,
854];
855
856/// Convert a raw rowan SyntaxKind to our SyntaxKind.
857///
858/// # Panics
859/// Panics if the raw value is out of range.
860pub fn syntax_kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
861    SYNTAX_KIND_TABLE.get(raw.0 as usize).copied().unwrap_or_else(|| panic!("invalid SyntaxKind: {}", raw.0))
862}
863
864#[cfg(test)]
865mod tests {
866    use super::*;
867
868    #[test]
869    fn syntax_kind_table_is_correct() {
870        // Verify that the table matches the enum discriminants
871        for (i, &kind) in SYNTAX_KIND_TABLE.iter().enumerate() {
872            assert_eq!(
873                kind as u16, i as u16,
874                "SYNTAX_KIND_TABLE[{i}] = {:?} has discriminant {}, expected {i}",
875                kind, kind as u16
876            );
877        }
878    }
879
880    #[test]
881    fn syntax_kind_roundtrip() {
882        // Test that we can convert to rowan::SyntaxKind and back
883        for &kind in SYNTAX_KIND_TABLE.iter() {
884            if kind == __LAST {
885                continue;
886            }
887            let raw: rowan::SyntaxKind = kind.into();
888            let back = syntax_kind_from_raw(raw);
889            assert_eq!(kind, back);
890        }
891    }
892
893    #[test]
894    fn is_trivia() {
895        assert!(WHITESPACE.is_trivia());
896        assert!(LINEBREAK.is_trivia());
897        assert!(COMMENT_LINE.is_trivia());
898        assert!(COMMENT_BLOCK.is_trivia());
899        assert!(!IDENT.is_trivia());
900        assert!(!KW_LET.is_trivia());
901    }
902
903    #[test]
904    fn is_keyword() {
905        assert!(KW_LET.is_keyword());
906        assert!(KW_FUNCTION.is_keyword());
907        assert!(KW_TRUE.is_keyword());
908        assert!(!IDENT.is_keyword());
909        assert!(!PLUS.is_keyword());
910    }
911
912    #[test]
913    fn is_literal() {
914        assert!(INTEGER.is_literal());
915        assert!(STRING.is_literal());
916        assert!(ADDRESS_LIT.is_literal());
917        assert!(KW_TRUE.is_literal());
918        assert!(KW_FALSE.is_literal());
919        assert!(KW_NONE.is_literal());
920        assert!(!IDENT.is_literal());
921    }
922}