extern crate proc_macro;
#[macro_use]
mod debug;
mod fact;
mod session;
mod theory;
mod body;
mod helpers;
mod assertion_derive;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse::Error, parse_macro_input, ItemFn, ItemImpl, ItemStruct};
const DOC_MSG: &str = "Read the documentation at: https://docs.rs/fluid/wiki";
#[proc_macro_attribute]
pub fn fact(args: TokenStream, input: TokenStream) -> TokenStream {
if let Some(tok) = args.into_iter().next() {
let msg = format!(
"The macro `fact` must have no arguments. \
If you want to add some test cases, please use a `theory` with `case`s. {}",
DOC_MSG
);
Error::new(tok.span().into(), msg).to_compile_error().into()
} else {
let mut output: TokenStream = quote!(#[cfg(test)] #[fact_inner]).into();
output.extend(input);
output
}
}
#[doc(hidden)]
#[proc_macro_attribute]
pub fn fact_inner(_args: TokenStream, input: TokenStream) -> TokenStream {
debug!(input);
let output = fact::generate(parse_macro_input!(input as ItemFn))
.unwrap_or_else(|e| e.to_compile_error());
debug!(output);
output.into()
}
#[proc_macro_attribute]
pub fn theory(args: TokenStream, input: TokenStream) -> TokenStream {
if let Some(tok) = args.into_iter().next() {
let msg = format!(
"The macro `theory` must have no arguments. \
If you want to add some test cases, please use the `case` attribute. {}",
DOC_MSG
);
Error::new(tok.span().into(), msg).to_compile_error().into()
} else {
let mut output: TokenStream = quote!(#[cfg(test)] #[theory_inner]).into();
output.extend(input);
output
}
}
#[doc(hidden)]
#[proc_macro_attribute]
pub fn theory_inner(_args: TokenStream, input: TokenStream) -> TokenStream {
debug!(input);
let mut input: ItemFn = parse_macro_input!(input as ItemFn);
let module = theory::generate(
input.ident.clone(),
&mut input.decl,
&mut input.block,
&mut input.attrs,
None,
)
.map(ToTokens::into_token_stream)
.unwrap_or_else(|e| e.to_compile_error());
let output = {
let mut module = module;
module.extend(input.into_token_stream());
module
};
debug!(output);
output.into()
}
#[proc_macro_attribute]
pub fn session(args: TokenStream, input: TokenStream) -> TokenStream {
if let Some(tok) = args.into_iter().next() {
let msg = format!("The macro `session` must have no arguments. {}", DOC_MSG);
Error::new(tok.span().into(), msg).to_compile_error().into()
} else {
let mut output: TokenStream = quote!(#[cfg(test)] #[session_inner]).into();
output.extend(input);
output
}
}
#[doc(hidden)]
#[proc_macro_attribute]
pub fn session_inner(_args: TokenStream, input: TokenStream) -> TokenStream {
debug!(input);
let item = parse_macro_input!(input as ItemImpl);
let output = session::generate(item).unwrap_or_else(|e| e.to_compile_error());
debug!(output);
output.into()
}
#[proc_macro_derive(Drop)]
pub fn drop_derive(input: TokenStream) -> TokenStream {
use assertion_derive::*;
debug!(input);
let item = parse_macro_input!(input as ItemStruct);
let output = generate(item).unwrap_or_else(|e| e.to_compile_error());
debug!(output);
output.into()
}