aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_macros/src')
-rw-r--r--mingling_macros/src/chain.rs69
-rw-r--r--mingling_macros/src/lib.rs13
-rw-r--r--mingling_macros/src/renderer.rs87
3 files changed, 125 insertions, 44 deletions
diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs
index 84353e9..14e62ec 100644
--- a/mingling_macros/src/chain.rs
+++ b/mingling_macros/src/chain.rs
@@ -4,7 +4,7 @@
//! generating structs that implement the `Chain` trait from async functions.
use proc_macro::TokenStream;
-use quote::quote;
+use quote::{ToTokens, quote};
use syn::spanned::Spanned;
use syn::{
FnArg, Ident, ItemFn, Pat, PatType, ReturnType, Signature, Type, TypePath, parse_macro_input,
@@ -129,7 +129,7 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
#[doc(hidden)]
#vis struct #struct_name;
- ::mingling::macros::register_type!(#previous_type);
+ ::mingling::macros::register_chain!(#previous_type, #struct_name);
impl ::mingling::Chain<ThisProgram> for #struct_name {
type Previous = #previous_type;
@@ -156,6 +156,8 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
#(#fn_attrs)*
#vis struct #struct_name;
+ ::mingling::macros::register_chain!(#previous_type, #struct_name);
+
impl ::mingling::Chain<#group_name> for #struct_name {
type Previous = #previous_type;
@@ -178,19 +180,6 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
}
};
- // Record the chain mapping
- let chain_entry = build_chain_arm(&struct_name, &previous_type);
- let chain_exist_entry = build_chain_exist_arm(&previous_type);
-
- let mut chains = crate::CHAINS.lock().unwrap();
- let mut chain_exist = crate::CHAINS_EXIST.lock().unwrap();
-
- let chain_entry = chain_entry.to_string();
- let chain_exist_entry = chain_exist_entry.to_string();
-
- chains.insert(chain_entry);
- chain_exist.insert(chain_exist_entry);
-
expanded.into()
}
@@ -207,3 +196,53 @@ pub fn build_chain_exist_arm(previous_type: &TypePath) -> proc_macro2::TokenStre
Self::#previous_type => true,
}
}
+
+pub fn register_chain(input: TokenStream) -> TokenStream {
+ // Parse the input as a comma-separated list of arguments
+ let input_parsed = syn::parse_macro_input!(input with syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>::parse_terminated);
+
+ // Check that we have exactly two elements
+ if input_parsed.len() != 2 {
+ return syn::Error::new(
+ input_parsed.span(),
+ "Expected exactly two comma-separated arguments: `PreviousType, StructName`",
+ )
+ .to_compile_error()
+ .into();
+ }
+
+ // Extract the two elements
+ let previous_type_expr = &input_parsed[0];
+ let struct_name_expr = &input_parsed[1];
+
+ // Convert expressions to TypePath and Ident
+ let previous_type = match syn::parse2::<TypePath>(previous_type_expr.to_token_stream()) {
+ Ok(ty) => ty,
+ Err(e) => return e.to_compile_error().into(),
+ };
+
+ let struct_name = match syn::parse2::<syn::Ident>(struct_name_expr.to_token_stream()) {
+ Ok(ident) => ident,
+ Err(e) => return e.to_compile_error().into(),
+ };
+
+ // Record the chain mapping: previous_type => struct_name
+ let chain_entry = build_chain_arm(&struct_name, &previous_type);
+
+ // Record the chain existence check
+ let chain_exist_entry = build_chain_exist_arm(&previous_type);
+
+ let mut chains = crate::CHAINS.lock().unwrap();
+ let mut chain_exist = crate::CHAINS_EXIST.lock().unwrap();
+
+ let chain_entry_str = chain_entry.to_string();
+ let chain_exist_entry_str = chain_exist_entry.to_string();
+
+ chains.insert(chain_entry_str);
+ chain_exist.insert(chain_exist_entry_str);
+
+ quote! {
+ ::mingling::macros::register_type!(#previous_type);
+ }
+ .into()
+}
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 8ddda8b..5391dfd 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -169,9 +169,6 @@ pub fn program_gen_completion(input: TokenStream) -> TokenStream {
TokenStream::from(comp_dispatcher)
}
-/// Internal macro for registering types.
-///
-/// This macro is used internally by the `#[chain]` and `#[renderer]` attribute macros
#[proc_macro]
pub fn register_type(input: TokenStream) -> TokenStream {
let type_ident = parse_macro_input!(input as syn::Ident);
@@ -183,6 +180,16 @@ pub fn register_type(input: TokenStream) -> TokenStream {
}
#[proc_macro]
+pub fn register_chain(input: TokenStream) -> TokenStream {
+ chain::register_chain(input)
+}
+
+#[proc_macro]
+pub fn register_renderer(input: TokenStream) -> TokenStream {
+ renderer::register_renderer(input)
+}
+
+#[proc_macro]
pub fn program_final_gen(input: TokenStream) -> TokenStream {
let name = read_name(&input);
diff --git a/mingling_macros/src/renderer.rs b/mingling_macros/src/renderer.rs
index 0f477ee..a3da2e7 100644
--- a/mingling_macros/src/renderer.rs
+++ b/mingling_macros/src/renderer.rs
@@ -4,7 +4,7 @@
//! generating structs that implement the `Renderer` trait from functions.
use proc_macro::TokenStream;
-use quote::quote;
+use quote::{ToTokens, quote};
use syn::spanned::Spanned;
use syn::{FnArg, ItemFn, Pat, PatType, ReturnType, Signature, Type, TypePath, parse_macro_input};
@@ -100,30 +100,6 @@ pub fn renderer_attr(item: TokenStream) -> TokenStream {
let pascal_case_name = just_fmt::pascal_case!(fn_name.to_string());
let struct_name = syn::Ident::new(&pascal_case_name, fn_name.span());
- // Register the renderer in the global list
- let renderer_entry = build_renderer_entry(&struct_name, &previous_type);
- let renderer_exist_entry = build_renderer_exist_entry(&previous_type);
- #[cfg(feature = "general_renderer")]
- let general_renderer_entry = build_general_renderer_entry(&previous_type);
-
- let mut renderers = crate::RENDERERS.lock().unwrap();
- let mut renderer_exist = crate::RENDERERS_EXIST.lock().unwrap();
-
- #[cfg(feature = "general_renderer")]
- let mut general_renderers = crate::GENERAL_RENDERERS.lock().unwrap();
-
- let renderer_entry_str = renderer_entry.to_string();
- let renderer_exist_entry_str = renderer_exist_entry.to_string();
-
- #[cfg(feature = "general_renderer")]
- let general_renderer_entry_str = general_renderer_entry.to_string();
-
- renderers.insert(renderer_entry_str);
- renderer_exist.insert(renderer_exist_entry_str);
-
- #[cfg(feature = "general_renderer")]
- general_renderers.insert(general_renderer_entry_str);
-
// Generate the struct and implementation
// We need to create a wrapper function that adds the r parameter
let expanded = quote! {
@@ -131,7 +107,7 @@ pub fn renderer_attr(item: TokenStream) -> TokenStream {
#[doc(hidden)]
#vis struct #struct_name;
- ::mingling::macros::register_type!(#previous_type);
+ ::mingling::macros::register_renderer!(#previous_type, #struct_name);
impl ::mingling::Renderer for #struct_name {
type Previous = #previous_type;
@@ -192,3 +168,62 @@ pub fn build_general_renderer_entry(previous_type: &TypePath) -> proc_macro2::To
}
}
}
+
+pub fn register_renderer(input: TokenStream) -> TokenStream {
+ // Parse the input as a comma-separated list of arguments
+ let input_parsed = syn::parse_macro_input!(input with syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>::parse_terminated);
+
+ // Check that we have exactly two elements
+ if input_parsed.len() != 2 {
+ return syn::Error::new(
+ input_parsed.span(),
+ "Expected exactly two comma-separated arguments: `PreviousType, StructName`",
+ )
+ .to_compile_error()
+ .into();
+ }
+
+ // Extract the two elements
+ let previous_type_expr = &input_parsed[0];
+ let struct_name_expr = &input_parsed[1];
+
+ // Convert expressions to TypePath and Ident
+ let previous_type = match syn::parse2::<TypePath>(previous_type_expr.to_token_stream()) {
+ Ok(ty) => ty,
+ Err(e) => return e.to_compile_error().into(),
+ };
+
+ let struct_name = match syn::parse2::<syn::Ident>(struct_name_expr.to_token_stream()) {
+ Ok(ident) => ident,
+ Err(e) => return e.to_compile_error().into(),
+ };
+
+ // Register the renderer in the global list
+ let renderer_entry = build_renderer_entry(&struct_name, &previous_type);
+ let renderer_exist_entry = build_renderer_exist_entry(&previous_type);
+ #[cfg(feature = "general_renderer")]
+ let general_renderer_entry = build_general_renderer_entry(&previous_type);
+
+ let mut renderers = crate::RENDERERS.lock().unwrap();
+ let mut renderer_exist = crate::RENDERERS_EXIST.lock().unwrap();
+
+ #[cfg(feature = "general_renderer")]
+ let mut general_renderers = crate::GENERAL_RENDERERS.lock().unwrap();
+
+ let renderer_entry_str = renderer_entry.to_string();
+ let renderer_exist_entry_str = renderer_exist_entry.to_string();
+
+ #[cfg(feature = "general_renderer")]
+ let general_renderer_entry_str = general_renderer_entry.to_string();
+
+ renderers.insert(renderer_entry_str);
+ renderer_exist.insert(renderer_exist_entry_str);
+
+ #[cfg(feature = "general_renderer")]
+ general_renderers.insert(general_renderer_entry_str);
+
+ quote! {
+ ::mingling::macros::register_type!(#previous_type);
+ }
+ .into()
+}