vec_reg_macro/
lib.rs

1use proc_macro::TokenStream;
2use syn::parse::{Parse, ParseStream};
3use syn::{braced, bracketed, parenthesized, parse_macro_input, Result};
4
5#[derive(Debug)]
6struct RegexMacroInput {
7    tt: proc_macro2::TokenStream,
8}
9
10impl RegexMacroInput {
11    fn parse_any(input: ParseStream) -> Result<proc_macro2::TokenStream> {
12        if let Err(err) = input.parse::<syn::Token![.]>() {
13            return Err(err);
14        }
15        Ok(syn::parse_quote!(vec_reg_common::Regex::any()))
16    }
17
18    // parse [#<ident>] or [#<closure>] syntax to Regex::statisfy
19    fn parse_satisfy(input: ParseStream) -> Result<proc_macro2::TokenStream> {
20        if !input.peek(syn::token::Bracket) {
21            return Err(syn::Error::new(input.span(), "expected brace"));
22        }
23
24        let braced_content;
25        bracketed!(braced_content in input);
26        let inverse = braced_content.parse::<syn::Token![^]>().is_ok();
27        if let Ok(fn_name) = braced_content.parse::<syn::Ident>() {
28            if inverse {
29                Ok(syn::parse_quote!(vec_reg_common::Regex::not_satisfy(#fn_name)))
30            } else {
31                Ok(syn::parse_quote!(vec_reg_common::Regex::satisfy(#fn_name)))
32            }
33        } else if let Ok(closure) = braced_content.parse::<syn::ExprClosure>() {
34            if inverse {
35                Ok(syn::parse_quote!(vec_reg_common::Regex::not_satisfy(#closure)))
36            } else {
37                Ok(syn::parse_quote!(vec_reg_common::Regex::satisfy(#closure)))
38            }
39        } else {
40            Err(syn::Error::new(
41                input.span(),
42                "expected closure or function name",
43            ))
44        }
45    }
46
47    // parse ?, +, *, {n}, {n,}, {n,m} meta characters.
48    fn parse_optional_meta_character(
49        input: ParseStream,
50        base_regex_expr: proc_macro2::TokenStream,
51    ) -> Result<proc_macro2::TokenStream> {
52        if input.parse::<syn::token::Question>().is_ok() {
53            let greedy = input.parse::<syn::token::Question>().is_err();
54            Ok(syn::parse_quote!(vec_reg_common::Regex::zero_or_one(#base_regex_expr, #greedy)))
55        } else if input.parse::<syn::token::Star>().is_ok() {
56            let greedy = input.parse::<syn::token::Question>().is_err();
57            Ok(syn::parse_quote!(vec_reg_common::Regex::repeat0(#base_regex_expr, #greedy)))
58        } else if input.parse::<syn::Token![+]>().is_ok() {
59            let greedy = input.parse::<syn::token::Question>().is_err();
60            Ok(syn::parse_quote!(vec_reg_common::Regex::repeat1(#base_regex_expr, #greedy)))
61        } else if input.peek(syn::token::Brace) {
62            let braced_content;
63            braced!(braced_content in input);
64            let greedy = input.parse::<syn::token::Question>().is_err();
65            if let Ok(n_lit) = braced_content.parse::<syn::LitInt>() {
66                if braced_content.parse::<syn::token::Comma>().is_err() {
67                    Ok(syn::parse_quote!(vec_reg_common::Regex::repeat_n(#base_regex_expr, #n_lit)))
68                } else if let Ok(m_lit) = braced_content.parse::<syn::LitInt>() {
69                    Ok(
70                        syn::parse_quote!(vec_reg_common::Regex::repeat_min_max(#base_regex_expr, #n_lit, #m_lit, #greedy)),
71                    )
72                } else if braced_content.is_empty() {
73                    Ok(
74                        syn::parse_quote!(vec_reg_common::Regex::repeat_n_or_more(#base_regex_expr, #n_lit, #greedy)),
75                    )
76                } else {
77                    Err(syn::Error::new(
78                        braced_content.span(),
79                        "expected integer literal or empty",
80                    ))
81                }
82            } else {
83                Err(syn::Error::new(input.span(), "expected integer literal"))
84            }
85        } else {
86            Ok(base_regex_expr)
87        }
88    }
89
90    fn parse_atom(input: ParseStream) -> Result<proc_macro2::TokenStream> {
91        if let Ok(any_regex) = Self::parse_any(input) {
92            Ok(any_regex)
93        } else if let Ok(satisfy_regex) = Self::parse_satisfy(input) {
94            Ok(satisfy_regex)
95        } else if input.peek(syn::token::Paren) {
96            let parend_content;
97            parenthesized!(parend_content in input);
98            let mut capturing = true;
99            let mut name = None;
100            if parend_content.parse::<syn::token::Question>().is_ok() {
101                if parend_content.parse::<syn::token::Colon>().is_ok() {
102                    capturing = false;
103                } else if parend_content.peek(syn::Ident) {
104                    let parsed_ident = parend_content.parse::<syn::Ident>()?;
105                    if parsed_ident.to_string().as_str() != "P" {
106                        return Err(syn::Error::new(parsed_ident.span(), "expected 'P'"));
107                    }
108                    if let Err(err) = parend_content.parse::<syn::Token![<]>() {
109                        return Err(err);
110                    }
111                    match parend_content.parse::<syn::LitStr>() {
112                        Ok(group_name) => {
113                            name = Some(group_name);
114                        }
115                        Err(err) => return Err(err),
116                    }
117                    if let Err(err) = parend_content.parse::<syn::Token![>]>() {
118                        return Err(err);
119                    }
120                }
121            }
122            match Self::parse_expr(&parend_content) {
123                Ok(expr) => {
124                    if capturing && name.is_none() {
125                        Ok(syn::parse_quote!(vec_reg_common::Regex::group(#expr)))
126                    } else if capturing && name.is_some() {
127                        let name = name.unwrap();
128                        Ok(syn::parse_quote!(vec_reg_common::Regex::named_group(#name, #expr)))
129                    } else {
130                        Ok(syn::parse_quote!(vec_reg_common::Regex::non_capturing_group(#expr)))
131                    }
132                }
133                Err(error) => Err(error),
134            }
135        } else {
136            Err(syn::Error::new(
137                input.span(),
138                "expected '.', {#<ident>}, {#<closure>}, (#<regex>), (?:#<regex>) or (?P<\"name\">#<regex>)",
139            ))
140        }
141    }
142
143    fn parse_factor(input: ParseStream) -> Result<proc_macro2::TokenStream> {
144        if input.parse::<syn::token::Caret>().is_ok() {
145            Ok(syn::parse_quote!(vec_reg_common::Regex::begin()))
146        } else if input.parse::<syn::token::Dollar>().is_ok() {
147            Ok(syn::parse_quote!(vec_reg_common::Regex::end()))
148        } else {
149            match Self::parse_atom(input) {
150                Ok(atom) => Self::parse_optional_meta_character(input, atom),
151                Err(error) => Err(error),
152            }
153        }
154    }
155
156    fn parse_term(input: ParseStream) -> Result<proc_macro2::TokenStream> {
157        let mut factors = vec![];
158
159        let factor = Self::parse_factor(input)?;
160        factors.push(factor);
161
162        while let Ok(f) = Self::parse_factor(input) {
163            factors.push(f);
164        }
165
166        if factors.len() == 1 {
167            Ok(factors[0].clone())
168        } else {
169            let mut reg = factors[0].clone();
170            for f in factors.iter().skip(1) {
171                reg = syn::parse_quote!(vec_reg_common::Regex::concat(#reg, #f));
172            }
173            Ok(reg)
174        }
175    }
176
177    fn parse_expr(input: ParseStream) -> Result<proc_macro2::TokenStream> {
178        let term = Self::parse_term(input)?;
179        let mut terms = vec![];
180        terms.push(term);
181
182        while input.parse::<syn::Token![|]>().is_ok() {
183            terms.push(Self::parse_term(input)?);
184        }
185
186        let mut reg = terms[0].clone();
187        for f in terms.iter().skip(1) {
188            reg = syn::parse_quote!(vec_reg_common::Regex::or(#reg, #f));
189        }
190        Ok(reg)
191    }
192}
193
194impl Parse for RegexMacroInput {
195    fn parse(input: ParseStream) -> Result<Self> {
196        match Self::parse_expr(input) {
197            Ok(tt) => {
198                if input.is_empty() {
199                    Ok(Self { tt })
200                } else {
201                    Err(syn::Error::new(input.span(), "unexpected tokens"))
202                }
203            }
204            Err(error) => Err(error),
205        }
206    }
207}
208
209impl From<RegexMacroInput> for proc_macro2::TokenStream {
210    fn from(input: RegexMacroInput) -> Self {
211        input.tt
212    }
213}
214
215#[proc_macro]
216pub fn vec_reg(input: TokenStream) -> TokenStream {
217    let input = parse_macro_input!(input as RegexMacroInput);
218    let output: proc_macro2::TokenStream = input.into();
219
220    output.into()
221}