Group generated ast boilerplate apart from the interesting part

This commit is contained in:
veetaha 2020-04-18 23:51:13 +03:00
parent b949500126
commit 972d3b2ba3
2 changed files with 1659 additions and 1649 deletions

File diff suppressed because it is too large Load diff

View file

@ -63,7 +63,10 @@ fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> {
} }
fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
let nodes = grammar.nodes.iter().map(|node| { let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
.nodes
.iter()
.map(|node| {
let name = format_ident!("{}", node.name); let name = format_ident!("{}", node.name);
let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); let kind = format_ident!("{}", to_upper_snake_case(&name.to_string()));
let traits = node.traits.iter().map(|trait_name| { let traits = node.traits.iter().map(|trait_name| {
@ -97,13 +100,20 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
} }
}); });
(
quote! { quote! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct #name { pub struct #name {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
} }
#(#traits)*
impl #name {
#(#methods)*
}
},
quote! {
impl AstNode for #name { impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool { fn can_cast(kind: SyntaxKind) -> bool {
kind == #kind kind == #kind
@ -113,33 +123,36 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
fn syntax(&self) -> &SyntaxNode { &self.syntax } fn syntax(&self) -> &SyntaxNode { &self.syntax }
} }
},
)
})
.unzip();
#(#traits)* let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
.enums
impl #name { .iter()
#(#methods)* .map(|en| {
} let variants: Vec<_> = en.variants.iter().map(|var| format_ident!("{}", var)).collect();
}
});
let enums = grammar.enums.iter().map(|en| {
let variants = en.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>();
let name = format_ident!("{}", en.name); let name = format_ident!("{}", en.name);
let kinds = variants let kinds: Vec<_> = variants
.iter() .iter()
.map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string()))) .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
.collect::<Vec<_>>(); .collect();
let traits = en.traits.iter().map(|trait_name| { let traits = en.traits.iter().map(|trait_name| {
let trait_name = format_ident!("{}", trait_name); let trait_name = format_ident!("{}", trait_name);
quote!(impl ast::#trait_name for #name {}) quote!(impl ast::#trait_name for #name {})
}); });
(
quote! { quote! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum #name { pub enum #name {
#(#variants(#variants),)* #(#variants(#variants),)*
} }
#(#traits)*
},
quote! {
#( #(
impl From<#variants> for #name { impl From<#variants> for #name {
fn from(node: #variants) -> #name { fn from(node: #variants) -> #name {
@ -172,17 +185,16 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
} }
} }
},
)
})
.unzip();
#(#traits)* let enum_names = grammar.enums.iter().map(|it| it.name);
} let node_names = grammar.nodes.iter().map(|it| it.name);
});
let displays = grammar let display_impls =
.enums enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
.iter()
.map(|it| format_ident!("{}", it.name))
.chain(grammar.nodes.iter().map(|it| format_ident!("{}", it.name)))
.map(|name| {
quote! { quote! {
impl std::fmt::Display for #name { impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
@ -192,13 +204,13 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
}); });
let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect(); let defined_nodes: HashSet<_> = node_names.collect();
for node in kinds for node in kinds
.nodes .nodes
.iter() .iter()
.map(|kind| to_pascal_case(*kind)) .map(|kind| to_pascal_case(kind))
.filter(|name| !defined_nodes.contains(&**name)) .filter(|name| !defined_nodes.contains(name.as_str()))
{ {
eprintln!("Warning: node {} not defined in ast source", node); eprintln!("Warning: node {} not defined in ast source", node);
} }
@ -210,9 +222,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
T, T,
}; };
#(#nodes)* #(#node_defs)*
#(#enums)* #(#enum_defs)*
#(#displays)* #(#node_boilerplate_impls)*
#(#enum_boilerplate_impls)*
#(#display_impls)*
}; };
let ast = ast.to_string().replace("T ! [ ", "T![").replace(" ] )", "])"); let ast = ast.to_string().replace("T ! [ ", "T![").replace(" ] )", "])");
@ -380,20 +394,16 @@ fn to_pascal_case(s: &str) -> String {
impl Field<'_> { impl Field<'_> {
fn is_many(&self) -> bool { fn is_many(&self) -> bool {
match self { matches!(self, Field::Node { src: FieldSrc::Many(_), .. })
Field::Node { src: FieldSrc::Many(_), .. } => true,
_ => false,
}
} }
fn token_kind(&self) -> Option<proc_macro2::TokenStream> { fn token_kind(&self) -> Option<proc_macro2::TokenStream> {
let res = match self { match self {
Field::Token(token) => { Field::Token(token) => {
let token: proc_macro2::TokenStream = token.parse().unwrap(); let token: proc_macro2::TokenStream = token.parse().unwrap();
quote! { T![#token] } Some(quote! { T![#token] })
}
_ => None,
} }
_ => return None,
};
Some(res)
} }
fn method_name(&self) -> proc_macro2::Ident { fn method_name(&self) -> proc_macro2::Ident {
match self { match self {