Skip to content

Instantly share code, notes, and snippets.

@kyleheadley
Last active April 18, 2021 19:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kyleheadley/c2f64e24c14e45b1e39ee664059bd86f to your computer and use it in GitHub Desktop.
Save kyleheadley/c2f64e24c14e45b1e39ee664059bd86f to your computer and use it in GitHub Desktop.
Higher-order rust macro that assists in parsing by macro
/// Higher-order macro fold function for pre-parsing comma separated lists
///
/// The commas on KEYWORD lines can be changed to parse lists with any
/// separator.
/// run a macro on a list of lists after splitting the input at commas
macro_rules! split_comma {
// no defaults
{$fun:ident <= $($item:tt)*} => {
split_comma![$fun () () () <= $($item)*]
};
// give initial params to the function
{$fun:ident ($($first:tt)*) <= $($item:tt)*} => {
split_comma![$fun ($($first)*) () () <= $($item)*]
};
// give inital params and initial inner items in every group
{$fun:ident ($($first:tt)*) ($($every:tt)*) <= $($item:tt)*} => {
split_comma![$fun ($($first)*) ($($every)*) ($($every)*) <= $($item)*]
};
// KEYWORD line
// on non-final seperator, stash the accumulator and restart it
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= , $($item:tt)+} => {
split_comma![$fun ($($first)* ($($current)*)) ($($every)*) ($($every)*) <= $($item)*]
};
// KEYWORD line
// ignore final seperator, run the function
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= , } => {
$fun![$($first)* ($($current)*)]
};
// on next item, add it to the accumulator
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= $next:tt $($item:tt)*} => {
split_comma![$fun ($($first)*) ($($every)*) ($($current)* $next) <= $($item)*]
};
// at end of items, run the function
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= } => {
$fun![$($first)* ($($current)*)]
};
// if there were no items and no default, run with only initial params, if any
{$fun:ident ($($first:tt)*) () () <= } => {
$fun![$($first)*]
};
}
// Macros passed to `split_comma` take optional initial parameters followed by a list of
// parenthesised items. These outer parentheses now separate what was originally separated
// by commas.
macro_rules! sum_vec {
{$(($($item:tt)*))*} => { vec![$(0 $(+ $item )*, )*] };
{debug $($item:tt)*} => { stringify![$($item)*].to_string() };
}
fn main(){
let x = split_comma![sum_vec <= 1 2, 3 4, 5 6];
println!("{:?}",x);
// [3, 7, 11]
let x = split_comma![sum_vec (debug) (hi) <= 4 5,7,,1 2 3,];
println!("{:?}",x);
// "( hi 4 5 ) ( hi 7 ) ( hi ) ( hi 1 2 3 )"
let hi = 8;
let x = split_comma![sum_vec () (hi) <= 4 5,7,,1 2 3];
println!("{:?}",x);
// [17, 15, 8, 14]
let x = split_comma![sum_vec (debug) <= ];
println!("{:?}",x);
// ""
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment