use SyntaxKind::*;
macro_rules! define_syntax_kinds {
(
$(
$(#[$attr:meta])*
$variant:ident $(= $value:expr)?
),* $(,)?
) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u16)]
#[allow(non_camel_case_types)]
pub enum SyntaxKind {
$(
$(#[$attr])*
$variant $(= $value)?
),*
}
const SYNTAX_KIND_TABLE: &[SyntaxKind] = &[
$(SyntaxKind::$variant),*
];
};
}
define_syntax_kinds! {
ERROR = 0,
EOF,
WHITESPACE,
LINEBREAK,
COMMENT_LINE,
COMMENT_BLOCK,
INTEGER,
STRING,
ADDRESS_LIT,
IDENT_LIT,
IDENT,
KW_TRUE,
KW_FALSE,
KW_NONE,
KW_ADDRESS,
KW_BOOL,
KW_FIELD,
KW_GROUP,
KW_SCALAR,
KW_SIGNATURE,
KW_STRING,
KW_RECORD,
KW_DYN,
KW_IDENTIFIER,
KW_FINAL_UPPER,
KW_I8,
KW_I16,
KW_I32,
KW_I64,
KW_I128,
KW_U8,
KW_U16,
KW_U32,
KW_U64,
KW_U128,
KW_IF,
KW_ELSE,
KW_FOR,
KW_IN,
KW_RETURN,
KW_LET,
KW_CONST,
KW_CONSTANT,
KW_FINAL,
KW_FN,
KW_FN_UPPER,
KW_STRUCT,
KW_CONSTRUCTOR,
KW_INTERFACE,
KW_PROGRAM,
KW_IMPORT,
KW_MAPPING,
KW_STORAGE,
KW_NETWORK,
KW_ALEO,
KW_SCRIPT,
KW_BLOCK,
KW_PUBLIC,
KW_PRIVATE,
KW_AS,
KW_SELF,
KW_ASSERT,
KW_ASSERT_EQ,
KW_ASSERT_NEQ,
L_PAREN,
R_PAREN,
L_BRACKET,
R_BRACKET,
L_BRACE,
R_BRACE,
COMMA,
DOT,
DOT_DOT,
DOT_DOT_EQ,
SEMICOLON,
COLON,
COLON_COLON,
QUESTION,
ARROW,
FAT_ARROW,
UNDERSCORE,
AT,
EQ,
PLUS_EQ,
MINUS_EQ,
STAR_EQ,
SLASH_EQ,
PERCENT_EQ,
STAR2_EQ,
AMP2_EQ,
PIPE2_EQ,
AMP_EQ,
PIPE_EQ,
CARET_EQ,
SHL_EQ,
SHR_EQ,
PLUS,
MINUS,
STAR,
SLASH,
PERCENT,
STAR2,
EQ2,
BANG_EQ,
LT,
LT_EQ,
GT,
GT_EQ,
AMP2,
PIPE2,
BANG,
AMP,
PIPE,
CARET,
SHL,
SHR,
ROOT,
PROGRAM_DECL,
IMPORT,
MAIN_CONTENTS,
MODULE_CONTENTS,
FUNCTION_DEF,
FINAL_FN_DEF,
CONSTRUCTOR_DEF,
STRUCT_DEF,
RECORD_DEF,
STRUCT_MEMBER,
STRUCT_MEMBER_PUBLIC,
STRUCT_MEMBER_PRIVATE,
STRUCT_MEMBER_CONSTANT,
MAPPING_DEF,
STORAGE_DEF,
GLOBAL_CONST,
INTERFACE_DEF,
FN_PROTOTYPE_DEF,
RECORD_PROTOTYPE_DEF,
ANNOTATION,
ANNOTATION_PAIR,
PARAM,
PARAM_PUBLIC,
PARAM_PRIVATE,
PARAM_CONSTANT,
PARAM_LIST,
RETURN_TYPE,
CONST_PARAM,
CONST_PARAM_LIST,
CONST_ARG_LIST,
DYNAMIC_CALL_RETURN_TYPE,
ARRAY_LENGTH,
LET_STMT,
CONST_STMT,
RETURN_STMT,
EXPR_STMT,
ASSIGN_STMT,
COMPOUND_ASSIGN_STMT,
IF_STMT,
FOR_STMT,
FOR_INCLUSIVE_STMT,
BLOCK,
ASSERT_STMT,
ASSERT_EQ_STMT,
ASSERT_NEQ_STMT,
IDENT_PATTERN,
TUPLE_PATTERN,
WILDCARD_PATTERN,
BINARY_EXPR,
UNARY_EXPR,
CALL_EXPR,
METHOD_CALL_EXPR,
FIELD_EXPR,
INDEX_EXPR,
CAST_EXPR,
TERNARY_EXPR,
ARRAY_EXPR,
TUPLE_EXPR,
STRUCT_EXPR,
STRUCT_LOCATOR_EXPR,
STRUCT_FIELD_INIT,
STRUCT_FIELD_SHORTHAND,
PATH_EXPR,
PATH_LOCATOR_EXPR,
PROGRAM_REF_EXPR,
SELF_EXPR,
BLOCK_KW_EXPR,
NETWORK_KW_EXPR,
PAREN_EXPR,
LITERAL_FIELD,
LITERAL_GROUP,
LITERAL_SCALAR,
LITERAL_INT,
LITERAL_STRING,
LITERAL_ADDRESS,
LITERAL_BOOL,
LITERAL_NONE,
LITERAL_IDENT,
REPEAT_EXPR,
FINAL_EXPR,
TUPLE_ACCESS_EXPR,
DYNAMIC_CALL_EXPR,
TYPE_PATH,
TYPE_PRIMITIVE,
TYPE_LOCATOR,
TYPE_ARRAY,
TYPE_VECTOR,
TYPE_TUPLE,
TYPE_OPTIONAL,
TYPE_FINAL,
TYPE_MAPPING,
TYPE_DYN_RECORD,
PARENT_LIST,
#[doc(hidden)]
__LAST,
}
impl SyntaxKind {
pub fn is_trivia(self) -> bool {
matches!(self, WHITESPACE | LINEBREAK | COMMENT_LINE | COMMENT_BLOCK)
}
pub fn is_keyword(self) -> bool {
matches!(
self,
KW_TRUE
| KW_FALSE
| KW_NONE
| KW_ADDRESS
| KW_BOOL
| KW_FIELD
| KW_GROUP
| KW_SCALAR
| KW_SIGNATURE
| KW_STRING
| KW_RECORD
| KW_DYN
| KW_IDENTIFIER
| KW_FINAL_UPPER
| KW_I8
| KW_I16
| KW_I32
| KW_I64
| KW_I128
| KW_U8
| KW_U16
| KW_U32
| KW_U64
| KW_U128
| KW_IF
| KW_ELSE
| KW_FOR
| KW_IN
| KW_RETURN
| KW_LET
| KW_CONST
| KW_CONSTANT
| KW_FN
| KW_FINAL
| KW_FN_UPPER
| KW_STRUCT
| KW_CONSTRUCTOR
| KW_INTERFACE
| KW_PROGRAM
| KW_IMPORT
| KW_MAPPING
| KW_STORAGE
| KW_NETWORK
| KW_ALEO
| KW_SCRIPT
| KW_BLOCK
| KW_PUBLIC
| KW_PRIVATE
| KW_AS
| KW_SELF
| KW_ASSERT
| KW_ASSERT_EQ
| KW_ASSERT_NEQ
)
}
pub fn is_type_keyword(self) -> bool {
matches!(
self,
KW_ADDRESS
| KW_BOOL
| KW_FIELD
| KW_GROUP
| KW_SCALAR
| KW_SIGNATURE
| KW_STRING
| KW_DYN
| KW_IDENTIFIER
| KW_FINAL_UPPER
| KW_I8
| KW_I16
| KW_I32
| KW_I64
| KW_I128
| KW_U8
| KW_U16
| KW_U32
| KW_U64
| KW_U128
)
}
pub fn is_literal(self) -> bool {
matches!(self, INTEGER | STRING | ADDRESS_LIT | IDENT_LIT | KW_TRUE | KW_FALSE | KW_NONE)
}
pub fn is_literal_node(self) -> bool {
matches!(
self,
LITERAL_FIELD
| LITERAL_GROUP
| LITERAL_SCALAR
| LITERAL_INT
| LITERAL_STRING
| LITERAL_ADDRESS
| LITERAL_BOOL
| LITERAL_NONE
| LITERAL_IDENT
)
}
pub fn is_type(self) -> bool {
matches!(
self,
TYPE_PRIMITIVE
| TYPE_LOCATOR
| TYPE_PATH
| TYPE_ARRAY
| TYPE_VECTOR
| TYPE_TUPLE
| TYPE_OPTIONAL
| TYPE_FINAL
| TYPE_MAPPING
| TYPE_DYN_RECORD
)
}
pub fn is_expression(self) -> bool {
self.is_literal_node()
|| matches!(
self,
BINARY_EXPR
| UNARY_EXPR
| CALL_EXPR
| METHOD_CALL_EXPR
| FIELD_EXPR
| TUPLE_ACCESS_EXPR
| INDEX_EXPR
| CAST_EXPR
| TERNARY_EXPR
| ARRAY_EXPR
| REPEAT_EXPR
| TUPLE_EXPR
| STRUCT_EXPR
| STRUCT_LOCATOR_EXPR
| PATH_EXPR
| PATH_LOCATOR_EXPR
| PROGRAM_REF_EXPR
| SELF_EXPR
| BLOCK_KW_EXPR
| NETWORK_KW_EXPR
| PAREN_EXPR
| FINAL_EXPR
| DYNAMIC_CALL_EXPR
)
}
pub fn is_statement(self) -> bool {
matches!(
self,
LET_STMT
| CONST_STMT
| RETURN_STMT
| EXPR_STMT
| ASSIGN_STMT
| COMPOUND_ASSIGN_STMT
| IF_STMT
| FOR_STMT
| FOR_INCLUSIVE_STMT
| BLOCK
| ASSERT_STMT
| ASSERT_EQ_STMT
| ASSERT_NEQ_STMT
)
}
pub fn is_punctuation(self) -> bool {
matches!(
self,
L_PAREN
| R_PAREN
| L_BRACKET
| R_BRACKET
| L_BRACE
| R_BRACE
| COMMA
| DOT
| DOT_DOT
| DOT_DOT_EQ
| SEMICOLON
| COLON
| COLON_COLON
| QUESTION
| ARROW
| FAT_ARROW
| UNDERSCORE
| AT
)
}
pub fn is_operator(self) -> bool {
matches!(
self,
EQ | PLUS_EQ
| MINUS_EQ
| STAR_EQ
| SLASH_EQ
| PERCENT_EQ
| STAR2_EQ
| AMP2_EQ
| PIPE2_EQ
| AMP_EQ
| PIPE_EQ
| CARET_EQ
| SHL_EQ
| SHR_EQ
| PLUS
| MINUS
| STAR
| SLASH
| PERCENT
| STAR2
| EQ2
| BANG_EQ
| LT
| LT_EQ
| GT
| GT_EQ
| AMP2
| PIPE2
| BANG
| AMP
| PIPE
| CARET
| SHL
| SHR
)
}
pub fn user_friendly_name(self) -> &'static str {
match self {
ERROR => "an error",
EOF => "end of file",
WHITESPACE | LINEBREAK => "whitespace",
COMMENT_LINE | COMMENT_BLOCK => "a comment",
INTEGER => "an integer literal",
STRING => "a static string",
ADDRESS_LIT => "an address literal",
IDENT_LIT => "an identifier literal",
IDENT => "an identifier",
KW_TRUE => "'true'",
KW_FALSE => "'false'",
KW_NONE => "'none'",
KW_ADDRESS => "'address'",
KW_BOOL => "'bool'",
KW_FIELD => "'field'",
KW_GROUP => "'group'",
KW_SCALAR => "'scalar'",
KW_SIGNATURE => "'signature'",
KW_STRING => "'string'",
KW_RECORD => "'record'",
KW_DYN => "'dyn'",
KW_IDENTIFIER => "'identifier'",
KW_FINAL_UPPER => "'Final'",
KW_I8 => "'i8'",
KW_I16 => "'i16'",
KW_I32 => "'i32'",
KW_I64 => "'i64'",
KW_I128 => "'i128'",
KW_U8 => "'u8'",
KW_U16 => "'u16'",
KW_U32 => "'u32'",
KW_U64 => "'u64'",
KW_U128 => "'u128'",
KW_IF => "'if'",
KW_ELSE => "'else'",
KW_FOR => "'for'",
KW_IN => "'in'",
KW_RETURN => "'return'",
KW_LET => "'let'",
KW_CONST => "'const'",
KW_CONSTANT => "'constant'",
KW_FINAL => "'final'",
KW_FN => "'fn'",
KW_FN_UPPER => "'Fn'",
KW_STRUCT => "'struct'",
KW_CONSTRUCTOR => "'constructor'",
KW_INTERFACE => "'interface'",
KW_PROGRAM => "'program'",
KW_IMPORT => "'import'",
KW_MAPPING => "'mapping'",
KW_STORAGE => "'storage'",
KW_NETWORK => "'network'",
KW_ALEO => "'aleo'",
KW_SCRIPT => "'script'",
KW_BLOCK => "'block'",
KW_PUBLIC => "'public'",
KW_PRIVATE => "'private'",
KW_AS => "'as'",
KW_SELF => "'self'",
KW_ASSERT => "'assert'",
KW_ASSERT_EQ => "'assert_eq'",
KW_ASSERT_NEQ => "'assert_neq'",
L_PAREN => "'('",
R_PAREN => "')'",
L_BRACKET => "'['",
R_BRACKET => "']'",
L_BRACE => "'{'",
R_BRACE => "'}'",
COMMA => "','",
DOT => "'.'",
DOT_DOT => "'..'",
DOT_DOT_EQ => "'..='",
SEMICOLON => "';'",
COLON => "':'",
COLON_COLON => "'::'",
QUESTION => "'?'",
ARROW => "'->'",
FAT_ARROW => "'=>'",
UNDERSCORE => "'_'",
AT => "'@'",
EQ => "'='",
PLUS_EQ => "'+='",
MINUS_EQ => "'-='",
STAR_EQ => "'*='",
SLASH_EQ => "'/='",
PERCENT_EQ => "'%='",
STAR2_EQ => "'**='",
AMP2_EQ => "'&&='",
PIPE2_EQ => "'||='",
AMP_EQ => "'&='",
PIPE_EQ => "'|='",
CARET_EQ => "'^='",
SHL_EQ => "'<<='",
SHR_EQ => "'>>='",
PLUS => "'+'",
MINUS => "'-'",
STAR => "'*'",
SLASH => "'/'",
PERCENT => "'%'",
STAR2 => "'**'",
EQ2 => "'=='",
BANG_EQ => "'!='",
LT => "'<'",
LT_EQ => "'<='",
GT => "'>'",
GT_EQ => "'>='",
AMP2 => "'&&'",
PIPE2 => "'||'",
BANG => "'!'",
AMP => "'&'",
PIPE => "'|'",
CARET => "'^'",
SHL => "'<<'",
SHR => "'>>'",
_ => "a token",
}
}
}
impl From<SyntaxKind> for rowan::SyntaxKind {
fn from(kind: SyntaxKind) -> Self {
Self(kind as u16)
}
}
pub fn syntax_kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
SYNTAX_KIND_TABLE.get(raw.0 as usize).copied().unwrap_or_else(|| panic!("invalid SyntaxKind: {}", raw.0))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn syntax_kind_table_is_correct() {
for (i, &kind) in SYNTAX_KIND_TABLE.iter().enumerate() {
assert_eq!(
kind as u16, i as u16,
"SYNTAX_KIND_TABLE[{i}] = {:?} has discriminant {}, expected {i}",
kind, kind as u16
);
}
}
#[test]
fn syntax_kind_roundtrip() {
for &kind in SYNTAX_KIND_TABLE.iter() {
if kind == __LAST {
continue;
}
let raw: rowan::SyntaxKind = kind.into();
let back = syntax_kind_from_raw(raw);
assert_eq!(kind, back);
}
}
#[test]
fn is_trivia() {
assert!(WHITESPACE.is_trivia());
assert!(LINEBREAK.is_trivia());
assert!(COMMENT_LINE.is_trivia());
assert!(COMMENT_BLOCK.is_trivia());
assert!(!IDENT.is_trivia());
assert!(!KW_LET.is_trivia());
}
#[test]
fn is_keyword() {
assert!(KW_LET.is_keyword());
assert!(KW_FN.is_keyword());
assert!(KW_TRUE.is_keyword());
assert!(!IDENT.is_keyword());
assert!(!PLUS.is_keyword());
}
#[test]
fn is_literal() {
assert!(INTEGER.is_literal());
assert!(STRING.is_literal());
assert!(ADDRESS_LIT.is_literal());
assert!(KW_TRUE.is_literal());
assert!(KW_FALSE.is_literal());
assert!(KW_NONE.is_literal());
assert!(!IDENT.is_literal());
}
}