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
extern crate proc_macro; use pmutil::ToTokensExt; use syn::{ fold::{fold_block, Fold}, parse2, Block, Expr, ImplItem, Item, Stmt, }; mod unbox; mod unwrap; #[proc_macro_attribute] pub fn asserter( _: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { match parse2::<Item>(input.clone().into()) { Ok(v) => Expander.fold_item(v).dump().into(), Err(_) => match parse2::<ImplItem>(input.into()) { Ok(v) => Expander.fold_impl_item(v).dump().into(), Err(_) => panic!("failed to parse input as Item / ImplItem"), }, } } struct Expander; impl Fold for Expander { fn fold_block(&mut self, b: Block) -> Block { let b = fold_block(self, b); let mut stmts = vec![]; let mut base = b.stmts.into_iter(); loop { let stmt = match base.next() { Some(v) => v, None => break, }; match stmt { Stmt::Semi(Expr::Macro(mac), semi) if mac.mac.path.is_ident("unwrap") => { let stmt = Stmt::Semi(crate::unwrap::expand(mac.mac.tokens, base.collect()), semi); stmts.push(stmt); break; } Stmt::Expr(Expr::Macro(mac)) if mac.mac.path.is_ident("unwrap") => { let stmt = Stmt::Expr(crate::unwrap::expand(mac.mac.tokens, base.collect())); stmts.push(stmt); break; } _ => stmts.push(stmt), } } Block { stmts, ..b } } }