use crate::parser::{DeriveField, DeriveInput};
use darling::ast::Fields;
use proc_macro2::Span;
use quote::quote;
use syn::Ident;
impl DeriveInput {
fn generate_mark(&self, fields: &Fields<DeriveField>) -> proc_macro2::TokenStream {
let ident = self.ident.clone();
let ts_node_name = self.ts_node_name();
quote! {
impl<'a> crate::parser::FromTreeSitter<'a> for #ident {
fn from_node(node: tree_sitter::Node<'a>, ctx: &mut crate::parser::ParseContext<'a>) -> crate::error::ParserResult<Self> {
debug_assert_eq!(node.kind_id(), xidl_parser_derive::node_id!(#ts_node_name));
Ok(Self)
}
}
}
}
fn generate_unit_transparent(&self, fields: &Fields<DeriveField>) -> proc_macro2::TokenStream {
let ident = self.ident.clone();
let ts_node_name = self.ts_node_name();
quote! {
impl<'a> crate::parser::FromTreeSitter<'a> for #ident {
fn from_node(node: tree_sitter::Node<'a>, ctx: &mut crate::parser::ParseContext<'a>) -> crate::error::ParserResult<Self> {
debug_assert_eq!(node.kind_id(), xidl_parser_derive::node_id!(#ts_node_name));
Ok(Self(crate::parser::FromTreeSitter::from_node(node, ctx)?))
}
}
}
}
fn is_generate_unit_transparent(&self) -> bool {
match &self.data {
darling::ast::Data::Struct(f) => f.len() == 1 && self.transparent,
_ => false,
}
}
pub fn is_mark(&self) -> bool {
let is_marked_type = match &self.data {
darling::ast::Data::Enum(_) => false,
darling::ast::Data::Struct(fields) => fields.is_empty(),
};
is_marked_type || self.mark
}
pub fn generate_struct(&self, fields: &Fields<DeriveField>) -> proc_macro2::TokenStream {
let ident = self.ident.clone();
if self.is_mark() {
return self.generate_mark(fields);
}
if self.is_generate_unit_transparent() {
return self.generate_unit_transparent(fields);
}
let mut gen_declare = quote! {};
let mut gen_fields = quote! {};
let mut gen_self = quote! {};
let ident = self.ident.clone();
let ts_node_name = self.ts_node_name();
let is_unit_struct = fields.iter().any(|item| item.ident.is_none());
if is_unit_struct {
for (idx, field) in fields.iter().enumerate() {
let name = field
.ident
.clone()
.unwrap_or_else(|| Ident::new(&format!("field_{idx}"), Span::call_site()));
let ts_node_name = field.ts_node_name();
let condition = if field.transparent {
quote! {
_
}
} else {
quote! {
xidl_parser_derive::node_id!(#ts_node_name)
}
};
if field.is_vec() {
gen_declare.extend(quote! {
let mut #name = vec![];
});
gen_fields.extend(quote! {
#condition => {
#name.push(crate::parser::FromTreeSitter::from_node(ch, ctx)?);
}
});
} else {
gen_declare.extend(quote! {
let mut #name = None;
});
gen_fields.extend(quote! {
#condition => {
#name = Some(crate::parser::FromTreeSitter::from_node(ch, ctx)?);
}
});
}
if field.is_vec() {
gen_self.extend(quote! {
#name,
});
} else {
gen_self.extend(quote! {
#name.unwrap(),
});
}
}
let has_transparent = fields.iter().any(|f| f.transparent);
let default_branch = if has_transparent {
quote! {}
} else {
quote! {
_ => {}
}
};
return quote! {
impl<'a> crate::parser::FromTreeSitter<'a> for #ident {
fn from_node(node: tree_sitter::Node<'a>, ctx: &mut crate::parser::ParseContext<'a>) -> crate::error::ParserResult<Self> {
#gen_declare
for ch in node.children(&mut node.walk()) {
match ch.kind_id() {
#gen_fields
#default_branch
}
}
Ok(Self(
#gen_self
))
}
}
};
} else {
for (idx, field) in fields.iter().enumerate() {
let name = field
.ident
.clone()
.unwrap_or_else(|| Ident::new(&format!("field_{idx}"), Span::call_site()));
if field.is_span() {
gen_self.extend(quote! {
span: node.range(),
});
continue;
}
let ts_node_name = field.ts_node_name();
if ts_node_name.value() == "-" && field.is_text() {
gen_declare.extend(quote! {
let #name = ctx.node_text(&node)?.to_string();
});
gen_self.extend(quote! {
#name,
});
continue;
}
if field.is_vec() {
gen_declare.extend(quote! {
let mut #name = vec![];
});
} else {
gen_declare.extend(quote! {
let mut #name = None;
});
}
if field.is_text() {
gen_fields.extend(quote! {
xidl_parser_derive::node_id!(#ts_node_name) => {
#name = Some(ctx.node_text(&ch)?.to_string());
}
});
} else {
#[allow(clippy::collapsible_else_if)]
if field.is_vec() {
gen_fields.extend(quote! {
xidl_parser_derive::node_id!(#ts_node_name) => {
#name.push(crate::parser::FromTreeSitter::from_node(ch, ctx)?);
}
});
} else {
gen_fields.extend(quote! {
xidl_parser_derive::node_id!(#ts_node_name) => {
#name = Some(crate::parser::FromTreeSitter::from_node(ch, ctx)?);
}
});
}
}
if field.is_vec() || field.is_option() {
gen_self.extend(quote! {
#name,
});
continue;
}
if field.is_unit() {
gen_self.extend(quote! {
#name.unwrap(),
});
} else {
gen_self.extend(quote! {
#name: #name.unwrap(),
});
}
}
}
quote! {
impl<'a> crate::parser::FromTreeSitter<'a> for #ident {
fn from_node(node: tree_sitter::Node<'a>, ctx: &mut crate::parser::ParseContext<'a>) -> crate::error::ParserResult<Self> {
assert_eq!(node.kind_id(), xidl_parser_derive::node_id!(#ts_node_name));
#gen_declare
for ch in node.children(&mut node.walk()) {
match ch.kind_id() {
#gen_fields
_ => {}
}
}
Ok(Self {
#gen_self
})
}
}
}
}
}