xidl-parser-derive 0.71.1

A IDL codegen.
Documentation
use crate::parser::{DeriveInput, DerivedVariant};
use quote::{ToTokens, quote};

impl DeriveInput {
    pub fn generate_variant(&self, fields: &[DerivedVariant]) -> proc_macro2::TokenStream {
        assert!(!self.mark, "variant cannot be marked");

        let ident = self.ident.clone();

        let has_unit = fields
            .iter()
            .any(|v| v.fields.style == darling::ast::Style::Unit);
        let has_tuple = fields
            .iter()
            .any(|v| v.fields.style == darling::ast::Style::Tuple);

        let using_id = !has_unit;

        let mut gen_variants = quote! {};
        for variant in fields {
            let variant_ident = &variant.ident;
            let ts_node_name = variant.ts_node_name();
            let ts_node_id = if using_id {
                quote! { xidl_parser_derive::node_id!(#ts_node_name) }
            } else {
                quote! { #ts_node_name }
            };

            match &variant.fields.style {
                darling::ast::Style::Unit => {
                    gen_variants.extend(quote! {
                        #ts_node_id => Ok(Self::#variant_ident),
                    });
                }
                darling::ast::Style::Tuple => {
                    let fields = &variant.fields.fields;
                    if fields.len() == 1 {
                        let field = &fields[0];
                        let is_text =
                            field.text || field.ty.to_token_stream().to_string() == "String";
                        if is_text {
                            gen_variants.extend(quote! {
                                #ts_node_id => {
                                    Ok(Self::#variant_ident(ctx.node_text(&ch)?.to_string()))
                                }
                            });
                        } else {
                            gen_variants.extend(quote! {
                            #ts_node_id => {
                                Ok(Self::#variant_ident(crate::parser::FromTreeSitter::from_node(ch, ctx)?))
                            }
                        });
                        }
                    }
                }
                darling::ast::Style::Struct => {}
            }
        }

        if self.transparent {
            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> {
                        let ch = node;
                        match node.kind_id() {
                            #gen_variants
                            _ => Err(crate::error::ParseError::UnexpectedNode(node.kind().to_string()))
                        }
                    }
                }
            }
        } else {
            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> {
                        for ch in node.children(&mut node.walk()) {
                            return match ch.kind_id() {
                                #gen_variants
                                _ => Err(crate::error::ParseError::UnexpectedNode(format!("parent: {}, got: {}", node.kind(), ch.kind())))
                            }
                        }
                        unreachable!()
                    }
                }
            }
        }
    }
}