use compactp_syntax::{SyntaxKind, SyntaxNode, SyntaxToken};
use crate::nodes::{Block, GenericArgList, ParamList, Type};
use crate::{AstNode, support};
macro_rules! ast_node {
(
$(#[$meta:meta])*
$name:ident => $kind:ident
) => {
$(#[$meta])*
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct $name(pub(crate) SyntaxNode);
impl AstNode for $name {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::$kind
}
fn cast(node: SyntaxNode) -> Option<Self> {
if Self::can_cast(node.kind()) {
Some(Self(node))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
};
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Expr {
Literal(LiteralExpr),
Name(NameExpr),
Ternary(TernaryExpr),
Binary(BinaryExpr),
Unary(UnaryExpr),
Cast(CastExpr),
Call(CallExpr),
Member(MemberExpr),
Index(IndexExpr),
Array(ArrayExpr),
Bytes(BytesExpr),
Spread(SpreadExpr),
Struct(StructExpr),
Default(DefaultExpr),
Map(MapExpr),
Fold(FoldExpr),
Disclose(DiscloseExpr),
Pad(PadExpr),
Slice(SliceExpr),
Lambda(LambdaExpr),
Paren(ParenExpr),
}
impl AstNode for Expr {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::LITERAL_EXPR
| SyntaxKind::NAME_EXPR
| SyntaxKind::TERNARY_EXPR
| SyntaxKind::BINARY_EXPR
| SyntaxKind::UNARY_EXPR
| SyntaxKind::CAST_EXPR
| SyntaxKind::CALL_EXPR
| SyntaxKind::MEMBER_EXPR
| SyntaxKind::INDEX_EXPR
| SyntaxKind::ARRAY_EXPR
| SyntaxKind::BYTES_EXPR
| SyntaxKind::SPREAD_EXPR
| SyntaxKind::STRUCT_EXPR
| SyntaxKind::DEFAULT_EXPR
| SyntaxKind::MAP_EXPR
| SyntaxKind::FOLD_EXPR
| SyntaxKind::DISCLOSE_EXPR
| SyntaxKind::PAD_EXPR
| SyntaxKind::SLICE_EXPR
| SyntaxKind::LAMBDA_EXPR
| SyntaxKind::PAREN_EXPR
)
}
fn cast(node: SyntaxNode) -> Option<Self> {
match node.kind() {
SyntaxKind::LITERAL_EXPR => Some(Self::Literal(LiteralExpr(node))),
SyntaxKind::NAME_EXPR => Some(Self::Name(NameExpr(node))),
SyntaxKind::TERNARY_EXPR => Some(Self::Ternary(TernaryExpr(node))),
SyntaxKind::BINARY_EXPR => Some(Self::Binary(BinaryExpr(node))),
SyntaxKind::UNARY_EXPR => Some(Self::Unary(UnaryExpr(node))),
SyntaxKind::CAST_EXPR => Some(Self::Cast(CastExpr(node))),
SyntaxKind::CALL_EXPR => Some(Self::Call(CallExpr(node))),
SyntaxKind::MEMBER_EXPR => Some(Self::Member(MemberExpr(node))),
SyntaxKind::INDEX_EXPR => Some(Self::Index(IndexExpr(node))),
SyntaxKind::ARRAY_EXPR => Some(Self::Array(ArrayExpr(node))),
SyntaxKind::BYTES_EXPR => Some(Self::Bytes(BytesExpr(node))),
SyntaxKind::SPREAD_EXPR => Some(Self::Spread(SpreadExpr(node))),
SyntaxKind::STRUCT_EXPR => Some(Self::Struct(StructExpr(node))),
SyntaxKind::DEFAULT_EXPR => Some(Self::Default(DefaultExpr(node))),
SyntaxKind::MAP_EXPR => Some(Self::Map(MapExpr(node))),
SyntaxKind::FOLD_EXPR => Some(Self::Fold(FoldExpr(node))),
SyntaxKind::DISCLOSE_EXPR => Some(Self::Disclose(DiscloseExpr(node))),
SyntaxKind::PAD_EXPR => Some(Self::Pad(PadExpr(node))),
SyntaxKind::SLICE_EXPR => Some(Self::Slice(SliceExpr(node))),
SyntaxKind::LAMBDA_EXPR => Some(Self::Lambda(LambdaExpr(node))),
SyntaxKind::PAREN_EXPR => Some(Self::Paren(ParenExpr(node))),
_ => None,
}
}
fn syntax(&self) -> &SyntaxNode {
match self {
Self::Literal(n) => &n.0,
Self::Name(n) => &n.0,
Self::Ternary(n) => &n.0,
Self::Binary(n) => &n.0,
Self::Unary(n) => &n.0,
Self::Cast(n) => &n.0,
Self::Call(n) => &n.0,
Self::Member(n) => &n.0,
Self::Index(n) => &n.0,
Self::Array(n) => &n.0,
Self::Bytes(n) => &n.0,
Self::Spread(n) => &n.0,
Self::Struct(n) => &n.0,
Self::Default(n) => &n.0,
Self::Map(n) => &n.0,
Self::Fold(n) => &n.0,
Self::Disclose(n) => &n.0,
Self::Pad(n) => &n.0,
Self::Slice(n) => &n.0,
Self::Lambda(n) => &n.0,
Self::Paren(n) => &n.0,
}
}
}
ast_node! {
LiteralExpr => LITERAL_EXPR
}
ast_node! {
NameExpr => NAME_EXPR
}
impl NameExpr {
pub fn ident(&self) -> Option<SyntaxToken> {
support::child_token(&self.0, SyntaxKind::IDENT)
}
}
ast_node! {
TernaryExpr => TERNARY_EXPR
}
impl TernaryExpr {
pub fn question(&self) -> Option<SyntaxToken> {
support::child_token(&self.0, SyntaxKind::QUESTION)
}
}
ast_node! {
BinaryExpr => BINARY_EXPR
}
impl BinaryExpr {
pub fn op(&self) -> Option<SyntaxToken> {
self.0
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|t| {
matches!(
t.kind(),
SyntaxKind::PLUS
| SyntaxKind::MINUS
| SyntaxKind::STAR
| SyntaxKind::SLASH
| SyntaxKind::EQ_EQ
| SyntaxKind::BANG_EQ
| SyntaxKind::LT
| SyntaxKind::LT_EQ
| SyntaxKind::GT
| SyntaxKind::GT_EQ
| SyntaxKind::AMP_AMP
| SyntaxKind::PIPE_PIPE
)
})
}
}
ast_node! {
UnaryExpr => UNARY_EXPR
}
impl UnaryExpr {
pub fn op(&self) -> Option<SyntaxToken> {
support::child_token(&self.0, SyntaxKind::BANG)
}
}
ast_node! {
CastExpr => CAST_EXPR
}
impl CastExpr {
pub fn ty(&self) -> Option<Type> {
support::child_node(&self.0)
}
}
ast_node! {
CallExpr => CALL_EXPR
}
impl CallExpr {
pub fn name(&self) -> Option<SyntaxToken> {
support::child_token(&self.0, SyntaxKind::IDENT)
}
pub fn generic_args(&self) -> Option<GenericArgList> {
support::child_node(&self.0)
}
}
ast_node! {
MemberExpr => MEMBER_EXPR
}
impl MemberExpr {
pub fn field(&self) -> Option<SyntaxToken> {
support::child_token(&self.0, SyntaxKind::IDENT)
}
}
ast_node! {
IndexExpr => INDEX_EXPR
}
ast_node! {
ArrayExpr => ARRAY_EXPR
}
ast_node! {
BytesExpr => BYTES_EXPR
}
ast_node! {
SpreadExpr => SPREAD_EXPR
}
ast_node! {
StructExpr => STRUCT_EXPR
}
impl StructExpr {
pub fn name(&self) -> Option<SyntaxToken> {
support::child_token(&self.0, SyntaxKind::IDENT)
}
pub fn field_inits(&self) -> impl Iterator<Item = StructFieldInit> {
support::children_nodes(&self.0)
}
pub fn update(&self) -> Option<StructUpdate> {
support::child_node(&self.0)
}
}
ast_node! {
StructFieldInit => STRUCT_FIELD_INIT
}
impl StructFieldInit {
pub fn name(&self) -> Option<SyntaxToken> {
support::child_token(&self.0, SyntaxKind::IDENT)
}
}
ast_node! {
StructUpdate => STRUCT_UPDATE
}
ast_node! {
DefaultExpr => DEFAULT_EXPR
}
impl DefaultExpr {
pub fn ty(&self) -> Option<Type> {
support::child_node(&self.0)
}
}
ast_node! {
MapExpr => MAP_EXPR
}
ast_node! {
FoldExpr => FOLD_EXPR
}
ast_node! {
DiscloseExpr => DISCLOSE_EXPR
}
ast_node! {
PadExpr => PAD_EXPR
}
ast_node! {
SliceExpr => SLICE_EXPR
}
impl SliceExpr {
pub fn generic_args(&self) -> Option<GenericArgList> {
support::child_node(&self.0)
}
}
ast_node! {
LambdaExpr => LAMBDA_EXPR
}
impl LambdaExpr {
pub fn param_list(&self) -> Option<ParamList> {
support::child_node(&self.0)
}
pub fn return_type(&self) -> Option<Type> {
support::child_node(&self.0)
}
pub fn body_block(&self) -> Option<Block> {
support::child_node(&self.0)
}
}
ast_node! {
ParenExpr => PAREN_EXPR
}