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