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