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