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 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 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}