temps_macros/
lib.rs

1use proc_macro::{Span, TokenStream};
2use quote::quote;
3use syn::{parse_macro_input, Ident};
4
5fn capitalize(input: &str) -> String {
6    let mut chars = input.chars();
7    match chars.next() {
8        None => String::new(),
9        Some(f) => f.to_uppercase().chain(chars).collect(),
10    }
11}
12
13#[proc_macro]
14pub fn time_parser(token_stream: TokenStream) -> TokenStream {
15    let lang = parse_macro_input!(token_stream as syn::Path);
16    let lang = lang.get_ident().unwrap();
17
18    let span = Span::call_site().into();
19    let fn_name = Ident::new(&format!("parse_time_{}", lang), span);
20    let lang_capitalized = capitalize(&lang.to_string());
21
22    let error_name = Ident::new(&format!("{}TimeParseError", lang_capitalized), span);
23    let time_parser_name = Ident::new(&format!("{}TimeParser", lang_capitalized), span);
24
25    let expanded = quote! {
26        use pest::iterators::Pair;
27        use pest::Parser;
28
29
30
31        pub fn #fn_name(
32            input: &str,
33        ) -> Result<crate::#lang::Time, crate::#lang::#error_name> {
34            let pairs =
35                crate::#lang::#time_parser_name::parse(crate::#lang::Rule::time, input)?;
36            let pairs = pairs.flatten().collect::<Vec<Pair<crate::#lang::Rule>>>();
37
38            let rules_and_str = pairs
39                .iter()
40                .map(|pair| (pair.as_rule(), pair.as_str()))
41                .collect::<Vec<(crate::#lang::Rule, &str)>>();
42
43            match rules_and_str.as_slice() {
44                [(crate::#lang::Rule::now, _), (crate::#lang::Rule::EOI, _)] => {
45                    Ok(crate::#lang::Time::Now)
46                }
47                _ => Err(crate::#lang::#error_name::UnexpectedPattern),
48            }
49        }
50    };
51
52    TokenStream::from(expanded)
53}