lwb-parser 0.1.7

parser framwork with automatically generated ASTs for the LWB project
Documentation
use crate::codegen::error::CodegenError;
use crate::codegen::sanitize_identifier;
use crate::parser::peg::parser_sugar_ast::{Annotation, SyntaxFileAst};
use itertools::Itertools;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

pub fn generate_trait_impls(syntax: &SyntaxFileAst) -> Result<TokenStream, CodegenError> {
    let mut impls = Vec::new();

    for sort in syntax.sorts.values() {
        if sort.annotations.contains(&Annotation::Hidden) {
            continue;
        }

        let sortname = format_ident!("{}", sanitize_identifier(&sort.name));
        let sortname_str = &sort.name;

        let constructor_names = sort
            .constructors
            .iter()
            .filter(|i| !i.dont_put_in_ast)
            .filter(|i| {
                !i.annotations
                    .iter()
                    .any(|i| matches!(i, Annotation::Error(_)))
            })
            .map(|i| format_ident!("{}", sanitize_identifier(&i.name)))
            .collect_vec();

        let constructor_names_str = sort
            .constructors
            .iter()
            .filter(|i| !i.dont_put_in_ast)
            .filter(|i| {
                !i.annotations
                    .iter()
                    .any(|i| matches!(i, Annotation::Error(_)))
            })
            .map(|i| i.name.as_str())
            .collect_vec();

        let (ast_info_body, constructor_body) = if constructor_names.len() == 1 {
            let constructor_name_str = &constructor_names_str[0];
            (
                quote!(
                    let Self (meta, ..) = self;
                    meta
                ),
                quote!(
                    #constructor_name_str
                ),
            )
        } else {
            (
                quote!(
                    match self {
                        #(
                            Self::#constructor_names (meta, ..) => meta
                        ),*,
                        _ => unreachable!()
                    }
                ),
                quote!(
                    match self {
                        #(
                            Self::#constructor_names (..) => #constructor_names_str
                        ),*,
                        _ => unreachable!()
                    }
                ),
            )
        };

        impls.push(quote!(
            impl<M: AstInfo> AstNode<M> for #sortname<M> {
                fn ast_info(&self) -> &M {
                    #ast_info_body
                }

                fn constructor(&self) -> &'static str {
                    #constructor_body
                }

                fn sort(&self) -> &'static str {
                    #sortname_str
                }
            }
        ));
    }

    Ok(quote!(
        use super::prelude::*;

        #(#impls)*
    ))
}