fix(macros): Generate namespacesed types and convertible impls
This commit is contained in:
parent
fa26bdfc6c
commit
5aaa2b43f3
|
@ -29,16 +29,23 @@ use convert_case::{Case, Casing};
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use trixy_parser::command_spec::{
|
use trixy_parser::command_spec::{
|
||||||
Attribute, CommandSpec, DocIdentifier, DocNamedType, Enumeration, Function, Identifier,
|
CommandSpec, Enumeration, Function, Identifier, Namespace, Structure,
|
||||||
Namespace, Structure,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::TrixyConfig,
|
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();}
|
thread_local! {static DEBUG: OnceCell<TokenStream2> = OnceCell::new();}
|
||||||
|
|
||||||
|
@ -66,13 +73,13 @@ thread_local! {static DEBUG: OnceCell<TokenStream2> = OnceCell::new();}
|
||||||
/// }
|
/// }
|
||||||
/// pub mod trinitrix {
|
/// pub mod trinitrix {
|
||||||
/// #[allow(non_camel_case_types)]
|
/// #[allow(non_camel_case_types)]
|
||||||
/// #[derive(Debug, Convertible)]
|
/// #[derive(Debug)]
|
||||||
/// struct Callback {
|
/// struct Callback {
|
||||||
/// func: String,
|
/// func: String,
|
||||||
/// timeout: String,
|
/// timeout: String,
|
||||||
/// }
|
/// }
|
||||||
/// #[allow(non_camel_case_types)]
|
/// #[allow(non_camel_case_types)]
|
||||||
/// #[derive(Debug, Convertible)]
|
/// #[derive(Debug)]
|
||||||
/// enum CallbackPriority {
|
/// enum CallbackPriority {
|
||||||
/// High,
|
/// High,
|
||||||
/// Medium,
|
/// Medium,
|
||||||
|
@ -122,9 +129,6 @@ pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
|
||||||
let debug = get_debug_sate();
|
let debug = get_debug_sate();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(unused_imports)]
|
|
||||||
use trixy::types::traits::convert_trait::*;
|
|
||||||
|
|
||||||
#structures
|
#structures
|
||||||
#enumerations
|
#enumerations
|
||||||
#debug
|
#debug
|
||||||
|
@ -145,7 +149,7 @@ fn namespace_to_module(namespace: &Namespace, namespaces: &Vec<&Identifier>) ->
|
||||||
let doc_comments: TokenStream2 = namespace
|
let doc_comments: TokenStream2 = namespace
|
||||||
.attributes
|
.attributes
|
||||||
.iter()
|
.iter()
|
||||||
.map(attribute_to_doc_comment)
|
.map(|attr| attribute_to_rust(&namespace.name, attr))
|
||||||
.collect();
|
.collect();
|
||||||
let structures: TokenStream2 = namespace.structures.iter().map(structure_to_rust).collect();
|
let structures: TokenStream2 = namespace.structures.iter().map(structure_to_rust).collect();
|
||||||
let enumerations: TokenStream2 = namespace
|
let enumerations: TokenStream2 = namespace
|
||||||
|
@ -173,9 +177,6 @@ fn namespace_to_module(namespace: &Namespace, namespaces: &Vec<&Identifier>) ->
|
||||||
quote! {
|
quote! {
|
||||||
#doc_comments
|
#doc_comments
|
||||||
pub mod #ident {
|
pub mod #ident {
|
||||||
#[allow(unused_imports)]
|
|
||||||
use trixy::types::traits::convert_trait::*;
|
|
||||||
|
|
||||||
#structures
|
#structures
|
||||||
#enumerations
|
#enumerations
|
||||||
#debug
|
#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 {
|
fn get_debug_sate() -> TokenStream2 {
|
||||||
let debug = DEBUG.with(|d| {
|
let debug = DEBUG.with(|d| {
|
||||||
d.get()
|
d.get()
|
||||||
|
@ -217,11 +210,11 @@ fn function_to_rust(function: &Function, namespaces: &[&Identifier]) -> TokenStr
|
||||||
let doc_comments: TokenStream2 = function
|
let doc_comments: TokenStream2 = function
|
||||||
.attributes
|
.attributes
|
||||||
.iter()
|
.iter()
|
||||||
.map(attribute_to_doc_comment)
|
.map(|attr| attribute_to_rust(&function.identifier, attr))
|
||||||
.collect();
|
.collect();
|
||||||
let function_ident =
|
let function_ident =
|
||||||
function_identifier_to_rust(&function, named_type_to_rust, move |r#type| {
|
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! {
|
quote! {
|
||||||
trixy::oneshot::Sender<#ident>
|
trixy::oneshot::Sender<#ident>
|
||||||
}
|
}
|
||||||
|
@ -238,8 +231,9 @@ fn enumeration_to_rust(enumeration: &Enumeration) -> TokenStream2 {
|
||||||
let doc_comments: TokenStream2 = enumeration
|
let doc_comments: TokenStream2 = enumeration
|
||||||
.attributes
|
.attributes
|
||||||
.iter()
|
.iter()
|
||||||
.map(attribute_to_doc_comment)
|
.map(|attr| attribute_to_rust(&enumeration.identifier, attr))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let ident = identifier_to_rust(&enumeration.identifier);
|
let ident = identifier_to_rust(&enumeration.identifier);
|
||||||
let states: Vec<TokenStream2> = enumeration
|
let states: Vec<TokenStream2> = enumeration
|
||||||
.states
|
.states
|
||||||
|
@ -249,15 +243,31 @@ fn enumeration_to_rust(enumeration: &Enumeration) -> TokenStream2 {
|
||||||
|
|
||||||
let debug = get_debug_sate();
|
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! {
|
quote! {
|
||||||
#doc_comments
|
#doc_comments
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#debug
|
#debug
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Convertible)]
|
|
||||||
pub enum #ident {
|
pub enum #ident {
|
||||||
#(#states),*
|
#(#states),*
|
||||||
}
|
}
|
||||||
|
#convertible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,14 +275,30 @@ fn structure_to_rust(structure: &Structure) -> TokenStream2 {
|
||||||
let doc_comments: TokenStream2 = structure
|
let doc_comments: TokenStream2 = structure
|
||||||
.attributes
|
.attributes
|
||||||
.iter()
|
.iter()
|
||||||
.map(attribute_to_doc_comment)
|
.map(|attr| attribute_to_rust(&structure.identifier, attr))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let ident = identifier_to_rust(&structure.identifier);
|
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
|
let contents: Vec<TokenStream2> = structure
|
||||||
.contents
|
.contents
|
||||||
.iter()
|
.iter()
|
||||||
.map(doc_named_type_to_rust)
|
.map(doc_named_type_to_rust)
|
||||||
.collect();
|
.collect();
|
||||||
|
let convertible = structure_convertable_derive(&structure, &c_ident);
|
||||||
|
let into_impl = structure_into_impl(&structure, &c_ident);
|
||||||
|
|
||||||
let debug = get_debug_sate();
|
let debug = get_debug_sate();
|
||||||
|
|
||||||
|
@ -280,37 +306,10 @@ fn structure_to_rust(structure: &Structure) -> TokenStream2 {
|
||||||
#doc_comments
|
#doc_comments
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#debug
|
#debug
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Convertible)]
|
|
||||||
pub struct #ident {
|
pub struct #ident {
|
||||||
#(#contents),*
|
#(#contents),*
|
||||||
}
|
}
|
||||||
}
|
#convertible
|
||||||
}
|
#into_impl
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,19 @@
|
||||||
* If not, see <https://www.gnu.org/licenses/>.
|
* If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::{format_ident, quote};
|
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;
|
use crate::config::TrixyConfig;
|
||||||
|
|
||||||
pub mod c_api;
|
pub mod c_api;
|
||||||
|
pub mod convertible_derive;
|
||||||
pub mod host;
|
pub mod host;
|
||||||
|
|
||||||
pub fn generate(trixy: &CommandSpec, config: &TrixyConfig) -> TokenStream2 {
|
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 {
|
fn type_to_rust(r#type: &Type) -> TokenStream2 {
|
||||||
let ident = identifier_to_rust(&r#type.identifier);
|
let ident = identifier_to_rust(&r#type.identifier);
|
||||||
if r#type.generic_args.is_empty() {
|
let namespaces_path = type_variant_rust_path(&r#type.identifier.variant);
|
||||||
if r#type.identifier.name == "str" {
|
|
||||||
|
let nasp_path = if let Some(nasp_path) = type_variant_rust_path(&r#type.identifier.variant) {
|
||||||
|
if nasp_path.is_empty() {
|
||||||
quote! {
|
quote! {
|
||||||
&str
|
crate ::
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let path = namespaces_path;
|
||||||
quote! {
|
quote! {
|
||||||
#ident
|
#path ::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if r#type.generic_args.is_empty() {
|
||||||
|
quote! {
|
||||||
|
#nasp_path #ident
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let generics: Vec<TokenStream2> = r#type.generic_args.iter().map(type_to_rust).collect();
|
let generics: Vec<TokenStream2> = r#type.generic_args.iter().map(type_to_rust).collect();
|
||||||
quote! {
|
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