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    /// Path expression: `foo::bar`
517    PATH_EXPR,
518    /// Path locator expression: `program.aleo::function`
519    PATH_LOCATOR_EXPR,
520    /// Program reference expression: `name.aleo` (without `::Type` suffix).
521    PROGRAM_REF_EXPR,
522    /// Self expression: `self`
523    SELF_EXPR,
524    /// Block keyword expression: `block`
525    BLOCK_KW_EXPR,
526    /// Network keyword expression: `network`
527    NETWORK_KW_EXPR,
528    /// Parenthesized expression: `(a + b)`
529    PAREN_EXPR,
530    /// Field literal: `42field`
531    LITERAL_FIELD,
532    /// Group literal: `42group`
533    LITERAL_GROUP,
534    /// Scalar literal: `42scalar`
535    LITERAL_SCALAR,
536    /// Integer literal: `42u32`, `42` (unsuffixed)
537    LITERAL_INT,
538    /// String literal: `"hello"`
539    LITERAL_STRING,
540    /// Address literal: `aleo1...`
541    LITERAL_ADDRESS,
542    /// Boolean literal: `true`, `false`
543    LITERAL_BOOL,
544    /// None literal: `none`
545    LITERAL_NONE,
546    /// Identifier literal: `'foo'`
547    LITERAL_IDENT,
548    /// Repeat expression: `[0u8; 32]`
549    REPEAT_EXPR,
550    /// Async expression: `async foo()`
551    FINAL_EXPR,
552    /// Tuple access: `a.0`
553    TUPLE_ACCESS_EXPR,
554    /// Dynamic interface access. Covers three surface forms:
555    /// - function call: `Interface @ (target) :: func(args)`
556    /// - storage/vector op: `Interface @ (target) :: member.op(args)`
557    /// - singleton bare read: `Interface @ (target) :: storage`
558    DYNAMIC_OP_EXPR,
559
560    // ==========================================================================
561    // Composite Nodes - Types
562    // ==========================================================================
563    /// Named/path type: `Foo`, `foo::Bar`
564    TYPE_PATH,
565    /// Primitive type: `u32`, `bool`, `field`, etc.
566    TYPE_PRIMITIVE,
567    /// Locator type: `program.aleo::Type`
568    TYPE_LOCATOR,
569    /// Array type: `[u32; 10]`
570    TYPE_ARRAY,
571    /// Vector type: `[u32]`
572    TYPE_VECTOR,
573    /// Tuple type: `(u32, u32)`
574    TYPE_TUPLE,
575    /// Optional type: `u32?` (Future feature)
576    TYPE_OPTIONAL,
577    /// Final type: `Final<Foo>`
578    TYPE_FINAL,
579    /// Mapping type in storage.
580    TYPE_MAPPING,
581    /// Dynamic record type: `dyn record`
582    TYPE_DYN_RECORD,
583    /// Parent list: `Foo + Bar`
584    PARENT_LIST,
585
586    // Sentinel for bounds checking (must be last)
587    #[doc(hidden)]
588    __LAST,
589}
590
591impl SyntaxKind {
592    /// Check if this is a trivia token (whitespace or comment).
593    pub fn is_trivia(self) -> bool {
594        matches!(self, WHITESPACE | LINEBREAK | COMMENT_LINE | COMMENT_BLOCK)
595    }
596
597    /// Check if this is a keyword.
598    pub fn is_keyword(self) -> bool {
599        matches!(
600            self,
601            KW_TRUE
602                | KW_FALSE
603                | KW_NONE
604                | KW_ADDRESS
605                | KW_BOOL
606                | KW_FIELD
607                | KW_GROUP
608                | KW_SCALAR
609                | KW_SIGNATURE
610                | KW_STRING
611                | KW_RECORD
612                | KW_DYN
613                | KW_IDENTIFIER
614                | KW_FINAL_UPPER
615                | KW_I8
616                | KW_I16
617                | KW_I32
618                | KW_I64
619                | KW_I128
620                | KW_U8
621                | KW_U16
622                | KW_U32
623                | KW_U64
624                | KW_U128
625                | KW_IF
626                | KW_ELSE
627                | KW_FOR
628                | KW_IN
629                | KW_RETURN
630                | KW_LET
631                | KW_CONST
632                | KW_CONSTANT
633                | KW_FN
634                | KW_FINAL
635                | KW_VIEW
636                | KW_FN_UPPER
637                | KW_STRUCT
638                | KW_CONSTRUCTOR
639                | KW_INTERFACE
640                | KW_PROGRAM
641                | KW_IMPORT
642                | KW_MAPPING
643                | KW_STORAGE
644                | KW_NETWORK
645                | KW_ALEO
646                | KW_SCRIPT
647                | KW_BLOCK
648                | KW_PUBLIC
649                | KW_PRIVATE
650                | KW_AS
651                | KW_SELF
652                | KW_ASSERT
653                | KW_ASSERT_EQ
654                | KW_ASSERT_NEQ
655        )
656    }
657
658    /// Check if this is a type keyword.
659    pub fn is_type_keyword(self) -> bool {
660        matches!(
661            self,
662            KW_ADDRESS
663                | KW_BOOL
664                | KW_FIELD
665                | KW_GROUP
666                | KW_SCALAR
667                | KW_SIGNATURE
668                | KW_STRING
669                | KW_DYN
670                | KW_IDENTIFIER
671                | KW_FINAL_UPPER
672                | KW_I8
673                | KW_I16
674                | KW_I32
675                | KW_I64
676                | KW_I128
677                | KW_U8
678                | KW_U16
679                | KW_U32
680                | KW_U64
681                | KW_U128
682        )
683    }
684
685    /// Check if this is a literal token.
686    pub fn is_literal(self) -> bool {
687        matches!(self, INTEGER | STRING | ADDRESS_LIT | IDENT_LIT | KW_TRUE | KW_FALSE | KW_NONE)
688    }
689
690    /// Check if this is a literal node kind.
691    pub fn is_literal_node(self) -> bool {
692        matches!(
693            self,
694            LITERAL_FIELD
695                | LITERAL_GROUP
696                | LITERAL_SCALAR
697                | LITERAL_INT
698                | LITERAL_STRING
699                | LITERAL_ADDRESS
700                | LITERAL_BOOL
701                | LITERAL_NONE
702                | LITERAL_IDENT
703        )
704    }
705
706    /// Check if this is a type node kind.
707    pub fn is_type(self) -> bool {
708        matches!(
709            self,
710            TYPE_PRIMITIVE
711                | TYPE_LOCATOR
712                | TYPE_PATH
713                | TYPE_ARRAY
714                | TYPE_VECTOR
715                | TYPE_TUPLE
716                | TYPE_OPTIONAL
717                | TYPE_FINAL
718                | TYPE_MAPPING
719                | TYPE_DYN_RECORD
720        )
721    }
722
723    /// Check if this is an expression node kind.
724    pub fn is_expression(self) -> bool {
725        self.is_literal_node()
726            || matches!(
727                self,
728                BINARY_EXPR
729                    | UNARY_EXPR
730                    | CALL_EXPR
731                    | METHOD_CALL_EXPR
732                    | FIELD_EXPR
733                    | TUPLE_ACCESS_EXPR
734                    | INDEX_EXPR
735                    | CAST_EXPR
736                    | TERNARY_EXPR
737                    | ARRAY_EXPR
738                    | REPEAT_EXPR
739                    | TUPLE_EXPR
740                    | STRUCT_EXPR
741                    | STRUCT_LOCATOR_EXPR
742                    | PATH_EXPR
743                    | PATH_LOCATOR_EXPR
744                    | PROGRAM_REF_EXPR
745                    | SELF_EXPR
746                    | BLOCK_KW_EXPR
747                    | NETWORK_KW_EXPR
748                    | PAREN_EXPR
749                    | FINAL_EXPR
750                    | DYNAMIC_OP_EXPR
751            )
752    }
753
754    /// Check if this is a statement node kind.
755    pub fn is_statement(self) -> bool {
756        matches!(
757            self,
758            LET_STMT
759                | CONST_STMT
760                | RETURN_STMT
761                | EXPR_STMT
762                | ASSIGN_STMT
763                | COMPOUND_ASSIGN_STMT
764                | IF_STMT
765                | FOR_STMT
766                | FOR_INCLUSIVE_STMT
767                | BLOCK
768                | ASSERT_STMT
769                | ASSERT_EQ_STMT
770                | ASSERT_NEQ_STMT
771        )
772    }
773
774    /// Check if this is a punctuation token.
775    pub fn is_punctuation(self) -> bool {
776        matches!(
777            self,
778            L_PAREN
779                | R_PAREN
780                | L_BRACKET
781                | R_BRACKET
782                | L_BRACE
783                | R_BRACE
784                | COMMA
785                | DOT
786                | DOT_DOT
787                | DOT_DOT_EQ
788                | SEMICOLON
789                | COLON
790                | COLON_COLON
791                | QUESTION
792                | ARROW
793                | FAT_ARROW
794                | UNDERSCORE
795                | AT
796        )
797    }
798
799    /// Check if this is an operator token.
800    pub fn is_operator(self) -> bool {
801        matches!(
802            self,
803            EQ | PLUS_EQ
804                | MINUS_EQ
805                | STAR_EQ
806                | SLASH_EQ
807                | PERCENT_EQ
808                | STAR2_EQ
809                | AMP2_EQ
810                | PIPE2_EQ
811                | AMP_EQ
812                | PIPE_EQ
813                | CARET_EQ
814                | SHL_EQ
815                | SHR_EQ
816                | PLUS
817                | MINUS
818                | STAR
819                | SLASH
820                | PERCENT
821                | STAR2
822                | EQ2
823                | BANG_EQ
824                | LT
825                | LT_EQ
826                | GT
827                | GT_EQ
828                | AMP2
829                | PIPE2
830                | BANG
831                | AMP
832                | PIPE
833                | CARET
834                | SHL
835                | SHR
836        )
837    }
838
839    /// Returns a user-friendly name for this token kind, suitable for error messages.
840    pub fn user_friendly_name(self) -> &'static str {
841        match self {
842            // Special
843            ERROR => "an error",
844            EOF => "end of file",
845
846            // Trivia
847            WHITESPACE | LINEBREAK => "whitespace",
848            COMMENT_LINE | COMMENT_BLOCK => "a comment",
849
850            // Literals
851            INTEGER => "an integer literal",
852            STRING => "a static string",
853            ADDRESS_LIT => "an address literal",
854            IDENT_LIT => "an identifier literal",
855
856            // Identifiers
857            IDENT => "an identifier",
858
859            // Boolean literals
860            KW_TRUE => "'true'",
861            KW_FALSE => "'false'",
862            KW_NONE => "'none'",
863
864            // Type keywords
865            KW_ADDRESS => "'address'",
866            KW_BOOL => "'bool'",
867            KW_FIELD => "'field'",
868            KW_GROUP => "'group'",
869            KW_SCALAR => "'scalar'",
870            KW_SIGNATURE => "'signature'",
871            KW_STRING => "'string'",
872            KW_RECORD => "'record'",
873            KW_DYN => "'dyn'",
874            KW_IDENTIFIER => "'identifier'",
875            KW_FINAL_UPPER => "'Final'",
876            KW_I8 => "'i8'",
877            KW_I16 => "'i16'",
878            KW_I32 => "'i32'",
879            KW_I64 => "'i64'",
880            KW_I128 => "'i128'",
881            KW_U8 => "'u8'",
882            KW_U16 => "'u16'",
883            KW_U32 => "'u32'",
884            KW_U64 => "'u64'",
885            KW_U128 => "'u128'",
886
887            // Control flow keywords
888            KW_IF => "'if'",
889            KW_ELSE => "'else'",
890            KW_FOR => "'for'",
891            KW_IN => "'in'",
892            KW_RETURN => "'return'",
893
894            // Declaration keywords
895            KW_LET => "'let'",
896            KW_CONST => "'const'",
897            KW_CONSTANT => "'constant'",
898            KW_FINAL => "'final'",
899            KW_VIEW => "'view'",
900            KW_FN => "'fn'",
901            KW_FN_UPPER => "'Fn'",
902            KW_STRUCT => "'struct'",
903            KW_CONSTRUCTOR => "'constructor'",
904            KW_INTERFACE => "'interface'",
905
906            // Program structure keywords
907            KW_PROGRAM => "'program'",
908            KW_IMPORT => "'import'",
909            KW_MAPPING => "'mapping'",
910            KW_STORAGE => "'storage'",
911            KW_NETWORK => "'network'",
912            KW_ALEO => "'aleo'",
913            KW_SCRIPT => "'script'",
914            KW_BLOCK => "'block'",
915
916            // Visibility and assertion keywords
917            KW_PUBLIC => "'public'",
918            KW_PRIVATE => "'private'",
919            KW_AS => "'as'",
920            KW_SELF => "'self'",
921            KW_ASSERT => "'assert'",
922            KW_ASSERT_EQ => "'assert_eq'",
923            KW_ASSERT_NEQ => "'assert_neq'",
924
925            // Delimiters
926            L_PAREN => "'('",
927            R_PAREN => "')'",
928            L_BRACKET => "'['",
929            R_BRACKET => "']'",
930            L_BRACE => "'{'",
931            R_BRACE => "'}'",
932
933            // Separators
934            COMMA => "','",
935            DOT => "'.'",
936            DOT_DOT => "'..'",
937            DOT_DOT_EQ => "'..='",
938            SEMICOLON => "';'",
939            COLON => "':'",
940            COLON_COLON => "'::'",
941            QUESTION => "'?'",
942            ARROW => "'->'",
943            FAT_ARROW => "'=>'",
944            UNDERSCORE => "'_'",
945            AT => "'@'",
946
947            // Assignment operators
948            EQ => "'='",
949            PLUS_EQ => "'+='",
950            MINUS_EQ => "'-='",
951            STAR_EQ => "'*='",
952            SLASH_EQ => "'/='",
953            PERCENT_EQ => "'%='",
954            STAR2_EQ => "'**='",
955            AMP2_EQ => "'&&='",
956            PIPE2_EQ => "'||='",
957            AMP_EQ => "'&='",
958            PIPE_EQ => "'|='",
959            CARET_EQ => "'^='",
960            SHL_EQ => "'<<='",
961            SHR_EQ => "'>>='",
962
963            // Arithmetic operators
964            PLUS => "'+'",
965            MINUS => "'-'",
966            STAR => "'*'",
967            SLASH => "'/'",
968            PERCENT => "'%'",
969            STAR2 => "'**'",
970
971            // Comparison operators
972            EQ2 => "'=='",
973            BANG_EQ => "'!='",
974            LT => "'<'",
975            LT_EQ => "'<='",
976            GT => "'>'",
977            GT_EQ => "'>='",
978
979            // Logical operators
980            AMP2 => "'&&'",
981            PIPE2 => "'||'",
982            BANG => "'!'",
983
984            // Bitwise operators
985            AMP => "'&'",
986            PIPE => "'|'",
987            CARET => "'^'",
988            SHL => "'<<'",
989            SHR => "'>>'",
990
991            // Composite nodes - these shouldn't appear in "expected" messages typically
992            _ => "a token",
993        }
994    }
995}
996
997impl From<SyntaxKind> for rowan::SyntaxKind {
998    fn from(kind: SyntaxKind) -> Self {
999        Self(kind as u16)
1000    }
1001}
1002
1003/// Convert a raw rowan SyntaxKind to our SyntaxKind.
1004///
1005/// # Panics
1006/// Panics if the raw value is out of range.
1007pub fn syntax_kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
1008    SYNTAX_KIND_TABLE.get(raw.0 as usize).copied().unwrap_or_else(|| panic!("invalid SyntaxKind: {}", raw.0))
1009}
1010
1011#[cfg(test)]
1012mod tests {
1013    use super::*;
1014
1015    #[test]
1016    fn syntax_kind_table_is_correct() {
1017        // Verify that the table matches the enum discriminants
1018        for (i, &kind) in SYNTAX_KIND_TABLE.iter().enumerate() {
1019            assert_eq!(
1020                kind as u16, i as u16,
1021                "SYNTAX_KIND_TABLE[{i}] = {:?} has discriminant {}, expected {i}",
1022                kind, kind as u16
1023            );
1024        }
1025    }
1026
1027    #[test]
1028    fn syntax_kind_roundtrip() {
1029        // Test that we can convert to rowan::SyntaxKind and back
1030        for &kind in SYNTAX_KIND_TABLE.iter() {
1031            if kind == __LAST {
1032                continue;
1033            }
1034            let raw: rowan::SyntaxKind = kind.into();
1035            let back = syntax_kind_from_raw(raw);
1036            assert_eq!(kind, back);
1037        }
1038    }
1039
1040    #[test]
1041    fn is_trivia() {
1042        assert!(WHITESPACE.is_trivia());
1043        assert!(LINEBREAK.is_trivia());
1044        assert!(COMMENT_LINE.is_trivia());
1045        assert!(COMMENT_BLOCK.is_trivia());
1046        assert!(!IDENT.is_trivia());
1047        assert!(!KW_LET.is_trivia());
1048    }
1049
1050    #[test]
1051    fn is_keyword() {
1052        assert!(KW_LET.is_keyword());
1053        assert!(KW_FN.is_keyword());
1054        assert!(KW_TRUE.is_keyword());
1055        assert!(!IDENT.is_keyword());
1056        assert!(!PLUS.is_keyword());
1057    }
1058
1059    #[test]
1060    fn is_literal() {
1061        assert!(INTEGER.is_literal());
1062        assert!(STRING.is_literal());
1063        assert!(ADDRESS_LIT.is_literal());
1064        assert!(KW_TRUE.is_literal());
1065        assert!(KW_FALSE.is_literal());
1066        assert!(KW_NONE.is_literal());
1067        assert!(!IDENT.is_literal());
1068    }
1069}