#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u16)]
#[allow(clippy::upper_case_acronyms)]
pub enum SyntaxKind {
Whitespace,
Comment,
DocComment,
Newline,
LineContinuation,
Indent,
Dedent,
Eof,
Unknown,
Int,
Float,
Str,
StringName,
NodePath,
GetNode,
UniqueNode,
Ident,
AndKw,
AsKw,
AssertKw,
AwaitKw,
BreakKw,
BreakpointKw,
ClassKw,
ClassNameKw,
ConstKw,
ContinueKw,
ElifKw,
ElseKw,
EnumKw,
ExtendsKw,
FalseKw,
ForKw,
FuncKw,
IfKw,
InKw,
IsKw,
MatchKw,
NamespaceKw,
NotKw,
NullKw,
OrKw,
PassKw,
PreloadKw,
ReturnKw,
SelfKw,
SignalKw,
StaticKw,
SuperKw,
TraitKw,
TrueKw,
VarKw,
VoidKw,
WhenKw,
WhileKw,
YieldKw,
Plus,
Minus,
Star,
StarStar,
Slash,
Percent,
Eq,
PlusEq,
MinusEq,
StarEq,
StarStarEq,
SlashEq,
PercentEq,
AmpEq,
PipeEq,
CaretEq,
ShlEq,
ShrEq,
EqEq,
Bang,
BangEq,
Lt,
LtEq,
Gt,
GtEq,
Amp,
AmpAmp,
Pipe,
PipePipe,
Caret,
Tilde,
Shl,
Shr,
Arrow,
ColonEq,
Colon,
Semicolon,
Comma,
Dot,
DotDot,
Ellipsis,
At,
Dollar,
LParen,
RParen,
LBracket,
RBracket,
LBrace,
RBrace,
SourceFile,
Annotation,
ClassNameDecl,
ExtendsDecl,
SignalDecl,
EnumDecl,
EnumBody,
EnumVariant,
ConstDecl,
VarDecl,
FuncDecl,
ClassDecl,
ParamList,
Param,
ArgList,
TypeHint,
ReturnType,
Initializer,
Accessors,
Setter,
Getter,
Block,
ExprStmt,
AssignStmt,
IfStmt,
ElifClause,
ElseClause,
WhileStmt,
ForStmt,
MatchStmt,
MatchArm,
MatchGuard,
ReturnStmt,
PassStmt,
BreakStmt,
ContinueStmt,
BreakpointStmt,
AssertStmt,
BinaryExpr,
UnaryExpr,
TernaryExpr,
CastExpr,
AwaitExpr,
CallExpr,
SubscriptExpr,
AttributeExpr,
ParenExpr,
ArrayExpr,
DictExpr,
DictEntry,
LambdaExpr,
PreloadExpr,
NameRef,
Literal,
Error,
}
impl SyntaxKind {
pub const FIRST_NODE: SyntaxKind = SyntaxKind::SourceFile;
const FIRST_KEYWORD: SyntaxKind = SyntaxKind::AndKw;
const LAST_KEYWORD: SyntaxKind = SyntaxKind::YieldKw;
#[must_use]
pub fn is_keyword(self) -> bool {
self >= Self::FIRST_KEYWORD && self <= Self::LAST_KEYWORD
}
#[must_use]
pub fn is_ident_like(self) -> bool {
self == Self::Ident || self.is_keyword()
}
#[must_use]
pub fn is_name(self) -> bool {
matches!(self, Self::Ident | Self::MatchKw | Self::WhenKw)
}
#[must_use]
pub fn is_token(self) -> bool {
self < Self::FIRST_NODE
}
#[must_use]
pub fn is_node(self) -> bool {
!self.is_token()
}
#[must_use]
pub fn is_trivia(self) -> bool {
matches!(
self,
Self::Whitespace
| Self::Comment
| Self::DocComment
| Self::Newline
| Self::LineContinuation
)
}
#[must_use]
pub fn is_comment(self) -> bool {
matches!(self, Self::Comment | Self::DocComment)
}
#[must_use]
pub fn is_literal(self) -> bool {
matches!(
self,
Self::Int
| Self::Float
| Self::Str
| Self::StringName
| Self::NodePath
| Self::TrueKw
| Self::FalseKw
| Self::NullKw
)
}
#[must_use]
pub fn from_keyword(text: &str) -> Option<Self> {
Some(match text {
"and" => Self::AndKw,
"as" => Self::AsKw,
"assert" => Self::AssertKw,
"await" => Self::AwaitKw,
"break" => Self::BreakKw,
"breakpoint" => Self::BreakpointKw,
"class" => Self::ClassKw,
"class_name" => Self::ClassNameKw,
"const" => Self::ConstKw,
"continue" => Self::ContinueKw,
"elif" => Self::ElifKw,
"else" => Self::ElseKw,
"enum" => Self::EnumKw,
"extends" => Self::ExtendsKw,
"false" => Self::FalseKw,
"for" => Self::ForKw,
"func" => Self::FuncKw,
"if" => Self::IfKw,
"in" => Self::InKw,
"is" => Self::IsKw,
"match" => Self::MatchKw,
"namespace" => Self::NamespaceKw,
"not" => Self::NotKw,
"null" => Self::NullKw,
"or" => Self::OrKw,
"pass" => Self::PassKw,
"preload" => Self::PreloadKw,
"return" => Self::ReturnKw,
"self" => Self::SelfKw,
"signal" => Self::SignalKw,
"static" => Self::StaticKw,
"super" => Self::SuperKw,
"trait" => Self::TraitKw,
"true" => Self::TrueKw,
"var" => Self::VarKw,
"void" => Self::VoidKw,
"when" => Self::WhenKw,
"while" => Self::WhileKw,
"yield" => Self::YieldKw,
_ => return None,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn token_and_node_partition() {
assert!(SyntaxKind::Whitespace.is_token());
assert!(SyntaxKind::RBrace.is_token());
assert!(SyntaxKind::SourceFile.is_node());
assert!(SyntaxKind::Error.is_node());
assert!(!SyntaxKind::SourceFile.is_token());
}
#[test]
fn indent_is_structural_not_trivia() {
assert!(SyntaxKind::Whitespace.is_trivia());
assert!(SyntaxKind::Comment.is_trivia());
assert!(!SyntaxKind::Indent.is_trivia());
assert!(!SyntaxKind::Dedent.is_trivia());
}
#[test]
fn keywords_round_trip() {
assert_eq!(SyntaxKind::from_keyword("func"), Some(SyntaxKind::FuncKw));
assert_eq!(
SyntaxKind::from_keyword("class_name"),
Some(SyntaxKind::ClassNameKw)
);
assert_eq!(SyntaxKind::from_keyword("classname"), None);
assert_eq!(SyntaxKind::from_keyword("Func"), None);
assert_eq!(SyntaxKind::from_keyword("position"), None);
}
}