1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
#[macro_export]
/**
Helper macro for easily defining types that implement [`crate::Function`].
## Syntax
The body of the macro should contain an arbitrary amount of "function type" items, ending in semicolons.
These "function type" items may have an arbitrary amount of attributes.
Due to how the macro is implemented, `cfg` attributes must be specified _with a @ instead of #_, like this:
`@[cfg(feature = "abc")]`
The body of one of these items is as follows:
```text
pub fn Name<A, B> ::= { C. D. { A, B {C, D}}}
where A: B, {A, B}: {C, D}, /* ... */;
```
It's quite a bit to take in, but it's actually quite simple! Let's break it down.
- The visibility specifier `pub` is optional, defaulting to private, as expected of any other item.
- The `Name` is the name of the type that's publicly exported by the macro.
As you can see, type parameters are also supported, but const generics are unfortunately not.
- Following the `::=` is the actual definition enclosed in `{}` braces.
Everything within the brackets is implicitly passed to `crate::call`.
- The `where` clauses are an unfortunate consequence of using a declarative macro instead of a procedural one,
as the macro can't generate one _for_ us due to the inability to use macro calls as parameter guards.
Both sides of each clause are implicitly passed to `crate::call`.
In order for the compiler to accept your function, you must tell the compiler in these clauses
that all arguments used in the definition are actually _able_ to be used in the way they're used.
A good strategy is to write each call out in the where clause while you're writing, like this:
```text
fn F ::= { A. B. C. { C, {B, A}, C }} where
B: A, // B calls A
C: {B, A}, // C calls {B, A}
{C, {B, A}}: C; // {C, {B, A}} calls C
```
Unfortunately, due to implementation complexity, anonymous functions like this:
```text
// λn.λf.λx. n (λg.λh. h (g f)) (λu.x) (λu.u)
pub fn Predecessor ::= { N. F. X. { N {G. H. H { G, F }}, Constant<X>, Identity } };
```
are unsupported.
Instead, you can break it up into smaller definitions, like this:
```text
pub fn Predecessor ::= { N. F. X. { N, Pred_1<F>, Constant<X>, Identity } };
fn Pred_1<F> ::= { G. H. { H { G, F } } };
```
which is actually the definition used in `crate::math::Predecessor`, sans the `where` clauses.
This macro is **hygienic**.
*/
macro_rules! define {
(
$(
$(#[$meta: meta])*
$(@[$modmeta: meta])*
$vis: vis fn $identifier: ident
$(< $($typearg: ident),+ >)?
::= { $($definition: tt)+ }
$(where $($lhs: tt : $rhs: tt),+ $(,)?)?
;
)*
) => {::paste::paste! {
$(
#[allow(non_snake_case)]
$(#[$modmeta])*
mod [< __$identifier >] {
#![allow(unused_parens, non_camel_case_types, unused_imports)]
use super::*;
$crate::define!{ @item $(#[$meta])* $identifier ; $($($typearg)+)? }
$crate::define!{
@impl $identifier; $($($typearg)+)? ;
{ $($definition)+ }
$(where $($lhs: $rhs),+)?
}
}
$(#[$modmeta])*
$vis use [< __$identifier >]::$identifier;
)*
}};
(
@item $(#[$meta: meta])* $name: ident ; $($($typearg: ident)+)?
) => {
$(#[$meta])*
#[allow(unused_parens)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct $name $( < $($typearg),+ > )? {
_p: ::core::marker::PhantomData<($($($typearg,)+)?)>
}
};
(
@impl $ident: ident ; $($arg: ident)*;
{ $name: ident . $name2: ident . $($definition: tt)+ } $(where $($lhs: tt:$rhs: tt),+)?
) => { ::paste::paste! {
#[allow(non_camel_case_types)]
impl<$($arg, )* $name> $crate::Function<$name> for $ident < $($arg,)* > {
type Output = [< $ident __ $name >] <$($arg,)* $name>;
}
$crate::define! {
@item #[doc(hidden)] [< $ident __ $name >] ; $($arg)* $name
}
$crate::define! {
@impl [<$ident __ $name>] ; $($arg)* $name;
{ $name2 . $($definition)+ } $(where $($lhs : $rhs),+)?
}
} };
(
@impl $ident: ident ; $($args: ident)*;
{ $name: ident . { $($definition: tt)+ } } $(where $($lhs: tt:$rhs: tt),+)?
) => {
#[allow(non_camel_case_types)]
impl<$($args, )* $name> $crate::Function<$name> for $ident <$($args, )*>
$(
where
$(
$crate::call!($lhs) : $crate::Function<$crate::call!($rhs)>
),+
)?
{
type Output = $crate::call!{ $($definition)+ };
}
};
}
/**
Ergonomic wrapper macro for calling a function.
Calling syntax is modeled around the lambda calculus, where:
- `fx` is translated to `f, x`
- `f(...)` is translated to `f, {...}`
So, for example, `ab(c(de)f)gh` translates to `a, b, { c, { d, e }, f }, g, h`.
The whitespace isn't mandatory, but is recommended for readibility (see: `a,b{c,{d,e},f},g,h`).
This macro is **hygienic**.
*/
#[macro_export]
macro_rules! call {
({$($wrapped: tt)+}) => { $crate::call!($($wrapped)+) };
($name: ty) => { $name };
($name: ty , $arg: ty) => {
<$name as $crate::Function<$arg>>::Output
};
($name: ty , { $($arg: tt)+ } $($arg2: tt)*) => {
$crate::call!( $crate::call!($name , $crate::call!($($arg)+) ) $($arg2)* )
};
($name: ty , $arg: ty , $($arg2: tt)+) => {
$crate::call!( $crate::call!($name , $arg), $($arg2)+ )
};
}
/**
Chains applications of a function onto many arguments.
For example, `chained!(Composed with A, B, C, D)` expands to `Composed<A, Composed<B, Composed<C, D>>>`.
This macro is **hygienic**.
*/
#[macro_export]
macro_rules! chained {
($name: ident with $lhs: ty, $rhs: ty $(, $extra: ty)+) => {
$name<$lhs, $crate::chained!($name with $rhs $(, $extra)+)>
};
($name: ident with $lhs: ty, $rhs: ty) => {
$name<$lhs, $rhs>
}
}