use rowan::ast::{AstNode, support};
use crate::syntax::{JuliaLanguage, SyntaxKind, SyntaxNode, SyntaxToken};
macro_rules! ast_node {
($name:ident, $kind:expr) => {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct $name(SyntaxNode);
impl AstNode for $name {
type Language = JuliaLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == $kind
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then_some(Self(syntax))
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
};
}
ast_node!(Root, SyntaxKind::ROOT);
ast_node!(Literal, SyntaxKind::LITERAL);
ast_node!(StringLiteral, SyntaxKind::STRING_LITERAL);
ast_node!(CmdLiteral, SyntaxKind::CMD_LITERAL);
ast_node!(Interpolation, SyntaxKind::INTERPOLATION);
ast_node!(Name, SyntaxKind::NAME);
ast_node!(BinaryExpr, SyntaxKind::BINARY_EXPR);
ast_node!(UnaryExpr, SyntaxKind::UNARY_EXPR);
ast_node!(ParenExpr, SyntaxKind::PAREN_EXPR);
ast_node!(TupleExpr, SyntaxKind::TUPLE_EXPR);
ast_node!(VectExpr, SyntaxKind::VECT_EXPR);
ast_node!(MatrixExpr, SyntaxKind::MATRIX_EXPR);
ast_node!(MatrixRow, SyntaxKind::MATRIX_ROW);
ast_node!(Comprehension, SyntaxKind::COMPREHENSION);
ast_node!(Generator, SyntaxKind::GENERATOR);
ast_node!(ComprehensionIf, SyntaxKind::COMPREHENSION_IF);
ast_node!(CallExpr, SyntaxKind::CALL_EXPR);
ast_node!(IndexExpr, SyntaxKind::INDEX_EXPR);
ast_node!(DotCallExpr, SyntaxKind::DOT_CALL_EXPR);
ast_node!(CurlyExpr, SyntaxKind::CURLY_EXPR);
ast_node!(Braces, SyntaxKind::BRACES);
ast_node!(ArgList, SyntaxKind::ARG_LIST);
ast_node!(KeywordArg, SyntaxKind::KEYWORD_ARG);
ast_node!(Parameters, SyntaxKind::PARAMETERS);
ast_node!(TypeAnnotation, SyntaxKind::TYPE_ANNOTATION);
ast_node!(WhereExpr, SyntaxKind::WHERE_EXPR);
ast_node!(SplatExpr, SyntaxKind::SPLAT_EXPR);
ast_node!(EndMarker, SyntaxKind::END_MARKER);
ast_node!(AssignmentExpr, SyntaxKind::ASSIGNMENT_EXPR);
ast_node!(ArrowExpr, SyntaxKind::ARROW_EXPR);
ast_node!(TernaryExpr, SyntaxKind::TERNARY_EXPR);
ast_node!(IfExpr, SyntaxKind::IF_EXPR);
ast_node!(ElseifClause, SyntaxKind::ELSEIF_CLAUSE);
ast_node!(ElseClause, SyntaxKind::ELSE_CLAUSE);
ast_node!(Condition, SyntaxKind::CONDITION);
ast_node!(FunctionDef, SyntaxKind::FUNCTION_DEF);
ast_node!(Signature, SyntaxKind::SIGNATURE);
ast_node!(Block, SyntaxKind::BLOCK);
ast_node!(BeginExpr, SyntaxKind::BEGIN_EXPR);
ast_node!(QuoteExpr, SyntaxKind::QUOTE_EXPR);
ast_node!(WhileExpr, SyntaxKind::WHILE_EXPR);
ast_node!(ForExpr, SyntaxKind::FOR_EXPR);
ast_node!(ForBinding, SyntaxKind::FOR_BINDING);
ast_node!(LetExpr, SyntaxKind::LET_EXPR);
ast_node!(LetBindings, SyntaxKind::LET_BINDINGS);
ast_node!(TryExpr, SyntaxKind::TRY_EXPR);
ast_node!(CatchClause, SyntaxKind::CATCH_CLAUSE);
ast_node!(FinallyClause, SyntaxKind::FINALLY_CLAUSE);
ast_node!(StructDef, SyntaxKind::STRUCT_DEF);
ast_node!(ModuleDef, SyntaxKind::MODULE_DEF);
ast_node!(DoExpr, SyntaxKind::DO_EXPR);
ast_node!(DoParams, SyntaxKind::DO_PARAMS);
ast_node!(ReturnExpr, SyntaxKind::RETURN_EXPR);
ast_node!(BreakExpr, SyntaxKind::BREAK_EXPR);
ast_node!(ContinueExpr, SyntaxKind::CONTINUE_EXPR);
ast_node!(ConstStmt, SyntaxKind::CONST_STMT);
ast_node!(GlobalStmt, SyntaxKind::GLOBAL_STMT);
ast_node!(LocalStmt, SyntaxKind::LOCAL_STMT);
ast_node!(ImportStmt, SyntaxKind::IMPORT_STMT);
ast_node!(UsingStmt, SyntaxKind::USING_STMT);
ast_node!(ExportStmt, SyntaxKind::EXPORT_STMT);
ast_node!(MacroCall, SyntaxKind::MACRO_CALL);
ast_node!(MacroName, SyntaxKind::MACRO_NAME);
impl Name {
pub fn ident(&self) -> Option<SyntaxToken> {
self.0
.children_with_tokens()
.filter_map(|e| e.into_token())
.find(|t| t.kind() == SyntaxKind::IDENT)
}
}
impl StringLiteral {
pub fn prefix(&self) -> Option<SyntaxToken> {
support::token(&self.0, SyntaxKind::STRING_PREFIX)
}
pub fn suffix(&self) -> Option<SyntaxToken> {
support::token(&self.0, SyntaxKind::STRING_SUFFIX)
}
pub fn interpolations(&self) -> impl Iterator<Item = Interpolation> {
support::children(&self.0)
}
}
impl CmdLiteral {
pub fn prefix(&self) -> Option<SyntaxToken> {
support::token(&self.0, SyntaxKind::STRING_PREFIX)
}
pub fn suffix(&self) -> Option<SyntaxToken> {
support::token(&self.0, SyntaxKind::STRING_SUFFIX)
}
pub fn interpolations(&self) -> impl Iterator<Item = Interpolation> {
support::children(&self.0)
}
}
impl Interpolation {
pub fn ident(&self) -> Option<SyntaxToken> {
support::token(&self.0, SyntaxKind::IDENT)
}
pub fn expr(&self) -> Option<SyntaxNode> {
self.0.children().next()
}
}
impl BinaryExpr {
pub fn op_token(&self) -> Option<SyntaxToken> {
self.0
.children_with_tokens()
.filter_map(|e| e.into_token())
.find(|t| is_operator_kind(t.kind()))
}
}
impl CallExpr {
pub fn arg_list(&self) -> Option<ArgList> {
support::child(&self.0)
}
}
impl MacroCall {
pub fn name(&self) -> Option<MacroName> {
support::child(&self.0)
}
pub fn arg_list(&self) -> Option<ArgList> {
support::child(&self.0)
}
}
impl MacroName {
pub fn macro_token(&self) -> Option<SyntaxToken> {
self.0
.children_with_tokens()
.filter_map(|e| e.into_token())
.filter(|t| matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::DOT))
.last()
}
}
impl CurlyExpr {
pub fn arg_list(&self) -> Option<ArgList> {
support::child(&self.0)
}
}
impl DotCallExpr {
pub fn arg_list(&self) -> Option<ArgList> {
support::child(&self.0)
}
}
impl TypeAnnotation {
pub fn op_token(&self) -> Option<SyntaxToken> {
self.0
.children_with_tokens()
.filter_map(|e| e.into_token())
.find(|t| t.kind() == SyntaxKind::COLON_COLON)
}
}
impl KeywordArg {
pub fn name(&self) -> Option<Name> {
support::child(&self.0)
}
}
impl IfExpr {
pub fn condition(&self) -> Option<Condition> {
support::child(&self.0)
}
}
impl FunctionDef {
pub fn signature(&self) -> Option<Signature> {
support::child(&self.0)
}
}
impl DoExpr {
pub fn params(&self) -> Option<DoParams> {
support::child(&self.0)
}
}
fn is_operator_kind(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::PLUS
| SyntaxKind::MINUS
| SyntaxKind::STAR
| SyntaxKind::SLASH
| SyntaxKind::BACKSLASH
| SyntaxKind::CARET
| SyntaxKind::PERCENT
| SyntaxKind::EQ_EQ
| SyntaxKind::NOT_EQ
| SyntaxKind::EQ_EQ_EQ
| SyntaxKind::NOT_EQ_EQ
| SyntaxKind::LT
| SyntaxKind::LE
| SyntaxKind::GT
| SyntaxKind::GE
| SyntaxKind::AND_AND
| SyntaxKind::OR_OR
| SyntaxKind::DOT_AND_AND
| SyntaxKind::DOT_OR_OR
| SyntaxKind::COLON
| SyntaxKind::DOT_DOT
| SyntaxKind::COLON_COLON
| SyntaxKind::SUBTYPE
| SyntaxKind::SUPERTYPE
| SyntaxKind::DOT
| SyntaxKind::PIPE_GT
| SyntaxKind::DOT_PLUS
| SyntaxKind::DOT_MINUS
| SyntaxKind::DOT_STAR
| SyntaxKind::DOT_SLASH
| SyntaxKind::DOT_BACKSLASH
| SyntaxKind::DOT_CARET
| SyntaxKind::DOT_PERCENT
| SyntaxKind::DOT_EQ_EQ
| SyntaxKind::DOT_NOT_EQ
| SyntaxKind::DOT_EQ_EQ_EQ
| SyntaxKind::DOT_NOT_EQ_EQ
| SyntaxKind::DOT_LT
| SyntaxKind::DOT_LE
| SyntaxKind::DOT_GT
| SyntaxKind::DOT_GE
)
}