#![doc = include_str!("../README.md")]
use proc_macro2::TokenStream;
#[cfg(test)]
use quote::quote;
mod product;
use product::Product;
mod token;
pub enum ScopeMode {
Expand,
SubExpand,
AutoBraceSemi,
}
pub fn expand_products(input: TokenStream, mode: ScopeMode) -> TokenStream {
Product::new(input).parse(mode).expand()
}
#[cfg(test)]
macro_rules! assert_expansion {
($expand_mode:ident {$($in:tt)*} == {$($out:tt)*}) => {
let input = quote! { $($in)* };
let output = expand_products(input, ScopeMode::$expand_mode);
let expected = quote! { $($out)* };
assert_eq!(output.to_string(), expected.to_string());
};
($($in:tt)*) => {
assert_expansion!(Expand {$($in)*} == {$($in)*});
};
(SubExpand $($in:tt)*) => {
assert_expansion!(SubExpand {$($in)*} == {$($in)*});
};
}
#[test]
fn smoke() {
assert_expansion! {
#[newtype]
pub struct MyNewtype<T>(T);
};
}
#[test]
fn smoke_sub() {
assert_expansion! {
noexpand
#[newtype]
pub struct MyNewtype<T>(T);
};
}
#[test]
fn test_tt_groups_parsed_recursive() {
let input = quote! {
{{$$}}
};
let output = expand_products(input, ScopeMode::Expand);
assert_eq!(output.to_string(), "{ { $ } }");
}
#[test]
fn test_scopes() {
assert_expansion! {
Expand {
foo ${bar ${baz}}
} == {
foo bar baz
}
};
}
#[test]
fn test_sub_scopes() {
assert_expansion! {
SubExpand {
foo ${bar ${baz}}
} == {
foo bar baz
}
};
}
#[test]
fn expand_at_escaping() {
assert_expansion! {
Expand {
$$ ${$$ foo}
} == {
$ $ foo
}
};
}
#[test]
#[should_panic]
fn single_at_is_invalid() {
assert_expansion! {
Expand {
$
} == {
$
}
};
}
#[test]
fn noexpand_leaves_at_verbatim() {
assert_expansion! {
SubExpand {
$ ${$$}
} == {
$ $
}
};
}
#[test]
fn simple_expand_unnamed() {
assert_expansion! {
Expand {
$((foo))
} == {
foo
}
};
}
#[test]
fn simple_expand_named() {
assert_expansion! {
Expand {
$(bar: (foo))
$bar
} == {
foo
}
};
}
#[test]
fn simple_expand_named_visible() {
assert_expansion! {
Expand {
$($bar: (foo))
} == {
foo
}
};
}
#[test]
fn empty_defintions_expand() {
assert_expansion! {
Expand {
$(()()())
$((foo)(bar)) ;
} == {
foo ;
foo ;
foo ;
bar ;
bar ;
bar ;
}
};
}