From 6d6e0b8f21385d008eb6161b56a98da2eac141a2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 21 Sep 2021 15:52:11 +0200 Subject: [PATCH] Generate ast nodes for each ast trait --- crates/hir/src/semantics.rs | 2 +- crates/hir_def/src/attr.rs | 36 +- crates/syntax/src/ast.rs | 4 +- crates/syntax/src/ast/generated/nodes.rs | 398 +++++++++++++++++++++++ crates/syntax/src/ast/node_ext.rs | 30 -- crates/syntax/src/tests/sourcegen_ast.rs | 61 ++++ 6 files changed, 480 insertions(+), 51 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 9821d9d4fa5..f5a8da24938 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -481,7 +481,7 @@ impl<'db> SemanticsImpl<'db> { ) } - // This might not be the correct way to due this, but it works for now + // This might not be the correct way to do this, but it works for now fn descend_node_into_attributes(&self, node: N) -> SmallVec<[N; 1]> { let mut res = smallvec![]; let tokens = (|| { diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index f8cc940486d..0470b9510f3 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -411,47 +411,47 @@ impl AttrsWithOwner { let file_id = id.parent.file_id(db); let root = db.parse_or_expand(file_id).unwrap(); let owner = match &map[id.local_id] { - Either::Left(it) => ast::AttrsOwnerNode::new(it.to_node(&root)), - Either::Right(it) => ast::AttrsOwnerNode::new(it.to_node(&root)), + Either::Left(it) => ast::DynAttrsOwner::new(it.to_node(&root)), + Either::Right(it) => ast::DynAttrsOwner::new(it.to_node(&root)), }; InFile::new(file_id, owner) } AttrDefId::AdtId(adt) => match adt { - AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), - AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), - AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), + AdtId::StructId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), + AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), + AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), }, - AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), + AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), AttrDefId::EnumVariantId(id) => { let map = db.variants_attrs_source_map(id.parent); let file_id = id.parent.lookup(db).id.file_id(); let root = db.parse_or_expand(file_id).unwrap(); - InFile::new(file_id, ast::AttrsOwnerNode::new(map[id.local_id].to_node(&root))) + InFile::new(file_id, ast::DynAttrsOwner::new(map[id.local_id].to_node(&root))) } - AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), - AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), - AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), - AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), + AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), + AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), + AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), + AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), AttrDefId::MacroDefId(id) => id.ast_id().either( - |it| it.with_value(ast::AttrsOwnerNode::new(it.to_node(db.upcast()))), - |it| it.with_value(ast::AttrsOwnerNode::new(it.to_node(db.upcast()))), + |it| it.with_value(ast::DynAttrsOwner::new(it.to_node(db.upcast()))), + |it| it.with_value(ast::DynAttrsOwner::new(it.to_node(db.upcast()))), ), - AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), + AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new), AttrDefId::GenericParamId(id) => match id { GenericParamId::TypeParamId(id) => { id.parent.child_source(db).map(|source| match &source[id.local_id] { - Either::Left(id) => ast::AttrsOwnerNode::new(id.clone()), - Either::Right(id) => ast::AttrsOwnerNode::new(id.clone()), + Either::Left(id) => ast::DynAttrsOwner::new(id.clone()), + Either::Right(id) => ast::DynAttrsOwner::new(id.clone()), }) } GenericParamId::LifetimeParamId(id) => id .parent .child_source(db) - .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())), + .map(|source| ast::DynAttrsOwner::new(source[id.local_id].clone())), GenericParamId::ConstParamId(id) => id .parent .child_source(db) - .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())), + .map(|source| ast::DynAttrsOwner::new(source[id.local_id].clone())), }, }; diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index e26c5b7ad90..7c9200f5688 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs @@ -21,8 +21,8 @@ pub use self::{ expr_ext::{ArrayExprKind, Effect, ElseBranch, LiteralKind}, generated::{nodes::*, tokens::*}, node_ext::{ - AttrKind, AttrsOwnerNode, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, - SelfParamKind, SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, + AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind, + SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, }, operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, token_ext::{ diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 205d01e974e..5c80dc8346f 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1445,6 +1445,46 @@ pub enum GenericParam { TypeParam(TypeParam), } impl ast::AttrsOwner for GenericParam {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynArgListOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::ArgListOwner for DynArgListOwner {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynAttrsOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for DynAttrsOwner {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynGenericParamsOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::GenericParamsOwner for DynGenericParamsOwner {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynLoopBodyOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::LoopBodyOwner for DynLoopBodyOwner {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynModuleItemOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::ModuleItemOwner for DynModuleItemOwner {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynNameOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::NameOwner for DynNameOwner {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynTypeBoundsOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::TypeBoundsOwner for DynTypeBoundsOwner {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynVisibilityOwner { + pub(crate) syntax: SyntaxNode, +} +impl ast::VisibilityOwner for DynVisibilityOwner {} impl AstNode for Name { fn can_cast(kind: SyntaxKind) -> bool { kind == NAME } fn cast(syntax: SyntaxNode) -> Option { @@ -3564,6 +3604,364 @@ impl AstNode for GenericParam { } } } +impl DynArgListOwner { + #[inline] + pub fn new(node: T) -> DynArgListOwner { + DynArgListOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynArgListOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + CALL_EXPR | METHOD_CALL_EXPR => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + CALL_EXPR => DynArgListOwner { syntax }, + METHOD_CALL_EXPR => DynArgListOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl DynAttrsOwner { + #[inline] + pub fn new(node: T) -> DynAttrsOwner { + DynAttrsOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynAttrsOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + MACRO_CALL + | SOURCE_FILE + | CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | ITEM_LIST + | BLOCK_EXPR + | SELF_PARAM + | PARAM + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + | ASSOC_ITEM_LIST + | EXTERN_ITEM_LIST + | CONST_PARAM + | LIFETIME_PARAM + | TYPE_PARAM + | EXPR_STMT + | LET_STMT + | ARRAY_EXPR + | AWAIT_EXPR + | BIN_EXPR + | BOX_EXPR + | BREAK_EXPR + | CALL_EXPR + | CAST_EXPR + | CLOSURE_EXPR + | CONTINUE_EXPR + | EFFECT_EXPR + | FIELD_EXPR + | FOR_EXPR + | IF_EXPR + | INDEX_EXPR + | LITERAL + | LOOP_EXPR + | MATCH_EXPR + | METHOD_CALL_EXPR + | PAREN_EXPR + | PATH_EXPR + | PREFIX_EXPR + | RANGE_EXPR + | REF_EXPR + | RETURN_EXPR + | TRY_EXPR + | TUPLE_EXPR + | WHILE_EXPR + | YIELD_EXPR + | RECORD_EXPR_FIELD_LIST + | RECORD_EXPR_FIELD + | MATCH_ARM_LIST + | MATCH_ARM + | IDENT_PAT + | RECORD_PAT_FIELD => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + MACRO_CALL => DynAttrsOwner { syntax }, + SOURCE_FILE => DynAttrsOwner { syntax }, + CONST => DynAttrsOwner { syntax }, + ENUM => DynAttrsOwner { syntax }, + EXTERN_BLOCK => DynAttrsOwner { syntax }, + EXTERN_CRATE => DynAttrsOwner { syntax }, + FN => DynAttrsOwner { syntax }, + IMPL => DynAttrsOwner { syntax }, + MACRO_RULES => DynAttrsOwner { syntax }, + MACRO_DEF => DynAttrsOwner { syntax }, + MODULE => DynAttrsOwner { syntax }, + STATIC => DynAttrsOwner { syntax }, + STRUCT => DynAttrsOwner { syntax }, + TRAIT => DynAttrsOwner { syntax }, + TYPE_ALIAS => DynAttrsOwner { syntax }, + UNION => DynAttrsOwner { syntax }, + USE => DynAttrsOwner { syntax }, + ITEM_LIST => DynAttrsOwner { syntax }, + BLOCK_EXPR => DynAttrsOwner { syntax }, + SELF_PARAM => DynAttrsOwner { syntax }, + PARAM => DynAttrsOwner { syntax }, + RECORD_FIELD => DynAttrsOwner { syntax }, + TUPLE_FIELD => DynAttrsOwner { syntax }, + VARIANT => DynAttrsOwner { syntax }, + ASSOC_ITEM_LIST => DynAttrsOwner { syntax }, + EXTERN_ITEM_LIST => DynAttrsOwner { syntax }, + CONST_PARAM => DynAttrsOwner { syntax }, + LIFETIME_PARAM => DynAttrsOwner { syntax }, + TYPE_PARAM => DynAttrsOwner { syntax }, + EXPR_STMT => DynAttrsOwner { syntax }, + LET_STMT => DynAttrsOwner { syntax }, + ARRAY_EXPR => DynAttrsOwner { syntax }, + AWAIT_EXPR => DynAttrsOwner { syntax }, + BIN_EXPR => DynAttrsOwner { syntax }, + BOX_EXPR => DynAttrsOwner { syntax }, + BREAK_EXPR => DynAttrsOwner { syntax }, + CALL_EXPR => DynAttrsOwner { syntax }, + CAST_EXPR => DynAttrsOwner { syntax }, + CLOSURE_EXPR => DynAttrsOwner { syntax }, + CONTINUE_EXPR => DynAttrsOwner { syntax }, + EFFECT_EXPR => DynAttrsOwner { syntax }, + FIELD_EXPR => DynAttrsOwner { syntax }, + FOR_EXPR => DynAttrsOwner { syntax }, + IF_EXPR => DynAttrsOwner { syntax }, + INDEX_EXPR => DynAttrsOwner { syntax }, + LITERAL => DynAttrsOwner { syntax }, + LOOP_EXPR => DynAttrsOwner { syntax }, + MATCH_EXPR => DynAttrsOwner { syntax }, + METHOD_CALL_EXPR => DynAttrsOwner { syntax }, + PAREN_EXPR => DynAttrsOwner { syntax }, + PATH_EXPR => DynAttrsOwner { syntax }, + PREFIX_EXPR => DynAttrsOwner { syntax }, + RANGE_EXPR => DynAttrsOwner { syntax }, + REF_EXPR => DynAttrsOwner { syntax }, + RETURN_EXPR => DynAttrsOwner { syntax }, + TRY_EXPR => DynAttrsOwner { syntax }, + TUPLE_EXPR => DynAttrsOwner { syntax }, + WHILE_EXPR => DynAttrsOwner { syntax }, + YIELD_EXPR => DynAttrsOwner { syntax }, + RECORD_EXPR_FIELD_LIST => DynAttrsOwner { syntax }, + RECORD_EXPR_FIELD => DynAttrsOwner { syntax }, + MATCH_ARM_LIST => DynAttrsOwner { syntax }, + MATCH_ARM => DynAttrsOwner { syntax }, + IDENT_PAT => DynAttrsOwner { syntax }, + RECORD_PAT_FIELD => DynAttrsOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl DynGenericParamsOwner { + #[inline] + pub fn new(node: T) -> DynGenericParamsOwner { + DynGenericParamsOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynGenericParamsOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + ENUM => DynGenericParamsOwner { syntax }, + FN => DynGenericParamsOwner { syntax }, + IMPL => DynGenericParamsOwner { syntax }, + STRUCT => DynGenericParamsOwner { syntax }, + TRAIT => DynGenericParamsOwner { syntax }, + TYPE_ALIAS => DynGenericParamsOwner { syntax }, + UNION => DynGenericParamsOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl DynLoopBodyOwner { + #[inline] + pub fn new(node: T) -> DynLoopBodyOwner { + DynLoopBodyOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynLoopBodyOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + FOR_EXPR => DynLoopBodyOwner { syntax }, + LOOP_EXPR => DynLoopBodyOwner { syntax }, + WHILE_EXPR => DynLoopBodyOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl DynModuleItemOwner { + #[inline] + pub fn new(node: T) -> DynModuleItemOwner { + DynModuleItemOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynModuleItemOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + MACRO_ITEMS => DynModuleItemOwner { syntax }, + SOURCE_FILE => DynModuleItemOwner { syntax }, + ITEM_LIST => DynModuleItemOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl DynNameOwner { + #[inline] + pub fn new(node: T) -> DynNameOwner { + DynNameOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynNameOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT + | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM + | TYPE_PARAM | IDENT_PAT => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + CONST => DynNameOwner { syntax }, + ENUM => DynNameOwner { syntax }, + FN => DynNameOwner { syntax }, + MACRO_RULES => DynNameOwner { syntax }, + MACRO_DEF => DynNameOwner { syntax }, + MODULE => DynNameOwner { syntax }, + STATIC => DynNameOwner { syntax }, + STRUCT => DynNameOwner { syntax }, + TRAIT => DynNameOwner { syntax }, + TYPE_ALIAS => DynNameOwner { syntax }, + UNION => DynNameOwner { syntax }, + RENAME => DynNameOwner { syntax }, + SELF_PARAM => DynNameOwner { syntax }, + RECORD_FIELD => DynNameOwner { syntax }, + VARIANT => DynNameOwner { syntax }, + CONST_PARAM => DynNameOwner { syntax }, + TYPE_PARAM => DynNameOwner { syntax }, + IDENT_PAT => DynNameOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl DynTypeBoundsOwner { + #[inline] + pub fn new(node: T) -> DynTypeBoundsOwner { + DynTypeBoundsOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynTypeBoundsOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + ASSOC_TYPE_ARG => DynTypeBoundsOwner { syntax }, + TRAIT => DynTypeBoundsOwner { syntax }, + TYPE_ALIAS => DynTypeBoundsOwner { syntax }, + LIFETIME_PARAM => DynTypeBoundsOwner { syntax }, + TYPE_PARAM => DynTypeBoundsOwner { syntax }, + WHERE_PRED => DynTypeBoundsOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl DynVisibilityOwner { + #[inline] + pub fn new(node: T) -> DynVisibilityOwner { + DynVisibilityOwner { syntax: node.syntax().clone() } + } +} +impl AstNode for DynVisibilityOwner { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC + | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => { + true + } + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + CONST => DynVisibilityOwner { syntax }, + ENUM => DynVisibilityOwner { syntax }, + EXTERN_CRATE => DynVisibilityOwner { syntax }, + FN => DynVisibilityOwner { syntax }, + IMPL => DynVisibilityOwner { syntax }, + MACRO_RULES => DynVisibilityOwner { syntax }, + MACRO_DEF => DynVisibilityOwner { syntax }, + MODULE => DynVisibilityOwner { syntax }, + STATIC => DynVisibilityOwner { syntax }, + STRUCT => DynVisibilityOwner { syntax }, + TRAIT => DynVisibilityOwner { syntax }, + TYPE_ALIAS => DynVisibilityOwner { syntax }, + UNION => DynVisibilityOwner { syntax }, + USE => DynVisibilityOwner { syntax }, + RECORD_FIELD => DynVisibilityOwner { syntax }, + TUPLE_FIELD => DynVisibilityOwner { syntax }, + VARIANT => DynVisibilityOwner { syntax }, + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl std::fmt::Display for GenericArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 99ef5c264fe..1dce67da639 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -167,36 +167,6 @@ impl NameOwner for Macro { impl AttrsOwner for Macro {} -/// Basically an owned `dyn AttrsOwner` without extra boxing. -pub struct AttrsOwnerNode { - node: SyntaxNode, -} - -impl AttrsOwnerNode { - pub fn new(node: N) -> Self { - AttrsOwnerNode { node: node.syntax().clone() } - } -} - -impl AttrsOwner for AttrsOwnerNode {} -impl AstNode for AttrsOwnerNode { - fn can_cast(_: SyntaxKind) -> bool - where - Self: Sized, - { - false - } - fn cast(_: SyntaxNode) -> Option - where - Self: Sized, - { - None - } - fn syntax(&self) -> &SyntaxNode { - &self.node - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub enum AttrKind { Inner, diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index a6624a8ab12..71171c859b1 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -8,6 +8,7 @@ use std::{ fmt::Write, }; +use itertools::Itertools; use proc_macro2::{Punct, Spacing}; use quote::{format_ident, quote}; use ungrammar::{rust_grammar, Grammar, Rule}; @@ -208,6 +209,64 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { }) .unzip(); + let (dyn_node_defs, dyn_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar + .nodes + .iter() + .flat_map(|node| node.traits.iter().map(move |t| (t, node))) + .into_group_map() + .into_iter() + .sorted_by_key(|(k, _)| k.clone()) + .map(|(trait_name, nodes)| { + let name = format_ident!("Dyn{}", trait_name); + let trait_name = format_ident!("{}", trait_name); + let kinds: Vec<_> = nodes + .iter() + .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string()))) + .collect(); + + ( + quote! { + #[pretty_doc_comment_placeholder_workaround] + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + pub struct #name { + pub(crate) syntax: SyntaxNode, + } + impl ast::#trait_name for #name {} + }, + quote! { + impl #name { + #[inline] + pub fn new(node: T) -> #name { + #name { + syntax: node.syntax().clone() + } + } + } + impl AstNode for #name { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + #(#kinds)|* => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + #( + #kinds => #name { syntax }, + )* + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + } + }, + ) + }) + .unzip(); + let enum_names = grammar.enums.iter().map(|it| &it.name); let node_names = grammar.nodes.iter().map(|it| &it.name); @@ -244,8 +303,10 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { #(#node_defs)* #(#enum_defs)* + #(#dyn_node_defs)* #(#node_boilerplate_impls)* #(#enum_boilerplate_impls)* + #(#dyn_node_boilerplate_impls)* #(#display_impls)* };