trixy 0.4.0

A rust crate used to generate multi-language apis for your application
Documentation
/*
* Copyright (C) 2023 - 2024:
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is part of the Trixy crate for Trinitrix.
*
* Trixy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/

use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};

use crate::parser::command_spec::{
    Attribute, Enumeration, Function, Identifier, Namespace, Structure, Type, Variant,
};

impl Namespace {
    pub fn to_auxiliary_c(&self, namespaces: &Vec<&Identifier>) -> String {
        let mut nasps = namespaces.clone();
        if self.name.variant != Variant::RootNamespace {
            nasps.push(&self.name);
        }

        let structures: String = self
            .structures
            .iter()
            .map(Structure::to_auxiliary_c)
            .collect::<Vec<String>>()
            .join("\n");
        let enumerations: String = self
            .enumerations
            .iter()
            .map(Enumeration::to_auxiliary_c)
            .collect::<Vec<String>>()
            .join("\n");

        let results: String = self
            .select_types_pred(|(ident, _generics)| ident.name.as_str() == "Result")
            .iter()
            .map(|(ident, generics)| Type::to_auxilary_c_result(ident, generics).to_string())
            .collect::<Vec<String>>()
            .join("\n");
        let options: String = self
            .select_types_pred(|(ident, _generics)| ident.name.as_str() == "Option")
            .iter()
            .map(|(ident, generics)| Type::to_auxilary_c_option(ident, generics).to_string())
            .collect::<Vec<String>>()
            .join("\n");
        let vectors: String = self
            .select_types_pred(|(ident, _generics)| ident.name.as_str() == "Vec")
            .iter()
            .map(|(ident, generics)| Type::to_auxilary_c_vector(ident, generics).to_string())
            .collect::<Vec<String>>()
            .join("\n");

        let functions: String = self
            .functions
            .iter()
            .map(|r#fn| r#fn.to_auxiliary_c(&nasps))
            .collect::<Vec<String>>()
            .join("\n");
        let namespaces: String = self
            .namespaces
            .iter()
            .map(|nasp| nasp.to_auxiliary_c(&nasps))
            .collect();

        // FIXME: The option, result and vector types can depend on each other, and thus need to be
        // sorted so that all types that depend on one of the other ones come after it.
        // Using forward declaration does not work in this context, as we can't use pointer <2024-07-07>
        format! {"\
        {enumerations}\n\
        {structures}\n\
        {options}\n\
        {results}\n\
        {vectors}\n\
        {functions}\n\
        {namespaces}"}
    }

    pub fn to_auxiliary_c_full_struct_init(&self, namespaces: &Vec<&Identifier>) -> TokenStream2 {
        let mut input_namespaces = namespaces.clone();
        input_namespaces.push(&self.name);

        let ident = &self.name.to_rust();
        let type_ident = ident.clone();

        let functions: TokenStream2 = self
            .functions
            .iter()
            .map(|r#fn| r#fn.to_auxiliary_c_namespace_init(&input_namespaces))
            .collect();
        let namespaces: TokenStream2 = self
            .namespaces
            .iter()
            .map(Namespace::to_auxiliary_c_namespace_init)
            .collect();

        let next_namespace: TokenStream2 = self
            .namespaces
            .iter()
            .map(|nasp| nasp.to_auxiliary_c_full_struct_init(&input_namespaces))
            .collect();

        quote! {
            #next_namespace

            const struct #type_ident #ident = {
                #functions
                #namespaces
            };
        }
    }
    pub fn to_auxiliary_c_typedef(&self) -> TokenStream2 {
        let ident = &self.name.to_rust();
        let type_ident = ident.clone();

        quote! {
            struct #type_ident #ident;
        }
    }
    pub fn to_auxiliary_c_full_typedef(&self) -> String {
        let ident = format_ident!("{}", self.name.name);
        let doc_comments: String = Attribute::to_auxiliary_c_merged(&self.attributes);

        let functions: TokenStream2 = self
            .functions
            .iter()
            .map(Function::to_auxiliary_c_typedef)
            .collect();
        let namespaces: TokenStream2 = self
            .namespaces
            .iter()
            .map(Namespace::to_auxiliary_c_typedef)
            .collect();
        let next_namespace: String = self
            .namespaces
            .iter()
            .map(Namespace::to_auxiliary_c_full_typedef)
            .collect::<Vec<String>>()
            .join("\n");

        let namespace = quote! {
            struct #ident {
                #functions
                #namespaces
            };
        };
        format! {"{}\n{}{}\n", next_namespace, doc_comments, namespace}
    }

    pub fn to_auxiliary_c_namespace_init(&self) -> TokenStream2 {
        let ident = self.name.to_rust();

        quote! {
            . #ident = #ident ,
        }
    }
}