fp_macros/lib.rs
1#![warn(missing_docs)]
2#![allow(clippy::tabs_in_doc_comments)]
3
4//! Procedural macros for the [`fp-library`](https://docs.rs/fp-library/latest/fp_library/) crate.
5//!
6//! This crate provides macros for generating and working with Higher-Kinded Type (HKT) traits.
7
8pub(crate) mod a_do; // Applicative do-notation
9pub(crate) mod analysis; // Type and trait analysis
10pub(crate) mod codegen; // Code generation (includes re-exports)
11pub(crate) mod core; // Core infrastructure (config, error, result)
12pub(crate) mod documentation; // Documentation generation macros
13pub(crate) mod hkt; // Higher-Kinded Type macros
14pub(crate) mod hm; // Hindley-Milner type conversion
15pub(crate) mod m_do; // Monadic do-notation
16pub(crate) mod resolution; // Type resolution
17pub(crate) mod support; // Support utilities (attributes, syntax, validation, errors)
18
19#[cfg(test)]
20mod property_tests;
21
22use {
23 crate::core::ToCompileError,
24 a_do::a_do_worker,
25 codegen::{
26 FunctionFormatter,
27 ReExportInput,
28 TraitFormatter,
29 generate_re_exports_worker,
30 },
31 documentation::{
32 document_examples_worker,
33 document_module_worker,
34 document_parameters_worker,
35 document_returns_worker,
36 document_signature_worker,
37 document_type_parameters_worker,
38 },
39 hkt::{
40 ApplyInput,
41 AssociatedTypes,
42 ImplKindInput,
43 apply_worker,
44 generate_name,
45 impl_kind_worker,
46 kind_attr_worker,
47 trait_kind_worker,
48 },
49 m_do::{
50 DoInput,
51 m_do_worker,
52 },
53 proc_macro::TokenStream,
54 quote::quote,
55 syn::parse_macro_input,
56};
57
58/// Generates the name of a `Kind` trait based on its signature.
59///
60/// This macro takes a list of associated type definitions, similar to a trait definition.
61///
62/// ### Syntax
63///
64/// ```ignore
65/// Kind!(
66/// type AssocName<Params>: Bounds;
67/// // ...
68/// )
69/// ```
70///
71/// * `Associated Types`: A list of associated type definitions (e.g., `type Of<T>;`) that define the signature of the Kind.
72///
73/// ### Generates
74///
75/// The name of the generated `Kind` trait (e.g., `Kind_0123456789abcdef`).
76/// The name is deterministic and based on a hash of the signature.
77///
78/// ### Examples
79///
80/// ```ignore
81/// // Invocation
82/// let name = Kind!(type Of<T>;);
83///
84/// // Expanded code
85/// let name = Kind_...; // e.g., Kind_a1b2c3d4e5f67890
86/// ```
87///
88/// ```ignore
89/// // Invocation
90/// let name = Kind!(type Of<'a, T: Display>: Debug;);
91///
92/// // Expanded code
93/// let name = Kind_...; // Unique hash based on signature
94/// ```
95///
96/// ```ignore
97/// // Invocation
98/// let name = Kind!(
99/// type Of<T>;
100/// type SendOf<T>: Send;
101/// );
102///
103/// // Expanded code
104/// let name = Kind_...; // Unique hash based on signature
105/// ```
106///
107/// ### Limitations
108///
109/// Due to Rust syntax restrictions, this macro cannot be used directly in positions where a
110/// concrete path is expected by the parser, such as:
111/// * Supertrait bounds: `trait MyTrait: Kind!(...) {}` (Invalid)
112/// * Type aliases: `type MyKind = Kind!(...);` (Invalid)
113/// * Trait aliases: `trait MyKind = Kind!(...);` (Invalid)
114///
115/// For supertrait bounds, use the [`kind`] attribute macro instead:
116/// ```ignore
117/// #[kind(type Of<'a, A: 'a>: 'a;)]
118/// pub trait Functor { ... }
119/// ```
120///
121/// For other positions, you must use the generated name directly (e.g., `Kind_...`).
122#[proc_macro]
123#[allow(non_snake_case)]
124pub fn Kind(input: TokenStream) -> TokenStream {
125 let input = parse_macro_input!(input as AssociatedTypes);
126 let name = match generate_name(&input) {
127 Ok(name) => name,
128 Err(e) => return e.to_compile_error().into(),
129 };
130 quote!(#name).into()
131}
132
133/// Defines a new `Kind` trait.
134///
135/// This macro generates a trait definition for a Higher-Kinded Type signature.
136///
137/// ### Syntax
138///
139/// ```ignore
140/// trait_kind!(
141/// type AssocName<Params>: Bounds;
142/// // ...
143/// )
144/// ```
145///
146/// * `Associated Types`: A list of associated type definitions (e.g., `type Of<T>;`) that define the signature of the Kind.
147///
148/// ### Generates
149///
150/// A public trait definition with a unique name derived from the signature (format: `Kind_{hash}`).
151///
152/// ### Examples
153///
154/// ```ignore
155/// // Invocation
156/// trait_kind!(type Of<T>;);
157///
158/// // Expanded code
159/// pub trait Kind_... { // e.g., Kind_a1b2c3d4e5f67890
160/// type Of<T>;
161/// }
162/// ```
163///
164/// ```ignore
165/// // Invocation
166/// trait_kind!(type Of<'a, T: Display>: Debug;);
167///
168/// // Expanded code
169/// pub trait Kind_... {
170/// type Of<'a, T: Display>: Debug;
171/// }
172/// ```
173///
174/// ```ignore
175/// // Invocation
176/// trait_kind!(
177/// type Of<T>;
178/// type SendOf<T>: Send;
179/// );
180///
181/// // Expanded code
182/// pub trait Kind_... {
183/// type Of<T>;
184/// type SendOf<T>: Send;
185/// }
186/// ```
187#[proc_macro]
188pub fn trait_kind(input: TokenStream) -> TokenStream {
189 let input = parse_macro_input!(input as AssociatedTypes);
190 match trait_kind_worker(input) {
191 Ok(tokens) => tokens.into(),
192 Err(e) => e.to_compile_error().into(),
193 }
194}
195
196/// Implements a `Kind` trait for a brand.
197///
198/// This macro simplifies the implementation of a generated `Kind` trait for a specific
199/// brand type. It infers the correct `Kind` trait to implement based on the signature
200/// of the associated types provided in the block.
201///
202/// The signature (names, parameters, and bounds) of the associated types must match
203/// the definition used in [`trait_kind!`] or [`Kind!`] to ensure the correct trait is implemented.
204///
205/// ### Syntax
206///
207/// ```ignore
208/// impl_kind! {
209/// // Optional impl generics
210/// impl<Generics> for BrandType
211/// // Optional where clause
212/// where Bounds
213/// {
214/// type AssocName<Params> = ConcreteType;
215/// // ... more associated types
216/// }
217/// }
218/// ```
219///
220/// * `Generics`: Optional generic parameters for the implementation.
221/// * `BrandType`: The brand type to implement the Kind for.
222/// * `Bounds`: Optional where clause bounds.
223/// * `Associated Types`: The associated type assignments (e.g., `type Of<A> = Option<A>;`).
224///
225/// ### Generates
226///
227/// An implementation of the appropriate `Kind` trait for the brand.
228///
229/// ### Attributes
230///
231/// Inside the `impl_kind!` block, you can use documentation-specific attributes on associated types:
232///
233/// * `#[document_default]`: Marks this associated type as the default for resolving bare `Self` in
234/// the generated documentation for this brand within the module.
235///
236/// ### Examples
237///
238/// ```ignore
239/// // Invocation
240/// impl_kind! {
241/// for OptionBrand {
242/// #[document_default]
243/// type Of<A> = Option<A>;
244/// }
245/// }
246///
247/// // Expanded code
248/// impl Kind_... for OptionBrand { // e.g., Kind_a1b2c3d4e5f67890
249/// type Of<A> = Option<A>;
250/// }
251/// ```
252///
253/// ```ignore
254/// // Invocation
255/// impl_kind! {
256/// impl<E> for ResultBrand<E> {
257/// type Of<A> = Result<A, E>;
258/// }
259/// }
260///
261/// // Expanded code
262/// impl<E> Kind_... for ResultBrand<E> {
263/// type Of<A> = Result<A, E>;
264/// }
265/// ```
266///
267/// ```ignore
268/// // Invocation
269/// impl_kind! {
270/// impl<E> for MyBrand<E> where E: Clone {
271/// type Of<A> = MyType<A, E>;
272/// type SendOf<A> = MySendType<A, E>;
273/// }
274/// }
275///
276/// // Expanded code
277/// impl<E> Kind_... for MyBrand<E> where E: Clone {
278/// type Of<A> = MyType<A, E>;
279/// type SendOf<A> = MySendType<A, E>;
280/// }
281/// ```
282///
283/// ```ignore
284/// // Invocation
285/// // Corresponds to: trait_kind!(type Of<T: Display>;);
286/// impl_kind! {
287/// for DisplayBrand {
288/// // Bounds here are used to infer the correct `Kind` trait name
289/// type Of<T: Display> = DisplayType<T>;
290/// }
291/// }
292///
293/// // Expanded code
294/// impl Kind_... for DisplayBrand {
295/// type Of<T: Display> = DisplayType<T>;
296/// }
297/// ```
298#[proc_macro]
299pub fn impl_kind(input: TokenStream) -> TokenStream {
300 let input = parse_macro_input!(input as ImplKindInput);
301 match impl_kind_worker(input) {
302 Ok(tokens) => tokens.into(),
303 Err(e) => e.to_compile_error().into(),
304 }
305}
306
307/// Applies a brand to type arguments.
308///
309/// This macro projects a brand type to its concrete type using the appropriate
310/// `Kind` trait. It uses a syntax that mimics a fully qualified path, where the
311/// `Kind` trait is specified by its signature.
312///
313/// ### Syntax
314///
315/// ```ignore
316/// Apply!(<Brand as Kind!( KindSignature )>::AssocType<Args>)
317/// ```
318///
319/// * `Brand`: The brand type (e.g., `OptionBrand`).
320/// * `KindSignature`: A list of associated type definitions defining the `Kind` trait schema.
321/// * `AssocType`: The associated type to project (e.g., `Of`).
322/// * `Args`: The concrete arguments to apply.
323///
324/// ### Generates
325///
326/// The concrete type resulting from applying the brand to the arguments.
327///
328/// ### Examples
329///
330/// ```ignore
331/// // Invocation
332/// // Applies MyBrand to lifetime 'static and type String.
333/// type Concrete = Apply!(<MyBrand as Kind!( type Of<'a, T>; )>::Of<'static, String>);
334///
335/// // Expanded code
336/// type Concrete = <MyBrand as Kind_...>::Of<'static, String>;
337/// ```
338///
339/// ```ignore
340/// // Invocation
341/// // Applies MyBrand to a generic type T with bounds.
342/// type Concrete = Apply!(<MyBrand as Kind!( type Of<T: Clone>; )>::Of<T>);
343///
344/// // Expanded code
345/// type Concrete = <MyBrand as Kind_...>::Of<T>;
346/// ```
347///
348/// ```ignore
349/// // Invocation
350/// // Complex example with lifetimes, types, and output bounds.
351/// type Concrete = Apply!(<MyBrand as Kind!( type Of<'a, T: Clone + Debug>: Display; )>::Of<'a, T>);
352///
353/// // Expanded code
354/// type Concrete = <MyBrand as Kind_...>::Of<'a, T>;
355/// ```
356///
357/// ```ignore
358/// // Invocation
359/// // Use a custom associated type for projection.
360/// type Concrete = Apply!(<MyBrand as Kind!( type Of<T>; type SendOf<T>; )>::SendOf<T>);
361///
362/// // Expanded code
363/// type Concrete = <MyBrand as Kind_...>::SendOf<T>;
364/// ```
365#[proc_macro]
366#[allow(non_snake_case)]
367pub fn Apply(input: TokenStream) -> TokenStream {
368 let input = parse_macro_input!(input as ApplyInput);
369 match apply_worker(input) {
370 Ok(tokens) => tokens.into(),
371 Err(e) => e.to_compile_error().into(),
372 }
373}
374
375/// Adds a `Kind` supertrait bound to a trait definition.
376///
377/// This attribute macro parses a Kind signature and adds the corresponding
378/// `Kind_` trait as a supertrait bound, avoiding the need to reference
379/// hash-based trait names directly.
380///
381/// ### Syntax
382///
383/// ```ignore
384/// #[kind(type AssocName<Params>: Bounds;)]
385/// pub trait MyTrait {
386/// // ...
387/// }
388/// ```
389///
390/// ### Examples
391///
392/// ```ignore
393/// // Invocation
394/// #[kind(type Of<'a, A: 'a>: 'a;)]
395/// pub trait Functor {
396/// fn map<'a, A: 'a, B: 'a>(
397/// f: impl Fn(A) -> B + 'a,
398/// fa: Apply!(<Self as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
399/// ) -> Apply!(<Self as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>);
400/// }
401///
402/// // Expanded code
403/// pub trait Functor: Kind_cdc7cd43dac7585f {
404/// // body unchanged
405/// }
406/// ```
407///
408/// ```ignore
409/// // Works with existing supertraits
410/// #[kind(type Of<'a, A: 'a>: 'a;)]
411/// pub trait Monad: Applicative {
412/// // Kind_ bound is appended: Monad: Applicative + Kind_...
413/// }
414/// ```
415#[proc_macro_attribute]
416pub fn kind(
417 attr: TokenStream,
418 item: TokenStream,
419) -> TokenStream {
420 let attr = parse_macro_input!(attr as AssociatedTypes);
421 let item = parse_macro_input!(item as syn::ItemTrait);
422 match kind_attr_worker(attr, item) {
423 Ok(tokens) => tokens.into(),
424 Err(e) => e.to_compile_error().into(),
425 }
426}
427
428/// Generates re-exports for all public free functions in a directory.
429///
430/// This macro scans the specified directory for Rust files, parses them to find public free functions,
431/// and generates `pub use` statements for them. It supports aliasing to resolve name conflicts.
432///
433/// ### Syntax
434///
435/// ```ignore
436/// generate_function_re_exports!("path/to/directory", {
437/// original_name: aliased_name,
438/// ...
439/// })
440/// ```
441///
442/// * `path/to/directory`: The path to the directory containing the modules, relative to the crate root.
443/// * `aliases`: A map of function names to their desired aliases.
444///
445/// ### Generates
446///
447/// `pub use` statements for each public function found in the directory.
448///
449/// ### Examples
450///
451/// ```ignore
452/// // Invocation
453/// generate_function_re_exports!("src/classes", {
454/// identity: category_identity,
455/// new: fn_new,
456/// });
457///
458/// // Expanded code
459/// pub use src::classes::category::identity as category_identity;
460/// pub use src::classes::function::new as fn_new;
461/// // ... other re-exports
462/// ```
463#[proc_macro]
464pub fn generate_function_re_exports(input: TokenStream) -> TokenStream {
465 let input = parse_macro_input!(input as ReExportInput);
466 generate_re_exports_worker(&input, &FunctionFormatter).into()
467}
468
469/// Generates re-exports for all public traits in a directory.
470///
471/// This macro scans the specified directory for Rust files, parses them to find public traits,
472/// and generates `pub use` statements for them.
473///
474/// ### Syntax
475///
476/// ```ignore
477/// generate_trait_re_exports!("path/to/directory", {
478/// original_name: aliased_name,
479/// ...
480/// })
481/// ```
482///
483/// * `path/to/directory`: The path to the directory containing the modules, relative to the crate root.
484/// * `aliases`: A map of trait names to their desired aliases (optional).
485///
486/// ### Generates
487///
488/// `pub use` statements for each public trait found in the directory.
489///
490/// ### Examples
491///
492/// ```ignore
493/// // Invocation
494/// generate_trait_re_exports!("src/classes", {});
495///
496/// // Expanded code
497/// pub use src::classes::functor::Functor;
498/// pub use src::classes::monad::Monad;
499/// // ... other re-exports
500/// ```
501#[proc_macro]
502pub fn generate_trait_re_exports(input: TokenStream) -> TokenStream {
503 let input = parse_macro_input!(input as ReExportInput);
504 generate_re_exports_worker(&input, &TraitFormatter).into()
505}
506
507/// Generates a Hindley-Milner style type signature for a function.
508///
509/// This macro analyzes the function signature and generates a documentation comment
510/// containing the corresponding Hindley-Milner type signature.
511///
512/// When used within a module annotated with [`#[document_module]`](macro@document_module),
513/// it automatically resolves `Self` and associated types based on the module's projection map.
514///
515/// ### Syntax
516///
517/// ```ignore
518/// #[document_signature]
519/// pub fn function_name<Generics>(params) -> ReturnType { ... }
520/// ```
521///
522/// When applying this macro to a method inside a trait, you can provide the trait name
523/// as an argument to correctly generate the `Trait self` constraint.
524///
525/// ### Generates
526///
527/// A documentation comment with the generated signature, prepended to the function definition.
528///
529/// ### Examples
530///
531/// ```ignore
532/// // Invocation
533/// #[document_signature]
534/// pub fn map<F: Functor, A, B>(f: impl Fn(A) -> B, fa: F::Of<A>) -> F::Of<B> { ... }
535///
536/// // Expanded code
537/// /// ### Type Signature
538/// /// `forall f a b. Functor f => (a -> b, f a) -> f b`
539/// pub fn map<F: Functor, A, B>(f: impl Fn(A) -> B, fa: F::Of<A>) -> F::Of<B> { ... }
540/// ```
541///
542/// ```ignore
543/// // Invocation
544/// #[document_signature]
545/// pub fn foo(x: impl Iterator<Item = String>) -> i32 { ... }
546///
547/// // Expanded code
548/// /// ### Type Signature
549/// /// `iterator -> i32`
550/// pub fn foo(x: impl Iterator<Item = String>) -> i32 { ... }
551/// ```
552///
553/// ```ignore
554/// // Invocation
555/// trait Functor {
556/// #[document_signature]
557/// fn map<A, B>(f: impl Fn(A) -> B, fa: Self::Of<A>) -> Self::Of<B>;
558/// }
559///
560/// // Expanded code
561/// trait Functor {
562/// /// ### Type Signature
563/// /// `forall self a b. Functor self => (a -> b, self a) -> self b`
564/// fn map<A, B>(f: impl Fn(A) -> B, fa: Self::Of<A>) -> Self::Of<B>;
565/// }
566/// ```
567///
568/// ### Configuration
569///
570/// This macro can be configured via `Cargo.toml` under `[package.metadata.document_signature]`.
571///
572/// * `brand_mappings`: A map of brand struct names to their display names in the signature.
573/// * `apply_macro_aliases`: A list of macro names that should be treated as `Apply!`.
574/// * `ignored_traits`: A list of traits to ignore in the signature constraints.
575///
576/// Example:
577/// ```toml
578/// [package.metadata.document_signature]
579/// brand_mappings = { "OptionBrand" = "Option", "VecBrand" = "Vec" }
580/// apply_macro_aliases = ["MyApply"]
581/// ignored_traits = ["Clone", "Debug"]
582/// ```
583#[proc_macro_attribute]
584pub fn document_signature(
585 attr: TokenStream,
586 item: TokenStream,
587) -> TokenStream {
588 match document_signature_worker(attr.into(), item.into()) {
589 Ok(tokens) => tokens.into(),
590 Err(e) => e.to_compile_error().into(),
591 }
592}
593
594/// Generates documentation for type parameters.
595///
596/// This macro analyzes the item's signature (function, struct, enum, impl block, etc.)
597/// and generates a documentation comment list based on the provided descriptions.
598///
599/// When used within a module annotated with [`#[document_module]`](macro@document_module),
600/// it benefits from automatic `Self` resolution and is applied as part of the module-level
601/// documentation pass.
602///
603/// ### Syntax
604///
605/// ```ignore
606/// #[document_type_parameters(
607/// "Description for first parameter",
608/// ("OverriddenName", "Description for second parameter"),
609/// ...
610/// )]
611/// pub fn function_name<Generics>(params) -> ReturnType { ... }
612/// ```
613///
614/// It can also be used on other items like `impl` blocks:
615///
616/// ```ignore
617/// #[document_type_parameters("Description for T")]
618/// impl<T> MyType<T> { ... }
619/// ```
620///
621/// * `Descriptions`: A comma-separated list. Each entry can be either a string literal
622/// or a tuple of two string literals `(Name, Description)`.
623///
624/// ### Generates
625///
626/// A list of documentation comments, one for each generic parameter, prepended to the
627/// function definition.
628///
629/// ### Examples
630///
631/// ```ignore
632/// // Invocation
633/// #[document_type_parameters(
634/// "The type of the elements.",
635/// ("E", "The error type.")
636/// )]
637/// pub fn map<T, ERR>(...) { ... }
638///
639/// // Expanded code
640/// /// ### Type Parameters
641/// /// * `T`: The type of the elements.
642/// /// * `E`: The error type.
643/// pub fn map<T, ERR>(...) { ... }
644/// ```
645///
646/// ### Constraints
647///
648/// * The number of arguments must exactly match the number of generic parameters
649/// (including lifetimes, types, and const generics) in the function signature.
650#[proc_macro_attribute]
651pub fn document_type_parameters(
652 attr: TokenStream,
653 item: TokenStream,
654) -> TokenStream {
655 match document_type_parameters_worker(attr.into(), item.into()) {
656 Ok(tokens) => tokens.into(),
657 Err(e) => e.to_compile_error().into(),
658 }
659}
660
661/// Generates documentation for a function's parameters.
662///
663/// This macro analyzes the function signature and generates a documentation comment
664/// list based on the provided descriptions. It also handles curried return types.
665///
666/// It can also be used on `impl` blocks to provide a common description for the receiver (`self`)
667/// parameter of methods within the block.
668///
669/// ### Syntax
670///
671/// For functions:
672/// ```ignore
673/// #[document_parameters(
674/// "Description for first parameter",
675/// ("overridden_name", "Description for second parameter"),
676/// ...
677/// )]
678/// pub fn function_name(params) -> impl Fn(...) { ... }
679/// ```
680///
681/// For `impl` blocks:
682/// ```ignore
683/// #[document_parameters("Description for receiver")]
684/// impl MyType {
685/// #[document_parameters]
686/// pub fn method_with_receiver(&self) { ... }
687///
688/// #[document_parameters("Description for arg")]
689/// pub fn method_with_args(&self, arg: i32) { ... }
690/// }
691/// ```
692///
693/// * `Descriptions`: A comma-separated list. Each entry can be either a string literal
694/// or a tuple of two string literals `(Name, Description)`.
695/// * For `impl` blocks: Exactly one string literal describing the receiver parameter.
696///
697/// ### Generates
698///
699/// A list of documentation comments, one for each parameter, prepended to the
700/// function definition.
701///
702/// ### Examples
703///
704/// ```ignore
705/// // Invocation
706/// #[document_parameters(
707/// "The first input value.",
708/// ("y", "The second input value.")
709/// )]
710/// pub fn foo(x: i32) -> impl Fn(i32) -> i32 { ... }
711///
712/// // Expanded code
713/// /// ### Parameters
714/// /// * `x`: The first input value.
715/// /// * `y`: The second input value.
716/// pub fn foo(x: i32) -> impl Fn(i32) -> i32 { ... }
717/// ```
718///
719/// ```ignore
720/// // Invocation on impl block
721/// #[document_parameters("The list instance")]
722/// impl<A> MyList<A> {
723/// #[document_parameters("The element to push")]
724/// pub fn push(&mut self, item: A) { ... }
725/// }
726///
727/// // Expanded code
728/// impl<A> MyList<A> {
729/// /// ### Parameters
730/// /// * `&mut self`: The list instance
731/// /// * `item`: The element to push
732/// pub fn push(&mut self, item: A) { ... }
733/// }
734/// ```
735///
736/// ### Constraints
737///
738/// * The number of arguments must exactly match the number of function parameters
739/// (excluding `self` but including parameters from curried return types).
740///
741/// ### Configuration
742///
743/// This macro can be configured via `Cargo.toml` under `[package.metadata.document_signature]`.
744///
745/// * `apply_macro_aliases`: A list of macro names that should be treated as `Apply!` for curried parameter extraction.
746///
747/// Example:
748/// ```toml
749/// [package.metadata.document_signature]
750/// apply_macro_aliases = ["MyApply"]
751/// ```
752#[proc_macro_attribute]
753pub fn document_parameters(
754 attr: TokenStream,
755 item: TokenStream,
756) -> TokenStream {
757 match document_parameters_worker(attr.into(), item.into()) {
758 Ok(tokens) => tokens.into(),
759 Err(e) => e.to_compile_error().into(),
760 }
761}
762
763/// Generates documentation for the return value of a function.
764///
765/// This macro adds a "Returns" section to the function's documentation.
766///
767/// ### Syntax
768///
769/// ```ignore
770/// #[document_returns("Description of the return value.")]
771/// pub fn foo() -> i32 { ... }
772/// ```
773///
774/// ### Generates
775///
776/// A documentation comment describing the return value.
777///
778/// ### Examples
779///
780/// ```ignore
781/// // Invocation
782/// #[document_returns("The sum of x and y.")]
783/// pub fn add(x: i32, y: i32) -> i32 { ... }
784///
785/// // Expanded code
786/// /// ### Returns
787/// /// The sum of x and y.
788/// pub fn add(x: i32, y: i32) -> i32 { ... }
789/// ```
790#[proc_macro_attribute]
791pub fn document_returns(
792 attr: TokenStream,
793 item: TokenStream,
794) -> TokenStream {
795 match document_returns_worker(attr.into(), item.into()) {
796 Ok(tokens) => tokens.into(),
797 Err(e) => e.to_compile_error().into(),
798 }
799}
800
801/// Inserts a `### Examples` heading and validates doc comment code blocks.
802///
803/// This attribute macro expands in-place to a `### Examples` heading. Example
804/// code is written as regular doc comments using fenced code blocks after the
805/// attribute. Every Rust code block must contain at least one assertion macro
806/// invocation (e.g., `assert_eq!`, `assert!`).
807///
808/// ### Syntax
809///
810/// ```ignore
811/// #[document_examples]
812/// ///
813/// /// ```
814/// /// let result = add(1, 2);
815/// /// assert_eq!(result, 3);
816/// /// ```
817/// pub fn add(x: i32, y: i32) -> i32 { ... }
818/// ```
819///
820/// ### Generates
821///
822/// A `### Examples` heading is inserted at the attribute's position. The code
823/// blocks in the doc comments are validated but not modified.
824///
825/// ### Examples
826///
827/// ```ignore
828/// // Invocation
829/// #[document_examples]
830/// ///
831/// /// ```
832/// /// let x = my_fn(1, 2);
833/// /// assert_eq!(x, 3);
834/// /// ```
835/// pub fn my_fn(a: i32, b: i32) -> i32 { a + b }
836///
837/// // Expanded code
838/// /// ### Examples
839/// ///
840/// /// ```
841/// /// let x = my_fn(1, 2);
842/// /// assert_eq!(x, 3);
843/// /// ```
844/// pub fn my_fn(a: i32, b: i32) -> i32 { a + b }
845/// ```
846///
847/// ### Errors
848///
849/// * Arguments are provided to the attribute.
850/// * No Rust code block is found in the doc comments.
851/// * A Rust code block does not contain an assertion macro invocation.
852/// * The attribute is applied more than once to the same function.
853#[proc_macro_attribute]
854pub fn document_examples(
855 attr: TokenStream,
856 item: TokenStream,
857) -> TokenStream {
858 match document_examples_worker(attr.into(), item.into()) {
859 Ok(tokens) => tokens.into(),
860 Err(e) => e.to_compile_error().into(),
861 }
862}
863
864/// Orchestrates documentation generation for an entire module.
865///
866/// This macro provides a centralized way to handle documentation for Higher-Kinded Type (HKT)
867/// implementations. It performs a two-pass analysis of the module:
868///
869/// 1. **Context Extraction**: It scans for `impl_kind!` invocations and standard `impl` blocks
870/// to build a comprehensive mapping of associated types (a "projection map").
871/// 2. **Documentation Generation**: It processes all methods annotated with [`#[document_signature]`](macro@document_signature)
872/// or [`#[document_type_parameters]`](macro@document_type_parameters), resolving `Self` and associated types
873/// using the collected context.
874/// 3. **Validation** (Optional): Checks that impl blocks and methods have appropriate documentation
875/// attributes and emits compile-time warnings for missing documentation.
876///
877/// ### Syntax
878///
879/// Due to inner macro attributes being unstable, use the following wrapper pattern:
880///
881/// ```ignore
882/// #[fp_macros::document_module]
883/// mod inner {
884/// // ... module content ...
885/// }
886/// pub use inner::*;
887/// ```
888///
889/// To disable validation warnings:
890///
891/// ```ignore
892/// #[fp_macros::document_module(no_validation)]
893/// mod inner {
894/// // ... module content ...
895/// }
896/// pub use inner::*;
897/// ```
898///
899/// ### Generates
900///
901/// In-place replacement of [`#[document_signature]`](macro@document_signature) and
902/// [`#[document_type_parameters]`](macro@document_type_parameters) attributes with generated documentation
903/// comments. It also resolves `Self` and `Self::AssocType` references to their concrete
904/// types based on the module's projection map.
905///
906/// ### Attributes
907///
908/// The macro supports several documentation-specific attributes for configuration:
909///
910/// * `#[document_default]`: (Used inside `impl` or `impl_kind!`) Marks an associated type as the
911/// default to use when resolving bare `Self` references.
912/// * `#[document_use = "AssocName"]`: (Used on `impl` or `fn`) Explicitly specifies which
913/// associated type definition to use for resolution within that scope.
914///
915/// ### Validation
916///
917/// By default, `document_module` validates that impl blocks and methods have appropriate
918/// documentation attributes and emits compile-time warnings for missing documentation.
919///
920/// To disable validation, use `#[document_module(no_validation)]`.
921///
922/// #### Validation Rules
923///
924/// An impl block or trait definition should have:
925/// * `#[document_type_parameters]` if it has type parameters
926/// * `#[document_parameters]` if it contains methods with receiver parameters (self, &self, &mut self)
927///
928/// A method should have:
929/// * `#[document_signature]` - always recommended for documenting the Hindley-Milner signature
930/// * `#[document_type_parameters]` if it has type parameters
931/// * `#[document_parameters]` if it has non-receiver parameters
932/// * `#[document_returns]` if it has a return type
933/// * `#[document_examples]` - always recommended
934///
935/// A free function should have:
936/// * `#[document_examples]` - always recommended
937///
938/// Documentation attributes must not be duplicated and must appear in canonical order:
939/// `#[document_signature]` → `#[document_type_parameters]` → `#[document_parameters]` →
940/// `#[document_returns]` → `#[document_examples]`.
941///
942/// Additionally, a lint warns when a named generic type parameter could be replaced with
943/// `impl Trait` (i.e., it has trait bounds, appears in exactly one parameter position, does
944/// not appear in the return type, and is not cross-referenced by other type parameters).
945/// This lint skips trait implementations. Suppress it on individual functions or methods
946/// with `#[allow_named_generics]`.
947///
948/// #### Examples of Validation
949///
950/// ```ignore
951/// // This will emit warnings:
952/// #[fp_macros::document_module]
953/// mod inner {
954/// pub struct MyType;
955///
956/// // WARNING: Impl block contains methods with receiver parameters
957/// // but no #[document_parameters] attribute
958/// impl MyType {
959/// // WARNING: Method should have #[document_signature] attribute
960/// // WARNING: Method has parameters but no #[document_parameters] attribute
961/// // WARNING: Method has a return type but no #[document_returns] attribute
962/// // WARNING: Method should have a #[document_examples] attribute
963/// pub fn process(&self, x: i32) -> i32 { x }
964/// }
965/// }
966/// ```
967///
968/// ```ignore
969/// // Properly documented (no warnings):
970/// #[fp_macros::document_module]
971/// mod inner {
972/// pub struct MyType;
973///
974/// #[document_parameters("The MyType instance")]
975/// impl MyType {
976/// #[document_signature]
977/// #[document_parameters("The input value")]
978/// #[document_returns("The input value unchanged.")]
979/// #[document_examples]
980/// ///
981/// /// ```
982/// /// # use my_crate::MyType;
983/// /// let t = MyType;
984/// /// assert_eq!(t.process(42), 42);
985/// /// ```
986/// pub fn process(&self, x: i32) -> i32 { x }
987/// }
988/// }
989/// ```
990///
991/// ```ignore
992/// // Disable validation to suppress warnings:
993/// #[fp_macros::document_module(no_validation)]
994/// mod inner {
995/// // ... undocumented code won't produce warnings ...
996/// }
997/// ```
998///
999/// ### Hierarchical Configuration
1000///
1001/// When resolving the concrete type of `Self`, the macro follows this precedence:
1002///
1003/// 1. **Method Override**: `#[document_use = "AssocName"]` on the method.
1004/// 2. **Impl Block Override**: `#[document_use = "AssocName"]` on the `impl` block.
1005/// 3. **(Type, Trait)-Scoped Default**: `#[document_default]` on the associated type definition
1006/// in a trait `impl` block.
1007/// 4. **Module Default**: `#[document_default]` on the associated type definition in `impl_kind!`.
1008///
1009/// ### Examples
1010///
1011/// ```ignore
1012/// // Invocation
1013/// #[fp_macros::document_module]
1014/// mod inner {
1015/// use super::*;
1016///
1017/// impl_kind! {
1018/// for MyBrand {
1019/// #[document_default]
1020/// type Of<'a, T: 'a>: 'a = MyType<T>;
1021/// }
1022/// }
1023///
1024/// impl Functor for MyBrand {
1025/// #[document_signature]
1026/// fn map<'a, A: 'a, B: 'a, Func>(
1027/// f: Func,
1028/// fa: Apply!(<Self as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
1029/// ) -> Apply!(<Self as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>)
1030/// where
1031/// Func: Fn(A) -> B + 'a
1032/// {
1033/// todo!()
1034/// }
1035/// }
1036/// }
1037/// pub use inner::*;
1038///
1039/// // Expanded code
1040/// mod inner {
1041/// use super::*;
1042///
1043/// // ... generated Kind implementations ...
1044///
1045/// impl Functor for MyBrand {
1046/// /// ### Type Signature
1047/// /// `forall a b. (a -> b, MyType a) -> MyType b`
1048/// fn map<'a, A: 'a, B: 'a, Func>(
1049/// f: Func,
1050/// fa: Apply!(<Self as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
1051/// ) -> Apply!(<Self as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>)
1052/// where
1053/// Func: Fn(A) -> B + 'a
1054/// {
1055/// todo!()
1056/// }
1057/// }
1058/// }
1059/// pub use inner::*;
1060/// ```
1061#[proc_macro_attribute]
1062pub fn document_module(
1063 attr: TokenStream,
1064 item: TokenStream,
1065) -> TokenStream {
1066 match document_module_worker(attr.into(), item.into()) {
1067 Ok(tokens) => tokens.into(),
1068 Err(e) => e.to_compile_error().into(),
1069 }
1070}
1071
1072/// Monadic do-notation.
1073///
1074/// Desugars flat monadic syntax into nested `bind` calls, matching
1075/// Haskell/PureScript `do` notation.
1076///
1077/// ### Syntax
1078///
1079/// ```ignore
1080/// m_do!(Brand {
1081/// x <- expr; // Bind: extract value from monadic computation
1082/// y: Type <- expr; // Typed bind: with explicit type annotation
1083/// _ <- expr; // Discard bind: sequence, discarding the result
1084/// expr; // Sequence: discard result (shorthand for `_ <- expr;`)
1085/// let z = expr; // Let binding: pure, not monadic
1086/// let w: Type = expr; // Typed let binding
1087/// expr // Final expression: no semicolon, returned as-is
1088/// })
1089/// ```
1090///
1091/// * `Brand`: The monad brand type (e.g., `OptionBrand`, `VecBrand`).
1092/// * `x <- expr;`: Binds the result of a monadic expression to a pattern.
1093/// * `let z = expr;`: A pure let binding (not monadic).
1094/// * `expr;`: Sequences a monadic expression, discarding the result.
1095/// * `expr` (final): The return expression, emitted as-is.
1096///
1097/// Bare `pure(args)` calls are automatically rewritten to `pure::<Brand, _>(args)`.
1098///
1099/// ### Statement Forms
1100///
1101/// | Syntax | Expansion |
1102/// |--------|-----------|
1103/// | `x <- expr;` | `bind::<Brand, _, _>(expr, move \|x\| { … })` |
1104/// | `x: Type <- expr;` | `bind::<Brand, _, _>(expr, move \|x: Type\| { … })` |
1105/// | `_ <- expr;` | `bind::<Brand, _, _>(expr, move \|_\| { … })` |
1106/// | `expr;` | `bind::<Brand, _, _>(expr, move \|_\| { … })` |
1107/// | `let x = expr;` | `{ let x = expr; … }` |
1108/// | `expr` (final) | Emitted as-is |
1109///
1110/// ### Generates
1111///
1112/// Nested `bind` calls equivalent to hand-written monadic code.
1113///
1114/// ### Examples
1115///
1116/// ```ignore
1117/// // Invocation
1118/// use fp_library::{brands::*, functions::*};
1119/// use fp_macros::m_do;
1120///
1121/// let result = m_do!(OptionBrand {
1122/// x <- Some(5);
1123/// y <- Some(x + 1);
1124/// let z = x * y;
1125/// pure(z)
1126/// });
1127/// assert_eq!(result, Some(30));
1128///
1129/// // Expanded code
1130/// let result = bind::<OptionBrand, _, _>(Some(5), move |x| {
1131/// bind::<OptionBrand, _, _>(Some(x + 1), move |y| {
1132/// let z = x * y;
1133/// pure::<OptionBrand, _>(z)
1134/// })
1135/// });
1136/// ```
1137///
1138/// ```ignore
1139/// // Invocation
1140/// // Works with any monad brand
1141/// let result = m_do!(VecBrand {
1142/// x <- vec![1, 2];
1143/// y <- vec![10, 20];
1144/// pure(x + y)
1145/// });
1146/// assert_eq!(result, vec![11, 21, 12, 22]);
1147/// ```
1148#[proc_macro]
1149pub fn m_do(input: TokenStream) -> TokenStream {
1150 let input = parse_macro_input!(input as DoInput);
1151 match m_do_worker(input) {
1152 Ok(tokens) => tokens.into(),
1153 Err(e) => e.to_compile_error().into(),
1154 }
1155}
1156
1157/// Applicative do-notation.
1158///
1159/// Desugars flat applicative syntax into `pure` / `map` / `lift2`–`lift5`
1160/// calls, matching PureScript `ado` notation. Unlike [`m_do!`], bindings are
1161/// independent: later bind expressions cannot reference earlier bound variables.
1162///
1163/// ### Syntax
1164///
1165/// ```ignore
1166/// a_do!(Brand {
1167/// x <- expr; // Bind: independent applicative computation
1168/// y: Type <- expr; // Typed bind: with explicit type annotation
1169/// _ <- expr; // Discard bind: compute for effect
1170/// expr; // Sequence: shorthand for `_ <- expr;`
1171/// let z = expr; // Let binding: placed inside the combining closure
1172/// let w: Type = expr; // Typed let binding
1173/// expr // Final expression: the combining body
1174/// })
1175/// ```
1176///
1177/// * `Brand`: The applicative brand type (e.g., `OptionBrand`, `VecBrand`).
1178/// * Bind expressions are evaluated independently (applicative, not monadic).
1179/// * `let` bindings before any `<-` are hoisted outside the combinator call.
1180/// * `let` bindings after a `<-` are placed inside the combining closure.
1181/// * Bare `pure(args)` calls in bind expressions are rewritten to `pure::<Brand, _>(args)`.
1182///
1183/// ### Desugaring
1184///
1185/// | Binds | Expansion |
1186/// |-------|-----------|
1187/// | 0 | `pure::<Brand, _>(final_expr)` |
1188/// | 1 | `map::<Brand, _, _>(\|x\| body, expr)` |
1189/// | N (2–5) | `liftN::<Brand, _, …>(\|x, y, …\| body, expr1, expr2, …)` |
1190///
1191/// ### Examples
1192///
1193/// ```ignore
1194/// use fp_library::{brands::*, functions::*};
1195/// use fp_macros::a_do;
1196///
1197/// // Two independent computations combined with lift2
1198/// let result = a_do!(OptionBrand {
1199/// x <- Some(3);
1200/// y <- Some(4);
1201/// x + y
1202/// });
1203/// assert_eq!(result, Some(7));
1204///
1205/// // Expands to:
1206/// let result = lift2::<OptionBrand, _, _, _>(|x, y| x + y, Some(3), Some(4));
1207///
1208/// // Single bind uses map
1209/// let result = a_do!(OptionBrand { x <- Some(5); x * 2 });
1210/// assert_eq!(result, Some(10));
1211///
1212/// // No binds uses pure
1213/// let result: Option<i32> = a_do!(OptionBrand { 42 });
1214/// assert_eq!(result, Some(42));
1215/// ```
1216#[proc_macro]
1217pub fn a_do(input: TokenStream) -> TokenStream {
1218 let input = parse_macro_input!(input as DoInput);
1219 match a_do_worker(input) {
1220 Ok(tokens) => tokens.into(),
1221 Err(e) => e.to_compile_error().into(),
1222 }
1223}