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
#![recursion_limit = "128"] extern crate proc_macro; use crate::proc_macro::TokenStream; use quote::{quote, ToTokens}; use std::str::FromStr; use syn::{self, parse_macro_input, parse_quote, AttributeArgs, FnArg, ItemFn, Stmt}; #[proc_macro_attribute] pub fn both_parser(attr: TokenStream, item: TokenStream) -> TokenStream { let attr = parse_macro_input!(attr as AttributeArgs); let item = parse_macro_input!(item as ItemFn); impl_both_parser(&attr, &item) } fn impl_both_parser(_attr: &AttributeArgs, item: &ItemFn) -> TokenStream { let body = impl_both_parser_body(&item); let body = parse_macro_input!(body as Stmt); let mut item = item.clone(); item.block.stmts.clear(); item.block.stmts.push(body); item.into_token_stream().into() } fn impl_both_parser_body(item: &ItemFn) -> TokenStream { let input = if let Some(x) = &item.decl.inputs.first() { match x.value() { FnArg::Captured(arg) => &arg.pat, _ => panic!("function with #[both_parser] must have an argument"), } } else { panic!("function with #[both_parser] must have an argument"); }; let body = item.block.as_ref(); let mut body_token = body.into_token_stream().to_string(); let both_cnt: Vec<&str> = body_token.matches("both").collect(); let both_cnt = both_cnt.len(); let mut replace_parsers = Vec::new(); for i in 0..both_cnt { let pos = body_token.find("both").unwrap(); let (head, rest) = body_token.split_at(pos); if rest.starts_with("both_opt") { let rest = rest.replacen("both_opt", &format!("b_temporary{}", i), 1); body_token = format!("{}{}", head, rest); replace_parsers.push(("nom_both::some", "nom_both::none")); } else if rest.starts_with("both_alt") { let rest = rest.replacen("both_alt", &format!("b_temporary{}", i), 1); body_token = format!("{}{}", head, rest); replace_parsers.push(("nom_both::alt_left", "nom_both::alt_right")); } } let mut gen = quote! {}; for i in 0..2_u32.pow(both_cnt as u32) { let mut body_token = body_token.clone(); for j in 0..both_cnt { let (p0, p1) = replace_parsers[j]; let repl = if ((i >> j) & 1) == 0 { p0 } else { p1 }; body_token = body_token.replace(&format!("b_temporary{}", j), repl); } let body_token = format!("{{ {} }}", body_token); let body_token = TokenStream::from_str(&body_token).unwrap(); let body_token = parse_macro_input!(body_token as Stmt); gen = quote! { #gen |#input| #body_token, }; } let gen = quote! { { alt(( #gen ))(s) } }; gen.into() }