mod args;
mod regex_code;
use {
crate::{
args::*,
regex_code::*,
},
proc_macro::TokenStream,
quote::quote,
syn::{Expr, ExprClosure, parse_macro_input},
};
fn process<T, F>(input: TokenStream, f: F) -> TokenStream
where T: Into<TokenStream>, F: Fn(RegexCode) -> T {
f(RegexCode::from(input)).into()
}
fn process_with_value<T, F>(input: TokenStream, f: F) -> TokenStream
where T: Into<TokenStream>, F: Fn(RegexCode, Expr) -> T {
let parsed = parse_macro_input!(input as RexValArgs);
f(RegexCode::from(parsed.regex_str), parsed.value).into()
}
fn process_with_value_fun<T, F>(input: TokenStream, f: F) -> TokenStream
where T: Into<TokenStream>,
F: Fn(RegexCode, Expr, ExprClosure) -> T {
let parsed = parse_macro_input!(input as RexValFunArgs);
f(RegexCode::from(parsed.regex_str), parsed.value, parsed.fun).into()
}
#[proc_macro]
pub fn regex(input: TokenStream) -> TokenStream {
process(input, |regex_code| regex_code.lazy_static())
}
#[proc_macro]
pub fn lazy_regex(input: TokenStream) -> TokenStream {
process(input, |regex_code| regex_code.build)
}
#[proc_macro]
pub fn regex_is_match(input: TokenStream) -> TokenStream {
process_with_value(input, |regex_code, value| {
let statick = regex_code.statick();
quote! {{
#statick;
RE.is_match(#value)
}}
})
}
#[proc_macro]
pub fn regex_find(input: TokenStream) -> TokenStream {
process_with_value(input, |regex_code, value| {
let statick = regex_code.statick();
let as_method = if regex_code.is_bytes {
quote! { as_bytes }
} else {
quote! { as_str }
};
quote! {{
#statick;
RE.find(#value).map(|mat| mat. #as_method ())
}}
})
}
#[proc_macro]
pub fn regex_captures(input: TokenStream) -> TokenStream {
process_with_value(input, |regex_code, value| {
let statick = regex_code.statick();
let n = regex_code.captures_len();
let groups = (0..n).map(|i| {
quote! {
caps.get(#i).map_or("", |c| c.as_str())
}
});
quote! {{
#statick;
RE.captures(#value)
.map(|caps| (
#(#groups),*
))
}}
})
}
fn replacen(input: TokenStream, limit: usize) -> TokenStream {
process_with_value_fun(input, |regex_code, value, fun| {
let statick = regex_code.statick();
let n = regex_code.captures_len();
let groups = (0..n).map(|i| {
quote! {
caps.get(#i).map_or("", |c| c.as_str())
}
});
quote! {{
#statick;
RE.replacen(
#value,
#limit,
|caps: &lazy_regex::Captures<'_>| {
let fun = #fun;
fun(
#(#groups),*
)
})
}}
})
}
#[proc_macro]
pub fn regex_replace(input: TokenStream) -> TokenStream {
replacen(input, 1)
}
#[proc_macro]
pub fn regex_replace_all(input: TokenStream) -> TokenStream {
replacen(input, 0)
}