fix(macros): Generate namespacesed types and convertible impls
This commit is contained in:
parent
5fe757f829
commit
8b02d13dae
|
@ -29,16 +29,23 @@ use convert_case::{Case, Casing};
|
|||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
use trixy_parser::command_spec::{
|
||||
Attribute, CommandSpec, DocIdentifier, DocNamedType, Enumeration, Function, Identifier,
|
||||
Namespace, Structure,
|
||||
CommandSpec, Enumeration, Function, Identifier, Namespace, Structure,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
config::TrixyConfig,
|
||||
generate::{identifier_to_rust, named_type_to_rust},
|
||||
generate::{
|
||||
attribute_to_rust,
|
||||
c_api::{mangle_c_type_identifier, type_variant_c_path},
|
||||
convertible_derive::{
|
||||
rust_enumeration_into_impl, structure_convertable_derive, structure_into_impl,
|
||||
},
|
||||
doc_identifier_to_rust, doc_named_type_to_rust, identifier_to_rust, named_type_to_rust,
|
||||
type_variant_rust_path,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{c_api::type_to_c_equalivalent, function_identifier_to_rust};
|
||||
use super::{c_api::type_to_c_equivalent, function_identifier_to_rust};
|
||||
|
||||
thread_local! {static DEBUG: OnceCell<TokenStream2> = OnceCell::new();}
|
||||
|
||||
|
@ -66,13 +73,13 @@ thread_local! {static DEBUG: OnceCell<TokenStream2> = OnceCell::new();}
|
|||
/// }
|
||||
/// pub mod trinitrix {
|
||||
/// #[allow(non_camel_case_types)]
|
||||
/// #[derive(Debug, Convertible)]
|
||||
/// #[derive(Debug)]
|
||||
/// struct Callback {
|
||||
/// func: String,
|
||||
/// timeout: String,
|
||||
/// }
|
||||
/// #[allow(non_camel_case_types)]
|
||||
/// #[derive(Debug, Convertible)]
|
||||
/// #[derive(Debug)]
|
||||
/// enum CallbackPriority {
|
||||
/// High,
|
||||
/// Medium,
|
||||
|
@ -122,9 +129,6 @@ pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
|
|||
let debug = get_debug_sate();
|
||||
|
||||
quote! {
|
||||
#[allow(unused_imports)]
|
||||
use trixy::types::traits::convert_trait::*;
|
||||
|
||||
#structures
|
||||
#enumerations
|
||||
#debug
|
||||
|
@ -145,7 +149,7 @@ fn namespace_to_module(namespace: &Namespace, namespaces: &Vec<&Identifier>) ->
|
|||
let doc_comments: TokenStream2 = namespace
|
||||
.attributes
|
||||
.iter()
|
||||
.map(attribute_to_doc_comment)
|
||||
.map(|attr| attribute_to_rust(&namespace.name, attr))
|
||||
.collect();
|
||||
let structures: TokenStream2 = namespace.structures.iter().map(structure_to_rust).collect();
|
||||
let enumerations: TokenStream2 = namespace
|
||||
|
@ -173,9 +177,6 @@ fn namespace_to_module(namespace: &Namespace, namespaces: &Vec<&Identifier>) ->
|
|||
quote! {
|
||||
#doc_comments
|
||||
pub mod #ident {
|
||||
#[allow(unused_imports)]
|
||||
use trixy::types::traits::convert_trait::*;
|
||||
|
||||
#structures
|
||||
#enumerations
|
||||
#debug
|
||||
|
@ -196,14 +197,6 @@ fn namespace_to_module_enum(namespace: &Namespace) -> TokenStream2 {
|
|||
}
|
||||
}
|
||||
|
||||
fn attribute_to_doc_comment(attribute: &Attribute) -> TokenStream2 {
|
||||
let Attribute::doc(doc_comment) = attribute;
|
||||
|
||||
quote! {
|
||||
#[doc = #doc_comment]
|
||||
}
|
||||
}
|
||||
|
||||
fn get_debug_sate() -> TokenStream2 {
|
||||
let debug = DEBUG.with(|d| {
|
||||
d.get()
|
||||
|
@ -217,11 +210,11 @@ fn function_to_rust(function: &Function, namespaces: &[&Identifier]) -> TokenStr
|
|||
let doc_comments: TokenStream2 = function
|
||||
.attributes
|
||||
.iter()
|
||||
.map(attribute_to_doc_comment)
|
||||
.map(|attr| attribute_to_rust(&function.identifier, attr))
|
||||
.collect();
|
||||
let function_ident =
|
||||
function_identifier_to_rust(&function, named_type_to_rust, move |r#type| {
|
||||
let ident = type_to_c_equalivalent(r#type, namespaces);
|
||||
let ident = type_to_c_equivalent(r#type);
|
||||
quote! {
|
||||
trixy::oneshot::Sender<#ident>
|
||||
}
|
||||
|
@ -238,8 +231,9 @@ fn enumeration_to_rust(enumeration: &Enumeration) -> TokenStream2 {
|
|||
let doc_comments: TokenStream2 = enumeration
|
||||
.attributes
|
||||
.iter()
|
||||
.map(attribute_to_doc_comment)
|
||||
.map(|attr| attribute_to_rust(&enumeration.identifier, attr))
|
||||
.collect();
|
||||
|
||||
let ident = identifier_to_rust(&enumeration.identifier);
|
||||
let states: Vec<TokenStream2> = enumeration
|
||||
.states
|
||||
|
@ -249,15 +243,31 @@ fn enumeration_to_rust(enumeration: &Enumeration) -> TokenStream2 {
|
|||
|
||||
let debug = get_debug_sate();
|
||||
|
||||
let paired_type = {
|
||||
let path = type_variant_c_path(&enumeration.identifier.variant);
|
||||
|
||||
let ident = mangle_c_type_identifier(&enumeration.identifier);
|
||||
if path.is_empty() {
|
||||
quote! {
|
||||
crate :: #ident
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#path :: #ident
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let convertible = rust_enumeration_into_impl(&enumeration, &paired_type);
|
||||
|
||||
quote! {
|
||||
#doc_comments
|
||||
#[allow(non_camel_case_types)]
|
||||
#debug
|
||||
#[repr(C)]
|
||||
#[derive(Convertible)]
|
||||
pub enum #ident {
|
||||
#(#states),*
|
||||
}
|
||||
#convertible
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,14 +275,30 @@ fn structure_to_rust(structure: &Structure) -> TokenStream2 {
|
|||
let doc_comments: TokenStream2 = structure
|
||||
.attributes
|
||||
.iter()
|
||||
.map(attribute_to_doc_comment)
|
||||
.map(|attr| attribute_to_rust(&structure.identifier, attr))
|
||||
.collect();
|
||||
|
||||
let ident = identifier_to_rust(&structure.identifier);
|
||||
let c_ident = {
|
||||
let path = type_variant_c_path(&structure.identifier.variant);
|
||||
let ident = mangle_c_type_identifier(&structure.identifier);
|
||||
if path.is_empty() {
|
||||
quote! {
|
||||
crate :: #ident
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#path :: #ident
|
||||
}
|
||||
}
|
||||
};
|
||||
let contents: Vec<TokenStream2> = structure
|
||||
.contents
|
||||
.iter()
|
||||
.map(doc_named_type_to_rust)
|
||||
.collect();
|
||||
let convertible = structure_convertable_derive(&structure, &c_ident);
|
||||
let into_impl = structure_into_impl(&structure, &c_ident);
|
||||
|
||||
let debug = get_debug_sate();
|
||||
|
||||
|
@ -280,37 +306,10 @@ fn structure_to_rust(structure: &Structure) -> TokenStream2 {
|
|||
#doc_comments
|
||||
#[allow(non_camel_case_types)]
|
||||
#debug
|
||||
#[repr(C)]
|
||||
#[derive(Convertible)]
|
||||
pub struct #ident {
|
||||
#(#contents),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_identifier_to_rust(doc_identifier: &DocIdentifier) -> TokenStream2 {
|
||||
let doc_comments: TokenStream2 = doc_identifier
|
||||
.attributes
|
||||
.iter()
|
||||
.map(attribute_to_doc_comment)
|
||||
.collect();
|
||||
let identifier = identifier_to_rust(&doc_identifier.into());
|
||||
|
||||
quote! {
|
||||
#doc_comments
|
||||
#identifier
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_named_type_to_rust(doc_named_type: &DocNamedType) -> TokenStream2 {
|
||||
let doc_comments: TokenStream2 = doc_named_type
|
||||
.attributes
|
||||
.iter()
|
||||
.map(attribute_to_doc_comment)
|
||||
.collect();
|
||||
let named_type = named_type_to_rust(&doc_named_type.into());
|
||||
quote! {
|
||||
#doc_comments
|
||||
#named_type
|
||||
#convertible
|
||||
#into_impl
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,19 @@
|
|||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
use trixy_parser::command_spec::{CommandSpec, Function, Identifier, NamedType, Type};
|
||||
use trixy_parser::command_spec::{
|
||||
Attribute, CommandSpec, DocIdentifier, DocNamedType, Function, Identifier, NamedType, Type,
|
||||
Variant,
|
||||
};
|
||||
|
||||
use crate::config::TrixyConfig;
|
||||
|
||||
pub mod c_api;
|
||||
pub mod convertible_derive;
|
||||
pub mod host;
|
||||
|
||||
pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
|
||||
|
@ -97,20 +103,142 @@ fn named_type_to_rust(named_type: &NamedType) -> TokenStream2 {
|
|||
}
|
||||
fn type_to_rust(r#type: &Type) -> TokenStream2 {
|
||||
let ident = identifier_to_rust(&r#type.identifier);
|
||||
if r#type.generic_args.is_empty() {
|
||||
if r#type.identifier.name == "str" {
|
||||
let namespaces_path = type_variant_rust_path(&r#type.identifier.variant);
|
||||
|
||||
let nasp_path = if let Some(nasp_path) = type_variant_rust_path(&r#type.identifier.variant) {
|
||||
if nasp_path.is_empty() {
|
||||
quote! {
|
||||
&str
|
||||
crate ::
|
||||
}
|
||||
} else {
|
||||
let path = namespaces_path;
|
||||
quote! {
|
||||
#ident
|
||||
#path ::
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
if r#type.generic_args.is_empty() {
|
||||
quote! {
|
||||
#nasp_path #ident
|
||||
}
|
||||
} else {
|
||||
let generics: Vec<TokenStream2> = r#type.generic_args.iter().map(type_to_rust).collect();
|
||||
quote! {
|
||||
#ident <#(#generics),*>
|
||||
#nasp_path #ident <#(#generics),*>
|
||||
}
|
||||
}
|
||||
}
|
||||
fn doc_identifier_to_rust(doc_identifier: &DocIdentifier) -> TokenStream2 {
|
||||
let doc_comments: TokenStream2 = doc_identifier
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|attr| attribute_to_rust(&doc_identifier.into(), attr))
|
||||
.collect();
|
||||
let identifier = identifier_to_rust(&doc_identifier.into());
|
||||
|
||||
quote! {
|
||||
#doc_comments
|
||||
#identifier
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_named_type_to_rust(doc_named_type: &DocNamedType) -> TokenStream2 {
|
||||
let doc_comments: TokenStream2 = doc_named_type
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|attr| attribute_to_rust(&&doc_named_type.name, attr))
|
||||
.collect();
|
||||
let named_type = named_type_to_rust(&doc_named_type.into());
|
||||
quote! {
|
||||
#doc_comments
|
||||
pub #named_type
|
||||
}
|
||||
}
|
||||
fn attribute_to_rust(_target: &Identifier, attribute: &Attribute) -> TokenStream2 {
|
||||
match attribute {
|
||||
Attribute::doc(comment) => quote! {
|
||||
#[doc = #comment]
|
||||
},
|
||||
Attribute::error => quote! {
|
||||
// We simply use thiserror here
|
||||
#[derive(trixy::__private::thiserror::Error)]
|
||||
},
|
||||
Attribute::msg(msg) => quote! {
|
||||
#[error(#msg)]
|
||||
},
|
||||
Attribute::derive(_) => unimplemented!("Derive is not used as of now"),
|
||||
}
|
||||
}
|
||||
pub fn type_variant_rust_path(variant: &Variant) -> Option<TokenStream2> {
|
||||
fn namespace_to_borrowed(vec: &Vec<Identifier>) -> Vec<&Identifier> {
|
||||
let vec_2: Vec<&Identifier> = vec.iter().collect();
|
||||
vec_2
|
||||
}
|
||||
|
||||
let main_namespace;
|
||||
match variant {
|
||||
Variant::Structure { namespace } => {
|
||||
main_namespace = namespace_to_borrowed(namespace);
|
||||
}
|
||||
Variant::Enumeration { namespace } => {
|
||||
main_namespace = namespace_to_borrowed(namespace);
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
Some(namespaces_to_path(&main_namespace[..]))
|
||||
}
|
||||
fn namespaces_to_path<T: Deref<Target = Identifier>>(namespaces: &[T]) -> TokenStream2 {
|
||||
namespaces
|
||||
.iter()
|
||||
.fold(TokenStream2::default(), |acc, nasp| {
|
||||
if nasp.variant == Variant::RootNamespace && nasp.name == "<root>" {
|
||||
if acc.is_empty() {
|
||||
quote! {
|
||||
crate
|
||||
}
|
||||
} else {
|
||||
unreachable!("An root namespace can never come, after another namespcae")
|
||||
}
|
||||
} else {
|
||||
let ident = format_ident!("{}", nasp.name);
|
||||
if acc.is_empty() {
|
||||
quote! {
|
||||
crate :: #ident
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#acc :: #ident
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
fn namespaces_to_path_expansive(namespaces: &[Identifier]) -> TokenStream2 {
|
||||
namespaces
|
||||
.iter()
|
||||
.fold(TokenStream2::default(), |acc, nasp| {
|
||||
if nasp.variant == Variant::RootNamespace && nasp.name == "<root>" {
|
||||
if acc.is_empty() {
|
||||
quote! {
|
||||
crate
|
||||
}
|
||||
} else {
|
||||
unreachable!("An root namespace can never come, after another namespcae")
|
||||
}
|
||||
} else {
|
||||
let ident = format_ident!("{}", nasp.name);
|
||||
if acc.is_empty() {
|
||||
quote! {
|
||||
crate :: #ident
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#acc :: #ident
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Reference in New Issue