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