#![allow(missing_docs)]
use cstree::interning::{Resolver, TokenKey};
use skullbrain_lexer::ModifierKind;
use crate::cst::utils::children;
use super::*;
define_cst_node! {
pub struct Break {
kind: SyntaxKind::LoopBreak,
child: [optional_expr => Expr],
tokens : [
break_token BreakToken => SyntaxKind::Keyword
],
}
}
define_cst_node! {
pub struct Continue {
kind: SyntaxKind::LoopContinue,
tokens: [
continue_token ContinueToken => SyntaxKind::Keyword
],
}
}
define_cst_node! {
pub struct Return {
kind: SyntaxKind::Return,
child: [optional_expr => Expr],
tokens: [
return_token ReturnToken => SyntaxKind::Keyword
],
}
}
define_cst_node! {
pub struct Throw {
kind: SyntaxKind::ThrowError,
child: [expr => Expr],
tokens: [
throw_token ThrowToken => SyntaxKind::Keyword
],
}
}
define_cst_node! {
pub struct BlockExpr {
kind : SyntaxKind::DelimitedRange,
nogen tokens: [
open_token OpenBraceToken => SyntaxKind::OpenBrace,
close_token CloseBraceToken => SyntaxKind::CloseBrace
],
}
}
impl BlockExpr {
pub fn exprs(&self) -> impl Iterator<Item = Expr> + use<'_> {
self.syntax.children_with_tokens().map(Expr::cast_element)
}
}
define_cst_node! {
pub struct ParenExpr {
kind : SyntaxKind::DelimitedRange,
nogen tokens: [
open_token OpenParenToken => SyntaxKind::OpenParen,
close_token CloseParenToken => SyntaxKind::CloseParen
],
}
}
impl ParenExpr {
pub fn exprs(&self) -> impl Iterator<Item = Expr> + use<'_> {
self.syntax.children_with_tokens().map(Expr::cast_element)
}
}
define_cst_node! {
pub struct Type {
kind: SyntaxKind::Type,
nogen tokens: [
ident IdentToken => SyntaxKind::Ident
],
forward: [
signature SyntaxKind::FunctionSignature => FunctionSignature
],
}
}
define_cst_node! {
pub struct FunctionSignature {
kind : SyntaxKind::FunctionSignature,
child : [return_ty => Type],
tokens: [
return_ty_token ReturnTypeToken => SyntaxKind::Arrow
],
}
}
define_cst_node! {
pub struct Parameters {}
}
impl FunctionSignature {
pub fn parameters(&self) -> Option<Parameters> {
utils::child::<ParenRange>(&self.syntax).map(|paren| Parameters {
syntax: paren.syntax,
})
}
pub fn open_brace_token(&self) -> Option<OpenParenToken> {
utils::child::<ParenRange>(&self.syntax)?.open_token()
}
pub fn close_brace_token(&self) -> Option<CloseParenToken> {
utils::child::<ParenRange>(&self.syntax)?.close_token()
}
}
pub enum CommaSeperated<T> {
Comma(CommaToken),
Item(T),
}
impl Parameters {
pub fn iter(&self) -> impl Iterator<Item = CommaSeperated<Parameter>> + '_ {
self.syntax
.children_with_tokens()
.filter_map(|it| match it {
cstree::util::NodeOrToken::Node(node) if Parameter::can_cast(node.kind()) => {
let Some(item) = Parameter::cast(node.clone()) else {
unreachable!()
};
Some(CommaSeperated::Item(item))
}
cstree::util::NodeOrToken::Token(tok) if CommaToken::can_cast(tok.kind()) => {
let Some(comma) = CommaToken::cast(tok.clone()) else {
unreachable!()
};
Some(CommaSeperated::Comma(comma))
}
_ => None,
})
}
}
define_cst_node! {
pub struct While {
kind: SyntaxKind::WhileLoop,
tokens: [
while_token WhileToken => SyntaxKind::Keyword
],
forward: [
body SyntaxKind::Body => BlockExpr,
condition SyntaxKind::Condition => ParenExpr
],
}
}
define_cst_node! {
pub struct ForLoop {
kind: SyntaxKind::ForLoop,
}
}
define_cst_token! {
pub struct ForIterOpenToken { kind : SyntaxKind::ForIterOpen}
}
define_cst_token! {
pub struct ForIterCloseToken { kind : SyntaxKind::ForIterClose}
}
impl ForLoop {
pub fn open_token(&self) -> Option<ForIterOpenToken> {
let value = children::<ParenRange>(&self.syntax).next()?.syntax;
utils::token::<ForIterOpenToken>(&value, SyntaxKind::ForIterOpen)
}
pub fn close_token(&self) -> Option<ForIterCloseToken> {
let value = children::<ParenRange>(&self.syntax).next()?.syntax;
utils::token::<ForIterCloseToken>(&value, SyntaxKind::ForIterClose)
}
pub fn body(&self) -> Option<BlockExpr> {
children(&self.syntax).last()
}
pub fn iter(&self) -> Option<ParenExpr> {
children(&self.syntax).next()
}
}
define_cst_node! {
pub struct TryCatch {
kind: SyntaxKind::TryCatch,
child: [try_arm => TryArm],
}
}
define_cst_node! {
pub struct TryArm {
kind : SyntaxKind::Try,
child:[block => BlockExpr],
tokens:[
try_token TryToken => SyntaxKind::Keyword
],
}
}
define_cst_node! {
pub struct CatchArm {
kind : SyntaxKind::Catch,
child:[catch_ty => CatchType,block => BlockExpr],
tokens:[
catch_token CatchToken => SyntaxKind::Keyword
],
}
}
define_cst_node! {
pub struct CatchType {
kind : SyntaxKind::Parameter,
child : [ty => Type,try_arm => TryArm],
nogen tokens : [
name IdentToken => SyntaxKind::Ident,
colon_token ColonToken => SyntaxKind::Colon
],
}
}
impl TryCatch {
pub fn catch_arms(&self) -> impl Iterator<Item = CatchArm> + use<'_> {
utils::children::<CatchArm>(&self.syntax)
}
}
define_cst_node! {
pub struct TypeAlias {
kind: SyntaxKind::TypeAlias,
child : [modifiers => Modifiers,aliased => Type],
tokens: [
alias_token AliasToken => SyntaxKind::Keyword
],
nogen tokens: [
assignment_token AssignmentToken => SyntaxKind::Assignment,
name IdentToken => SyntaxKind::Ident
],
}
}
define_cst_node! {
pub struct VariableStmt {
kind: SyntaxKind::VariableDeclaration,
child:[modifiers => Modifiers,initialiser => BlockExpr],
}
}
impl VariableStmt {
pub fn name(&self) -> Option<IdentToken> {
Parameter::forward_name_from(&self.syntax)
}
pub fn ty(&self) -> Option<Type> {
Parameter::forward_type_from(&self.syntax)
}
pub fn var_token(&self) -> VariableToken {
let Some(tok) = utils::token_with(&self.syntax, |k| {
matches!(
k,
SyntaxKind::MutableVariableKeyword | SyntaxKind::ImmutableVariableKeyword
)
}) else {
unreachable!()
};
VariableToken { token: tok.clone() }
}
}
define_cst_token! {
pub struct VariableToken {}
}
impl VariableToken {
pub fn is_mutable(&self) -> bool {
matches!(self.token.kind(), SyntaxKind::MutableVariableKeyword)
}
}
impl CstToken for VariableToken {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::MutableVariableKeyword | SyntaxKind::ImmutableVariableKeyword
)
}
fn cast(token: SyntaxToken) -> Option<Self> {
Self::can_cast(token.kind()).then(|| Self { token })
}
fn token(&self) -> &SyntaxToken {
&self.token
}
}
define_cst_node! {
pub struct Parameter {
kind: SyntaxKind::Parameter,
child :[ty => Type],
nogen tokens: [
name IdentToken => SyntaxKind::Ident,
colon_token ColonToken => SyntaxKind::Colon
],
}
}
impl Parameter {
fn forward_name_from(syntax: &SyntaxNode) -> Option<IdentToken> {
utils::child::<Parameter>(&syntax)?.name()
}
fn forward_type_from(syntax: &SyntaxNode) -> Option<Type> {
utils::child::<Parameter>(&syntax)?.ty()
}
}
define_cst_node! {
pub struct BinaryExpr {
forward: [
lhs SyntaxKind::Lhs => Expr,
rhs SyntaxKind::Rhs => Expr
],
}
}
define_cst_token! {
pub struct BinaryOp {}
}
impl BinaryExpr {
pub fn operator(&self) -> BinaryOp {
use SyntaxKind::*;
const fn is_op(it: SyntaxKind) -> bool {
matches!(
it,
OpEq | OpNotEq
| OpLt
| OpGt
| OpLtEq
| OpGtEq
| OpAnd
| OpOr
| OpMinus
| OpPlus
| OpMul
| OpDivide
| OpMod
)
}
let Some(tok) = utils::token_with(&self.syntax, is_op) else {
unreachable!()
};
BinaryOp { token: tok.clone() }
}
}
define_cst_node! {
pub struct UnaryExpr {
forward: [
expr SyntaxKind::Rhs => Expr
],
}
}
define_cst_token! {
pub struct UnaryOp {}
}
impl UnaryExpr {
pub fn operator(&self) -> UnaryOp {
use SyntaxKind::*;
const fn is_op(it: SyntaxKind) -> bool {
matches!(it, OpMinus | OpNot)
}
let Some(tok) = utils::token_with(&self.syntax, is_op) else {
unreachable!()
};
UnaryOp { token: tok.clone() }
}
}
define_cst_node! {
pub struct ChainExpr {
tokens : [
chaining_token ChainingToken => SyntaxKind::OpMethodChaining
],
forward: [
object SyntaxKind::Lhs => Expr,
method SyntaxKind::Rhs => Expr
],
}
}
define_cst_node! {
pub struct IfElse {
kind: SyntaxKind::IfElse,
child : [if_arm => IfArm],
}
}
define_cst_node! {
pub struct IfArm {
kind : SyntaxKind::If,
tokens:[
if_token IfToken => SyntaxKind::Keyword],
forward: [
body SyntaxKind::Body => BlockExpr,
condition SyntaxKind::Condition => ParenExpr
],
}
}
define_cst_node! {
pub struct ElseArm {
tokens:[
else_token ElseToken => SyntaxKind::Keyword],
forward: [
body SyntaxKind::Body => BlockExpr
],
}
}
define_cst_node! {
pub struct ElseIfArm {
forward: [
body SyntaxKind::Body => BlockExpr,
condition SyntaxKind::Condition => ParenExpr
],
}
}
pub enum ElseBranch {
Else(ElseArm),
ElseIf(ElseIfArm),
}
impl IfElse {
pub fn else_branches(&self) -> impl Iterator<Item = ElseBranch> + use<'_> {
utils::children::<ElseBranch>(&self.syntax)
}
}
impl ElseIfArm {
pub fn contains_else_if(&self) -> Option<()> {
let count_of_keywords = self
.syntax
.children_with_tokens()
.filter_map(|it| it.into_token())
.filter(|n| IdentToken::can_cast(n.kind()))
.count();
(count_of_keywords == 2).then_some(())
}
}
impl CstNode for ElseBranch {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(kind, SyntaxKind::Else)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
let count_of_keywords = syntax
.children_with_tokens()
.filter_map(|it| it.into_token())
.filter(|n| IdentToken::can_cast(n.kind()))
.count();
let res = match count_of_keywords {
1 => ElseBranch::Else(ElseArm { syntax }),
2 => ElseBranch::ElseIf(ElseIfArm { syntax }),
_ => unreachable!(),
};
Some(res)
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
match self {
ElseBranch::Else(else_arm) => &else_arm.syntax,
ElseBranch::ElseIf(else_if_arm) => &else_if_arm.syntax,
}
}
}
define_cst_node! {
pub struct Match {
kind: SyntaxKind::Match,
tokens: [
match_token MatchToken => SyntaxKind::Keyword
],
}
}
define_cst_node! {
pub struct MatchArmWithCondition {
kind: SyntaxKind::MatchCondition,
tokens:[arrow ArrowToken => SyntaxKind::Arrow],
forward: [
pat SyntaxKind::Condition => MatchPat,
body SyntaxKind::DelimitedRange => BlockExpr
],
}
}
define_cst_node! {
pub struct MatchPat {
nogen tokens:[
ident IdentToken => SyntaxKind::Ident,
lit LiteralToken => SyntaxKind::Literal
],
}
}
define_cst_node! {
pub struct MatchArmDefault {
kind: SyntaxKind::MatchConditionDefault,
nogen tokens:[arrow ArrowToken => SyntaxKind::Arrow],
forward: [
body SyntaxKind::DelimitedRange => BlockExpr
],
}
}
pub enum MatchArm {
WithCondition(MatchArmWithCondition),
Default(MatchArmDefault),
}
impl Match {
pub fn expr(&self) -> Option<ParenExpr> {
children(&self.syntax).next()
}
fn body(&self) -> Option<&SyntaxNode> {
self.syntax
.children()
.find(|i| BraceRange::can_cast(i.kind()))
}
pub fn body_open_token(&self) -> Option<OpenBraceToken> {
utils::token(self.body()?, SyntaxKind::OpenBrace)
}
pub fn body_close_token(&self) -> Option<CloseBraceToken> {
utils::token(self.body()?, SyntaxKind::CloseBrace)
}
pub fn match_arms(&self) -> Option<impl Iterator<Item = MatchArm> + use<'_>> {
Some(children(self.body()?))
}
pub fn disallowed_exprs(&self) -> Option<impl Iterator<Item = Expr> + use<'_>> {
Some(
self.body()?
.children_with_tokens()
.filter(|it| {
matches!(
it.kind(),
SyntaxKind::MatchCondition | SyntaxKind::MatchConditionDefault
)
})
.map(|it| Expr::cast_element(it.clone())),
)
}
}
impl CstNode for MatchArm {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::MatchCondition | SyntaxKind::MatchConditionDefault
)
}
fn syntax(&self) -> &SyntaxNode {
match self {
MatchArm::WithCondition(match_arm_with_condition) => &match_arm_with_condition.syntax,
MatchArm::Default(match_arm_default) => &match_arm_default.syntax,
}
}
fn cast(node: SyntaxNode) -> Option<Self> {
let res = match node.kind() {
SyntaxKind::MatchCondition => {
let Some(arm) = MatchArmWithCondition::cast(node) else {
unreachable!()
};
MatchArm::WithCondition(arm)
}
SyntaxKind::MatchConditionDefault => {
let Some(arm) = MatchArmDefault::cast(node) else {
unreachable!()
};
MatchArm::Default(arm)
}
_ => return None,
};
Some(res)
}
}
impl CstNode for MatchPat {
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
fn can_cast(kind: SyntaxKind) -> bool {
matches!(kind, SyntaxKind::Literal | SyntaxKind::Ident)
}
fn cast(node: SyntaxNode) -> Option<Self> {
Self::can_cast(node.kind()).then(|| Self { syntax: node })
}
}
define_cst_node! {
pub struct ImportStmt {
kind: SyntaxKind::Import,
child : [
source => ImportSource,
items => ImportItems
],
tokens: [
import_token ImportToken => SyntaxKind::Keyword
],
nogen tokens: [
alias_token AliasToken=> SyntaxKind::ImportAlias
],
}
}
define_cst_node! {
pub struct ImportItems {
kind: SyntaxKind::ImportItem,
nogen tokens: [
open_token OpenBraceToken => SyntaxKind::OpenBrace,
close_token CloseBraceToken => SyntaxKind::CloseBrace
],
}
}
define_cst_node! {
pub struct ImportSource {
kind : SyntaxKind::ImportSource,
nogen tokens : [
ident IdentToken => SyntaxKind::Ident,
path StringToken => SyntaxKind::Literal
],
}
}
impl ImportItems {
pub fn idents(&self) -> impl Iterator<Item = IdentToken> + use<'_> {
self.syntax
.children_with_tokens()
.filter_map(|it| it.into_token())
.filter_map(|i| IdentToken::cast(i.clone()))
}
}
define_cst_node! {
pub struct Modifiers {
kind: SyntaxKind::Modifiers,
}
}
impl Modifiers {
pub fn iter(&self) -> impl Iterator<Item = ModifierToken> + '_ {
self.syntax
.children_with_tokens()
.filter_map(|it| it.into_token())
.filter(|token| matches!(token.kind(), SyntaxKind::Keyword))
.map(|it| ModifierToken { token: it.clone() })
}
}
define_cst_token! {
pub struct ModifierToken {}
}
impl ModifierToken {
pub fn kind<I>(&self, resolver: &I) -> ModifierKind
where
I: Resolver<TokenKey> + ?Sized,
{
let text = self.token.resolve_text(resolver);
let Some(kind) = ModifierKind::from_token_repr(text) else {
unreachable!()
};
kind
}
}
define_cst_node! {
pub struct Class {
kind: SyntaxKind::Class,
child:[modifiers => Modifiers],
tokens: [
class_token ClassToken => SyntaxKind::Keyword
],
nogen tokens :[
name IdentToken => SyntaxKind::Ident
],
}
}
impl Class {
fn body(&self) -> Option<&SyntaxNode> {
self.syntax
.children()
.find(|i| BraceRange::can_cast(i.kind()))
}
pub fn body_open_tok(&self) -> Option<OpenBraceToken> {
utils::token(self.body()?, SyntaxKind::OpenBrace)
}
pub fn body_close_tok(&self) -> Option<CloseBraceToken> {
utils::token(self.body()?, SyntaxKind::CloseBrace)
}
pub fn methods(&self) -> Option<impl Iterator<Item = Function> + use<'_>> {
self.body().map(|syn| utils::children(&syn))
}
pub fn ty_aliasz(&self) -> Option<impl Iterator<Item = TypeAlias> + use<'_>> {
self.body().map(|syn| utils::children(&syn))
}
pub fn variables(&self) -> Option<impl Iterator<Item = VariableStmt> + use<'_>> {
self.body().map(|syn| utils::children(syn))
}
pub fn nested_impls(&self) -> Option<impl Iterator<Item = TraitImpl> + use<'_>> {
self.body().map(|syn| utils::children(syn))
}
pub fn implicit_init_exprs(&self) -> Option<impl Iterator<Item = Expr> + use<'_>> {
self.body().map(|syn| implicit_init_exprs(syn))
}
}
fn implicit_init_exprs<'a>(syntax: &'a SyntaxNode) -> impl Iterator<Item = Expr> + 'a {
syntax
.children_with_tokens()
.filter(move |i| {
matches!(
i.kind(),
SyntaxKind::Function
| SyntaxKind::VariableDeclaration
| SyntaxKind::Trait
| SyntaxKind::TraitImpl
| SyntaxKind::TypeAlias
| SyntaxKind::Enum
| SyntaxKind::EnumVariant
| SyntaxKind::Import
| SyntaxKind::ImportAlias
| SyntaxKind::ImportSource
| SyntaxKind::ImportItem
)
})
.map(|element| Expr::cast_element(element))
}
define_cst_node! {
pub struct TraitImpl {
kind: SyntaxKind::TraitImpl,
child: [modifiers => Modifiers],
tokens: [impl_token TraitImplToken => SyntaxKind::Keyword],
}
}
impl TraitImpl {
pub fn body_open_tok(&self) -> Option<OpenBraceToken> {
utils::token(self.body()?, SyntaxKind::OpenBrace)
}
pub fn body_close_tok(&self) -> Option<CloseBraceToken> {
utils::token(self.body()?, SyntaxKind::CloseBrace)
}
fn body(&self) -> Option<&SyntaxNode> {
self.syntax
.children()
.find(|i| BraceRange::can_cast(i.kind()))
}
pub fn methods(&self) -> Option<impl Iterator<Item = Function> + '_> {
self.body().map(|syntax| utils::children(syntax))
}
pub fn var_decls(&self) -> Option<impl Iterator<Item = VariableStmt> + '_> {
self.body().map(|syntax| utils::children(syntax))
}
pub fn type_aliases(&self) -> Option<impl Iterator<Item = TypeAlias> + '_> {
self.body().map(|syntax| utils::children(syntax))
}
pub fn implicit_init_exprs(&self) -> Option<impl Iterator<Item = Expr> + use<'_>> {
self.body().map(|syntax| implicit_init_exprs(syntax))
}
}
define_cst_node! {
pub struct Enum {
kind: SyntaxKind::Enum,
child:[modifiers => Modifiers],
tokens: [
enum_token EnumToken => SyntaxKind::Keyword
],
nogen tokens: [
name IdentToken => SyntaxKind::Ident
],
}
}
impl Enum {
pub fn variants(&self) -> impl Iterator<Item = EnumVariant> + use<'_> {
utils::children::<EnumVariant>(&self.syntax)
}
pub fn body_open_tok(&self) -> Option<OpenBraceToken> {
utils::token(self.body()?, SyntaxKind::OpenBrace)
}
pub fn body_close_tok(&self) -> Option<CloseBraceToken> {
utils::token(self.body()?, SyntaxKind::CloseBrace)
}
fn body(&self) -> Option<&SyntaxNode> {
self.syntax
.children()
.find(|i| BraceRange::can_cast(i.kind()))
}
pub fn implicit_init_exprs(&self) -> Option<impl Iterator<Item = Expr> + use<'_>> {
self.body().map(|syntax| implicit_init_exprs(syntax))
}
pub fn methods(&self) -> Option<impl Iterator<Item = Function> + use<'_>> {
self.body().map(|syntax| utils::children(syntax))
}
pub fn variables(&self) -> Option<impl Iterator<Item = VariableStmt> + use<'_>> {
self.body().map(|syntax| utils::children(syntax))
}
pub fn nested_impls(&self) -> Option<impl Iterator<Item = TraitImpl> + use<'_>> {
self.body().map(|syntax| utils::children(syntax))
}
pub fn ty_aliasz(&self) -> Option<impl Iterator<Item = TypeAlias> + use<'_>> {
self.body().map(|syn| utils::children(&syn))
}
}
define_cst_node! {
pub struct EnumVariant {
kind: SyntaxKind::EnumVariant,
child:[modifiers => Modifiers],
nogen tokens: [name IdentToken => SyntaxKind::Ident],
}
}
define_cst_node! {
pub struct EnumVariantField {
kind: SyntaxKind::Parameter,
child :[ty => Type],
nogen tokens: [name IdentToken => SyntaxKind::Ident,colon_token ColonToken => SyntaxKind::Colon ],
}
}
impl EnumVariant {
pub fn fields(&self) -> Option<impl Iterator<Item = EnumVariantField> + use<'_>> {
let syntax = self
.syntax
.children()
.find(|i| ParenRange::can_cast(i.kind()))?;
let children = children(syntax);
Some(children)
}
pub fn open_brace_token(&self) -> Option<OpenParenToken> {
utils::child::<ParenRange>(&self.syntax)?.open_token()
}
pub fn close_brace_token(&self) -> Option<CloseParenToken> {
utils::child::<ParenRange>(&self.syntax)?.close_token()
}
pub fn is_unit(&self) -> bool {
self.fields().is_some()
}
}
define_cst_node! {
pub(super) struct ParenRange {
kind: SyntaxKind::DelimitedRange,
nogen tokens: [
open_token OpenParenToken => SyntaxKind::OpenParen,
close_token CloseParenToken => SyntaxKind::CloseParen
],
}
}
define_cst_node! {
struct BraceRange {
kind: SyntaxKind::DelimitedRange,
}
}
define_cst_node! {
pub struct Trait {
kind: SyntaxKind::Trait,
child: [
modifiers => Modifiers
],
tokens: [
trait_token TraitToken => SyntaxKind::Keyword
],
nogen tokens: [
name IdentToken => SyntaxKind::Ident
],
}
}
impl Trait {
fn body(&self) -> Option<&SyntaxNode> {
self.syntax
.children()
.find(|i| BraceRange::can_cast(i.kind()))
}
pub fn open_brace_token(&self) -> Option<OpenParenToken> {
utils::child::<ParenRange>(self.body()?)?.open_token()
}
pub fn close_brace_token(&self) -> Option<CloseParenToken> {
utils::child::<ParenRange>(self.body()?)?.close_token()
}
pub fn functions(&self) -> Option<impl Iterator<Item = FunctionItem> + use<'_>> {
self.body().map(|syntax| children(syntax))
}
pub fn var_decls(&self) -> Option<impl Iterator<Item = VariableStmt> + use<'_>> {
self.body().map(|syntax| children(syntax))
}
pub fn type_aliases(&self) -> Option<impl Iterator<Item = TypeAlias> + '_> {
self.body().map(|syntax| children(syntax))
}
pub fn implicit_init_exprs(&self) -> Option<impl Iterator<Item = Expr> + use<'_>> {
self.body().map(|syntax| implicit_init_exprs(syntax))
}
}
define_cst_node! {
pub struct Function {
kind: SyntaxKind::Function,
child: [modifiers => Modifiers,body => BlockExpr],
tokens: [
fn_token FnToken => SyntaxKind::Keyword
],
nogen tokens: [
name IdentToken=> SyntaxKind::Ident
],
forward: [
signature SyntaxKind::FunctionSignature => FunctionSignature
],
}
}
define_cst_node! {
pub struct PartialFunction {
child: [modifiers => Modifiers],
nogen tokens: [
name IdentToken=> SyntaxKind::Ident,
fn_token FnToken => SyntaxKind::Keyword
],
forward: [
signature SyntaxKind::FunctionSignature => FunctionSignature
],
}
}
pub enum FunctionItem {
Full(Function),
Partial(PartialFunction),
}
impl FunctionItem {
pub fn modifiers(&self) -> Option<Modifiers> {
match self {
FunctionItem::Full(function) => function.modifiers(),
FunctionItem::Partial(partial_function) => partial_function.modifiers(),
}
}
pub fn name(&self) -> Option<IdentToken> {
match self {
FunctionItem::Full(function) => function.name(),
FunctionItem::Partial(partial_function) => partial_function.name(),
}
}
pub fn signature(&self) -> Option<FunctionSignature> {
match self {
FunctionItem::Full(function) => function.signature(),
FunctionItem::Partial(partial_function) => partial_function.signature(),
}
}
}
impl CstNode for FunctionItem {
fn can_cast(kind: SyntaxKind) -> bool {
Function::can_cast(kind)
}
fn cast(node: SyntaxNode) -> Option<Self> {
Self::can_cast(node.kind()).then(|| {
let function = Function { syntax: node };
match function.body() {
Some(_) => Self::Full(function),
None => Self::Partial(PartialFunction {
syntax: function.syntax,
}),
}
})
}
fn syntax(&self) -> &SyntaxNode {
match self {
FunctionItem::Full(function) => &function.syntax,
FunctionItem::Partial(partial_function) => &partial_function.syntax,
}
}
}
pub enum Fragment {
EnumVariant(EnumVariant),
Modifiers(Modifiers),
Unknown(UnknownToken),
MatchArm(MatchArm),
Generic {
syntax: SyntaxNode,
},
}