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/// Macro to define SyntaxKind enum and its lookup table in one place.
28/// This ensures they can never get out of sync.
29macro_rules! define_syntax_kinds {
30    (
31        $(
32            $(#[$attr:meta])*
33            $variant:ident $(= $value:expr)?
34        ),* $(,)?
35    ) => {
36        /// All syntax kinds for Leo tokens and nodes.
37        ///
38        /// This enum is intentionally flat (not nested) to satisfy rowan's requirement
39        /// for a `#[repr(u16)]` type. Categories are indicated by comments and helper
40        /// methods like `is_trivia()` and `is_keyword()`.
41        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
42        #[repr(u16)]
43        #[allow(non_camel_case_types)]
44        pub enum SyntaxKind {
45            $(
46                $(#[$attr])*
47                $variant $(= $value)?
48            ),*
49        }
50
51        /// Lookup table for converting raw u16 values back to SyntaxKind.
52        /// This is auto-generated by the define_syntax_kinds! macro.
53        const SYNTAX_KIND_TABLE: &[SyntaxKind] = &[
54            $(SyntaxKind::$variant),*
55        ];
56    };
57}
58
59define_syntax_kinds! {
60    // ==========================================================================
61    // Special
62    // ==========================================================================
63    /// Error node for wrapping parse errors and invalid tokens.
64    ERROR = 0,
65    /// End of file marker.
66    EOF,
67
68    // ==========================================================================
69    // Trivia (whitespace and comments)
70    // ==========================================================================
71    /// Horizontal whitespace: spaces, tabs, form feeds.
72    WHITESPACE,
73    /// Line breaks: \n or \r\n.
74    LINEBREAK,
75    /// Line comment: // ...
76    COMMENT_LINE,
77    /// Block comment: /* ... */
78    COMMENT_BLOCK,
79
80    // ==========================================================================
81    // Literals
82    // ==========================================================================
83    /// Integer literal: 123, 0xFF, 0b101, 0o77
84    INTEGER,
85    /// String literal: "..."
86    STRING,
87    /// Address literal: aleo1...
88    ADDRESS_LIT,
89    /// Identifier literal: 'foo'
90    IDENT_LIT,
91
92    // ==========================================================================
93    // Identifiers
94    // ==========================================================================
95    /// Identifier: foo, Bar, _baz
96    /// Note: Complex identifiers (paths, program IDs, locators) are deferred
97    /// to Phase 2. The lexer produces simple IDENT tokens; the parser handles
98    /// disambiguation of foo::bar, foo.aleo, foo.aleo::bar patterns.
99    IDENT,
100
101    // ==========================================================================
102    // Keywords - Literals
103    // ==========================================================================
104    /// `true`
105    KW_TRUE,
106    /// `false`
107    KW_FALSE,
108    /// `none`
109    KW_NONE,
110
111    // ==========================================================================
112    // Keywords - Types
113    // ==========================================================================
114    /// `address`
115    KW_ADDRESS,
116    /// `bool`
117    KW_BOOL,
118    /// `field`
119    KW_FIELD,
120    /// `group`
121    KW_GROUP,
122    /// `scalar`
123    KW_SCALAR,
124    /// `signature`
125    KW_SIGNATURE,
126    /// `string`
127    KW_STRING,
128    /// `record`
129    KW_RECORD,
130    /// `dyn`
131    KW_DYN,
132    /// `identifier`
133    KW_IDENTIFIER,
134    /// `Final`
135    KW_FINAL_UPPER,
136    /// `i8`
137    KW_I8,
138    /// `i16`
139    KW_I16,
140    /// `i32`
141    KW_I32,
142    /// `i64`
143    KW_I64,
144    /// `i128`
145    KW_I128,
146    /// `u8`
147    KW_U8,
148    /// `u16`
149    KW_U16,
150    /// `u32`
151    KW_U32,
152    /// `u64`
153    KW_U64,
154    /// `u128`
155    KW_U128,
156
157    // ==========================================================================
158    // Keywords - Control Flow
159    // ==========================================================================
160    /// `if`
161    KW_IF,
162    /// `else`
163    KW_ELSE,
164    /// `for`
165    KW_FOR,
166    /// `in`
167    KW_IN,
168    /// `return`
169    KW_RETURN,
170
171    // ==========================================================================
172    // Keywords - Declarations
173    // ==========================================================================
174    /// `let`
175    KW_LET,
176    /// `const`
177    KW_CONST,
178    /// `constant`
179    KW_CONSTANT,
180    /// `final`
181    KW_FINAL,
182    /// `fn`
183    KW_FN,
184    /// `Fn`
185    KW_FN_UPPER,
186    /// `struct`
187    KW_STRUCT,
188    /// `constructor`
189    KW_CONSTRUCTOR,
190    /// `interface`
191    KW_INTERFACE,
192
193    // ==========================================================================
194    // Keywords - Program Structure
195    // ==========================================================================
196    /// `program`
197    KW_PROGRAM,
198    /// `import`
199    KW_IMPORT,
200    /// `mapping`
201    KW_MAPPING,
202    /// `storage`
203    KW_STORAGE,
204    /// `network`
205    KW_NETWORK,
206    /// `aleo`
207    KW_ALEO,
208    /// `script`
209    KW_SCRIPT,
210    /// `block`
211    KW_BLOCK,
212
213    // ==========================================================================
214    // Keywords - Visibility & Assertions
215    // ==========================================================================
216    /// `public`
217    KW_PUBLIC,
218    /// `private`
219    KW_PRIVATE,
220    /// `as`
221    KW_AS,
222    /// `self`
223    KW_SELF,
224    /// `assert`
225    KW_ASSERT,
226    /// `assert_eq`
227    KW_ASSERT_EQ,
228    /// `assert_neq`
229    KW_ASSERT_NEQ,
230
231    // ==========================================================================
232    // Punctuation - Delimiters
233    // ==========================================================================
234    /// `(`
235    L_PAREN,
236    /// `)`
237    R_PAREN,
238    /// `[`
239    L_BRACKET,
240    /// `]`
241    R_BRACKET,
242    /// `{`
243    L_BRACE,
244    /// `}`
245    R_BRACE,
246
247    // ==========================================================================
248    // Punctuation - Separators
249    // ==========================================================================
250    /// `,`
251    COMMA,
252    /// `.`
253    DOT,
254    /// `..`
255    DOT_DOT,
256    /// `..=`
257    DOT_DOT_EQ,
258    /// `;`
259    SEMICOLON,
260    /// `:`
261    COLON,
262    /// `::`
263    COLON_COLON,
264    /// `?`
265    QUESTION,
266    /// `->`
267    ARROW,
268    /// `=>`
269    FAT_ARROW,
270    /// `_`
271    UNDERSCORE,
272    /// `@`
273    AT,
274
275    // ==========================================================================
276    // Operators - Assignment
277    // ==========================================================================
278    /// `=`
279    EQ,
280    /// `+=`
281    PLUS_EQ,
282    /// `-=`
283    MINUS_EQ,
284    /// `*=`
285    STAR_EQ,
286    /// `/=`
287    SLASH_EQ,
288    /// `%=`
289    PERCENT_EQ,
290    /// `**=`
291    STAR2_EQ,
292    /// `&&=`
293    AMP2_EQ,
294    /// `||=`
295    PIPE2_EQ,
296    /// `&=`
297    AMP_EQ,
298    /// `|=`
299    PIPE_EQ,
300    /// `^=`
301    CARET_EQ,
302    /// `<<=`
303    SHL_EQ,
304    /// `>>=`
305    SHR_EQ,
306
307    // ==========================================================================
308    // Operators - Arithmetic
309    // ==========================================================================
310    /// `+`
311    PLUS,
312    /// `-`
313    MINUS,
314    /// `*`
315    STAR,
316    /// `/`
317    SLASH,
318    /// `%`
319    PERCENT,
320    /// `**`
321    STAR2,
322
323    // ==========================================================================
324    // Operators - Comparison
325    // ==========================================================================
326    /// `==`
327    EQ2,
328    /// `!=`
329    BANG_EQ,
330    /// `<`
331    LT,
332    /// `<=`
333    LT_EQ,
334    /// `>`
335    GT,
336    /// `>=`
337    GT_EQ,
338
339    // ==========================================================================
340    // Operators - Logical
341    // ==========================================================================
342    /// `&&`
343    AMP2,
344    /// `||`
345    PIPE2,
346    /// `!`
347    BANG,
348
349    // ==========================================================================
350    // Operators - Bitwise
351    // ==========================================================================
352    /// `&`
353    AMP,
354    /// `|`
355    PIPE,
356    /// `^`
357    CARET,
358    /// `<<`
359    SHL,
360    /// `>>`
361    SHR,
362
363    // ==========================================================================
364    // Composite Nodes - Top Level
365    // ==========================================================================
366    /// Root node of the syntax tree.
367    ROOT,
368    /// Program declaration: `program foo.aleo { ... }`
369    PROGRAM_DECL,
370    /// Import statement: `import foo.aleo;`
371    IMPORT,
372    /// Main file contents.
373    MAIN_CONTENTS,
374    /// Module file contents.
375    MODULE_CONTENTS,
376
377    // ==========================================================================
378    // Composite Nodes - Declarations
379    // ==========================================================================
380    /// Function definition.
381    FUNCTION_DEF,
382    /// Final function definition: `final fn ...`
383    FINAL_FN_DEF,
384    /// Constructor definition.
385    CONSTRUCTOR_DEF,
386    /// Struct definition.
387    STRUCT_DEF,
388    /// Record definition.
389    RECORD_DEF,
390    /// Struct member declaration.
391    STRUCT_MEMBER,
392    /// Public struct member: `public name: Type`
393    STRUCT_MEMBER_PUBLIC,
394    /// Private struct member: `private name: Type`
395    STRUCT_MEMBER_PRIVATE,
396    /// Constant struct member: `constant name: Type`
397    STRUCT_MEMBER_CONSTANT,
398    /// Mapping definition.
399    MAPPING_DEF,
400    /// Storage definition.
401    STORAGE_DEF,
402    /// Global constant definition.
403    GLOBAL_CONST,
404    /// Interface declaration.
405    INTERFACE_DEF,
406    /// Function prototype (in interface).
407    FN_PROTOTYPE_DEF,
408    /// Record prototype (in interface).
409    RECORD_PROTOTYPE_DEF,
410
411    // ==========================================================================
412    // Composite Nodes - Function Parts
413    // ==========================================================================
414    /// Annotation: `@foo`
415    ANNOTATION,
416    /// Annotation key-value pair: `key = "value"`
417    ANNOTATION_PAIR,
418    /// Parameter in a function signature.
419    PARAM,
420    /// Public parameter: `public name: Type`
421    PARAM_PUBLIC,
422    /// Private parameter: `private name: Type`
423    PARAM_PRIVATE,
424    /// Constant parameter: `constant name: Type`
425    PARAM_CONSTANT,
426    /// Parameter list: `(a: u32, b: u32)`
427    PARAM_LIST,
428    /// Function output type.
429    RETURN_TYPE,
430    /// Const generic parameter.
431    CONST_PARAM,
432    /// Const generic parameter list.
433    CONST_PARAM_LIST,
434    /// Const generic argument list.
435    CONST_ARG_LIST,
436    /// Visibility-annotated return type for `_dynamic_call` (e.g. `public u64`).
437    DYNAMIC_CALL_RETURN_TYPE,
438    /// Array length expression wrapper in `[T; N]`.
439    ARRAY_LENGTH,
440
441    // ==========================================================================
442    // Composite Nodes - Statements
443    // ==========================================================================
444    /// Let statement: `let x = ...;`
445    LET_STMT,
446    /// Const statement: `const x = ...;`
447    CONST_STMT,
448    /// Return statement: `return ...;`
449    RETURN_STMT,
450    /// Expression statement: `foo();`
451    EXPR_STMT,
452    /// Assignment statement: `x = ...;`
453    ASSIGN_STMT,
454    /// Compound assignment statement: `x += ...;`, `x -= ...;`, etc.
455    COMPOUND_ASSIGN_STMT,
456    /// If statement: `if ... { } else { }`
457    IF_STMT,
458    /// For loop: `for i in 0..10 { }`
459    FOR_STMT,
460    /// Inclusive for loop: `for i in 0..=10 { }`
461    FOR_INCLUSIVE_STMT,
462    /// Block: `{ ... }`
463    BLOCK,
464    /// Assert statement: `assert(...);`
465    ASSERT_STMT,
466    /// Assert equals statement: `assert_eq(...);`
467    ASSERT_EQ_STMT,
468    /// Assert not equals statement: `assert_neq(...);`
469    ASSERT_NEQ_STMT,
470
471    // ==========================================================================
472    // Composite Nodes - Patterns
473    // ==========================================================================
474    /// Identifier pattern: `x`
475    IDENT_PATTERN,
476    /// Tuple pattern: `(a, b, c)`
477    TUPLE_PATTERN,
478    /// Wildcard pattern: `_`
479    WILDCARD_PATTERN,
480
481    // ==========================================================================
482    // Composite Nodes - Expressions
483    // ==========================================================================
484    /// Binary expression: `a + b`
485    BINARY_EXPR,
486    /// Unary expression: `!a`, `-a`
487    UNARY_EXPR,
488    /// Function call: `foo(a, b)`
489    CALL_EXPR,
490    /// Method call: `a.foo(b)`
491    METHOD_CALL_EXPR,
492    /// Member access: `a.b`
493    FIELD_EXPR,
494    /// Array/tuple index: `a[0]`
495    INDEX_EXPR,
496    /// Cast expression: `a as u32`
497    CAST_EXPR,
498    /// Ternary expression: `a ? b : c`
499    TERNARY_EXPR,
500    /// Array literal: `[1, 2, 3]`
501    ARRAY_EXPR,
502    /// Tuple literal: `(1, 2, 3)`
503    TUPLE_EXPR,
504    /// Struct literal: `Foo { a: 1, b: 2 }`
505    STRUCT_EXPR,
506    /// Struct locator literal: `program.aleo::Type { a: 1, b: 2 }`
507    STRUCT_LOCATOR_EXPR,
508    /// Struct field initializer: `a: 1`
509    STRUCT_FIELD_INIT,
510    /// Struct field shorthand: `{ x }` (equivalent to `{ x: x }`)
511    STRUCT_FIELD_SHORTHAND,
512    /// Path expression: `foo::bar`
513    PATH_EXPR,
514    /// Path locator expression: `program.aleo::function`
515    PATH_LOCATOR_EXPR,
516    /// Program reference expression: `name.aleo` (without `::Type` suffix).
517    PROGRAM_REF_EXPR,
518    /// Self expression: `self`
519    SELF_EXPR,
520    /// Block keyword expression: `block`
521    BLOCK_KW_EXPR,
522    /// Network keyword expression: `network`
523    NETWORK_KW_EXPR,
524    /// Parenthesized expression: `(a + b)`
525    PAREN_EXPR,
526    /// Field literal: `42field`
527    LITERAL_FIELD,
528    /// Group literal: `42group`
529    LITERAL_GROUP,
530    /// Scalar literal: `42scalar`
531    LITERAL_SCALAR,
532    /// Integer literal: `42u32`, `42` (unsuffixed)
533    LITERAL_INT,
534    /// String literal: `"hello"`
535    LITERAL_STRING,
536    /// Address literal: `aleo1...`
537    LITERAL_ADDRESS,
538    /// Boolean literal: `true`, `false`
539    LITERAL_BOOL,
540    /// None literal: `none`
541    LITERAL_NONE,
542    /// Identifier literal: `'foo'`
543    LITERAL_IDENT,
544    /// Repeat expression: `[0u8; 32]`
545    REPEAT_EXPR,
546    /// Async expression: `async foo()`
547    FINAL_EXPR,
548    /// Tuple access: `a.0`
549    TUPLE_ACCESS_EXPR,
550    /// Dynamic call: `Interface @ (target) :: function(args)`
551    DYNAMIC_CALL_EXPR,
552
553    // ==========================================================================
554    // Composite Nodes - Types
555    // ==========================================================================
556    /// Named/path type: `Foo`, `foo::Bar`
557    TYPE_PATH,
558    /// Primitive type: `u32`, `bool`, `field`, etc.
559    TYPE_PRIMITIVE,
560    /// Locator type: `program.aleo::Type`
561    TYPE_LOCATOR,
562    /// Array type: `[u32; 10]`
563    TYPE_ARRAY,
564    /// Vector type: `[u32]`
565    TYPE_VECTOR,
566    /// Tuple type: `(u32, u32)`
567    TYPE_TUPLE,
568    /// Optional type: `u32?` (Future feature)
569    TYPE_OPTIONAL,
570    /// Final type: `Final<Foo>`
571    TYPE_FINAL,
572    /// Mapping type in storage.
573    TYPE_MAPPING,
574    /// Dynamic record type: `dyn record`
575    TYPE_DYN_RECORD,
576    /// Parent list: `Foo + Bar`
577    PARENT_LIST,
578
579    // Sentinel for bounds checking (must be last)
580    #[doc(hidden)]
581    __LAST,
582}
583
584impl SyntaxKind {
585    /// Check if this is a trivia token (whitespace or comment).
586    pub fn is_trivia(self) -> bool {
587        matches!(self, WHITESPACE | LINEBREAK | COMMENT_LINE | COMMENT_BLOCK)
588    }
589
590    /// Check if this is a keyword.
591    pub fn is_keyword(self) -> bool {
592        matches!(
593            self,
594            KW_TRUE
595                | KW_FALSE
596                | KW_NONE
597                | KW_ADDRESS
598                | KW_BOOL
599                | KW_FIELD
600                | KW_GROUP
601                | KW_SCALAR
602                | KW_SIGNATURE
603                | KW_STRING
604                | KW_RECORD
605                | KW_DYN
606                | KW_IDENTIFIER
607                | KW_FINAL_UPPER
608                | KW_I8
609                | KW_I16
610                | KW_I32
611                | KW_I64
612                | KW_I128
613                | KW_U8
614                | KW_U16
615                | KW_U32
616                | KW_U64
617                | KW_U128
618                | KW_IF
619                | KW_ELSE
620                | KW_FOR
621                | KW_IN
622                | KW_RETURN
623                | KW_LET
624                | KW_CONST
625                | KW_CONSTANT
626                | KW_FN
627                | KW_FINAL
628                | KW_FN_UPPER
629                | KW_STRUCT
630                | KW_CONSTRUCTOR
631                | KW_INTERFACE
632                | KW_PROGRAM
633                | KW_IMPORT
634                | KW_MAPPING
635                | KW_STORAGE
636                | KW_NETWORK
637                | KW_ALEO
638                | KW_SCRIPT
639                | KW_BLOCK
640                | KW_PUBLIC
641                | KW_PRIVATE
642                | KW_AS
643                | KW_SELF
644                | KW_ASSERT
645                | KW_ASSERT_EQ
646                | KW_ASSERT_NEQ
647        )
648    }
649
650    /// Check if this is a type keyword.
651    pub fn is_type_keyword(self) -> bool {
652        matches!(
653            self,
654            KW_ADDRESS
655                | KW_BOOL
656                | KW_FIELD
657                | KW_GROUP
658                | KW_SCALAR
659                | KW_SIGNATURE
660                | KW_STRING
661                | KW_DYN
662                | KW_IDENTIFIER
663                | KW_FINAL_UPPER
664                | KW_I8
665                | KW_I16
666                | KW_I32
667                | KW_I64
668                | KW_I128
669                | KW_U8
670                | KW_U16
671                | KW_U32
672                | KW_U64
673                | KW_U128
674        )
675    }
676
677    /// Check if this is a literal token.
678    pub fn is_literal(self) -> bool {
679        matches!(self, INTEGER | STRING | ADDRESS_LIT | IDENT_LIT | KW_TRUE | KW_FALSE | KW_NONE)
680    }
681
682    /// Check if this is a literal node kind.
683    pub fn is_literal_node(self) -> bool {
684        matches!(
685            self,
686            LITERAL_FIELD
687                | LITERAL_GROUP
688                | LITERAL_SCALAR
689                | LITERAL_INT
690                | LITERAL_STRING
691                | LITERAL_ADDRESS
692                | LITERAL_BOOL
693                | LITERAL_NONE
694                | LITERAL_IDENT
695        )
696    }
697
698    /// Check if this is a type node kind.
699    pub fn is_type(self) -> bool {
700        matches!(
701            self,
702            TYPE_PRIMITIVE
703                | TYPE_LOCATOR
704                | TYPE_PATH
705                | TYPE_ARRAY
706                | TYPE_VECTOR
707                | TYPE_TUPLE
708                | TYPE_OPTIONAL
709                | TYPE_FINAL
710                | TYPE_MAPPING
711                | TYPE_DYN_RECORD
712        )
713    }
714
715    /// Check if this is an expression node kind.
716    pub fn is_expression(self) -> bool {
717        self.is_literal_node()
718            || matches!(
719                self,
720                BINARY_EXPR
721                    | UNARY_EXPR
722                    | CALL_EXPR
723                    | METHOD_CALL_EXPR
724                    | FIELD_EXPR
725                    | TUPLE_ACCESS_EXPR
726                    | INDEX_EXPR
727                    | CAST_EXPR
728                    | TERNARY_EXPR
729                    | ARRAY_EXPR
730                    | REPEAT_EXPR
731                    | TUPLE_EXPR
732                    | STRUCT_EXPR
733                    | STRUCT_LOCATOR_EXPR
734                    | PATH_EXPR
735                    | PATH_LOCATOR_EXPR
736                    | PROGRAM_REF_EXPR
737                    | SELF_EXPR
738                    | BLOCK_KW_EXPR
739                    | NETWORK_KW_EXPR
740                    | PAREN_EXPR
741                    | FINAL_EXPR
742                    | DYNAMIC_CALL_EXPR
743            )
744    }
745
746    /// Check if this is a statement node kind.
747    pub fn is_statement(self) -> bool {
748        matches!(
749            self,
750            LET_STMT
751                | CONST_STMT
752                | RETURN_STMT
753                | EXPR_STMT
754                | ASSIGN_STMT
755                | COMPOUND_ASSIGN_STMT
756                | IF_STMT
757                | FOR_STMT
758                | FOR_INCLUSIVE_STMT
759                | BLOCK
760                | ASSERT_STMT
761                | ASSERT_EQ_STMT
762                | ASSERT_NEQ_STMT
763        )
764    }
765
766    /// Check if this is a punctuation token.
767    pub fn is_punctuation(self) -> bool {
768        matches!(
769            self,
770            L_PAREN
771                | R_PAREN
772                | L_BRACKET
773                | R_BRACKET
774                | L_BRACE
775                | R_BRACE
776                | COMMA
777                | DOT
778                | DOT_DOT
779                | DOT_DOT_EQ
780                | SEMICOLON
781                | COLON
782                | COLON_COLON
783                | QUESTION
784                | ARROW
785                | FAT_ARROW
786                | UNDERSCORE
787                | AT
788        )
789    }
790
791    /// Check if this is an operator token.
792    pub fn is_operator(self) -> bool {
793        matches!(
794            self,
795            EQ | PLUS_EQ
796                | MINUS_EQ
797                | STAR_EQ
798                | SLASH_EQ
799                | PERCENT_EQ
800                | STAR2_EQ
801                | AMP2_EQ
802                | PIPE2_EQ
803                | AMP_EQ
804                | PIPE_EQ
805                | CARET_EQ
806                | SHL_EQ
807                | SHR_EQ
808                | PLUS
809                | MINUS
810                | STAR
811                | SLASH
812                | PERCENT
813                | STAR2
814                | EQ2
815                | BANG_EQ
816                | LT
817                | LT_EQ
818                | GT
819                | GT_EQ
820                | AMP2
821                | PIPE2
822                | BANG
823                | AMP
824                | PIPE
825                | CARET
826                | SHL
827                | SHR
828        )
829    }
830
831    /// Returns a user-friendly name for this token kind, suitable for error messages.
832    pub fn user_friendly_name(self) -> &'static str {
833        match self {
834            // Special
835            ERROR => "an error",
836            EOF => "end of file",
837
838            // Trivia
839            WHITESPACE | LINEBREAK => "whitespace",
840            COMMENT_LINE | COMMENT_BLOCK => "a comment",
841
842            // Literals
843            INTEGER => "an integer literal",
844            STRING => "a static string",
845            ADDRESS_LIT => "an address literal",
846            IDENT_LIT => "an identifier literal",
847
848            // Identifiers
849            IDENT => "an identifier",
850
851            // Boolean literals
852            KW_TRUE => "'true'",
853            KW_FALSE => "'false'",
854            KW_NONE => "'none'",
855
856            // Type keywords
857            KW_ADDRESS => "'address'",
858            KW_BOOL => "'bool'",
859            KW_FIELD => "'field'",
860            KW_GROUP => "'group'",
861            KW_SCALAR => "'scalar'",
862            KW_SIGNATURE => "'signature'",
863            KW_STRING => "'string'",
864            KW_RECORD => "'record'",
865            KW_DYN => "'dyn'",
866            KW_IDENTIFIER => "'identifier'",
867            KW_FINAL_UPPER => "'Final'",
868            KW_I8 => "'i8'",
869            KW_I16 => "'i16'",
870            KW_I32 => "'i32'",
871            KW_I64 => "'i64'",
872            KW_I128 => "'i128'",
873            KW_U8 => "'u8'",
874            KW_U16 => "'u16'",
875            KW_U32 => "'u32'",
876            KW_U64 => "'u64'",
877            KW_U128 => "'u128'",
878
879            // Control flow keywords
880            KW_IF => "'if'",
881            KW_ELSE => "'else'",
882            KW_FOR => "'for'",
883            KW_IN => "'in'",
884            KW_RETURN => "'return'",
885
886            // Declaration keywords
887            KW_LET => "'let'",
888            KW_CONST => "'const'",
889            KW_CONSTANT => "'constant'",
890            KW_FINAL => "'final'",
891            KW_FN => "'fn'",
892            KW_FN_UPPER => "'Fn'",
893            KW_STRUCT => "'struct'",
894            KW_CONSTRUCTOR => "'constructor'",
895            KW_INTERFACE => "'interface'",
896
897            // Program structure keywords
898            KW_PROGRAM => "'program'",
899            KW_IMPORT => "'import'",
900            KW_MAPPING => "'mapping'",
901            KW_STORAGE => "'storage'",
902            KW_NETWORK => "'network'",
903            KW_ALEO => "'aleo'",
904            KW_SCRIPT => "'script'",
905            KW_BLOCK => "'block'",
906
907            // Visibility and assertion keywords
908            KW_PUBLIC => "'public'",
909            KW_PRIVATE => "'private'",
910            KW_AS => "'as'",
911            KW_SELF => "'self'",
912            KW_ASSERT => "'assert'",
913            KW_ASSERT_EQ => "'assert_eq'",
914            KW_ASSERT_NEQ => "'assert_neq'",
915
916            // Delimiters
917            L_PAREN => "'('",
918            R_PAREN => "')'",
919            L_BRACKET => "'['",
920            R_BRACKET => "']'",
921            L_BRACE => "'{'",
922            R_BRACE => "'}'",
923
924            // Separators
925            COMMA => "','",
926            DOT => "'.'",
927            DOT_DOT => "'..'",
928            DOT_DOT_EQ => "'..='",
929            SEMICOLON => "';'",
930            COLON => "':'",
931            COLON_COLON => "'::'",
932            QUESTION => "'?'",
933            ARROW => "'->'",
934            FAT_ARROW => "'=>'",
935            UNDERSCORE => "'_'",
936            AT => "'@'",
937
938            // Assignment operators
939            EQ => "'='",
940            PLUS_EQ => "'+='",
941            MINUS_EQ => "'-='",
942            STAR_EQ => "'*='",
943            SLASH_EQ => "'/='",
944            PERCENT_EQ => "'%='",
945            STAR2_EQ => "'**='",
946            AMP2_EQ => "'&&='",
947            PIPE2_EQ => "'||='",
948            AMP_EQ => "'&='",
949            PIPE_EQ => "'|='",
950            CARET_EQ => "'^='",
951            SHL_EQ => "'<<='",
952            SHR_EQ => "'>>='",
953
954            // Arithmetic operators
955            PLUS => "'+'",
956            MINUS => "'-'",
957            STAR => "'*'",
958            SLASH => "'/'",
959            PERCENT => "'%'",
960            STAR2 => "'**'",
961
962            // Comparison operators
963            EQ2 => "'=='",
964            BANG_EQ => "'!='",
965            LT => "'<'",
966            LT_EQ => "'<='",
967            GT => "'>'",
968            GT_EQ => "'>='",
969
970            // Logical operators
971            AMP2 => "'&&'",
972            PIPE2 => "'||'",
973            BANG => "'!'",
974
975            // Bitwise operators
976            AMP => "'&'",
977            PIPE => "'|'",
978            CARET => "'^'",
979            SHL => "'<<'",
980            SHR => "'>>'",
981
982            // Composite nodes - these shouldn't appear in "expected" messages typically
983            _ => "a token",
984        }
985    }
986}
987
988impl From<SyntaxKind> for rowan::SyntaxKind {
989    fn from(kind: SyntaxKind) -> Self {
990        Self(kind as u16)
991    }
992}
993
994/// Convert a raw rowan SyntaxKind to our SyntaxKind.
995///
996/// # Panics
997/// Panics if the raw value is out of range.
998pub fn syntax_kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
999    SYNTAX_KIND_TABLE.get(raw.0 as usize).copied().unwrap_or_else(|| panic!("invalid SyntaxKind: {}", raw.0))
1000}
1001
1002#[cfg(test)]
1003mod tests {
1004    use super::*;
1005
1006    #[test]
1007    fn syntax_kind_table_is_correct() {
1008        // Verify that the table matches the enum discriminants
1009        for (i, &kind) in SYNTAX_KIND_TABLE.iter().enumerate() {
1010            assert_eq!(
1011                kind as u16, i as u16,
1012                "SYNTAX_KIND_TABLE[{i}] = {:?} has discriminant {}, expected {i}",
1013                kind, kind as u16
1014            );
1015        }
1016    }
1017
1018    #[test]
1019    fn syntax_kind_roundtrip() {
1020        // Test that we can convert to rowan::SyntaxKind and back
1021        for &kind in SYNTAX_KIND_TABLE.iter() {
1022            if kind == __LAST {
1023                continue;
1024            }
1025            let raw: rowan::SyntaxKind = kind.into();
1026            let back = syntax_kind_from_raw(raw);
1027            assert_eq!(kind, back);
1028        }
1029    }
1030
1031    #[test]
1032    fn is_trivia() {
1033        assert!(WHITESPACE.is_trivia());
1034        assert!(LINEBREAK.is_trivia());
1035        assert!(COMMENT_LINE.is_trivia());
1036        assert!(COMMENT_BLOCK.is_trivia());
1037        assert!(!IDENT.is_trivia());
1038        assert!(!KW_LET.is_trivia());
1039    }
1040
1041    #[test]
1042    fn is_keyword() {
1043        assert!(KW_LET.is_keyword());
1044        assert!(KW_FN.is_keyword());
1045        assert!(KW_TRUE.is_keyword());
1046        assert!(!IDENT.is_keyword());
1047        assert!(!PLUS.is_keyword());
1048    }
1049
1050    #[test]
1051    fn is_literal() {
1052        assert!(INTEGER.is_literal());
1053        assert!(STRING.is_literal());
1054        assert!(ADDRESS_LIT.is_literal());
1055        assert!(KW_TRUE.is_literal());
1056        assert!(KW_FALSE.is_literal());
1057        assert!(KW_NONE.is_literal());
1058        assert!(!IDENT.is_literal());
1059    }
1060}