bird_machine_macros/
lib.rs1extern crate proc_macro;
2use proc_macro::TokenStream;
3
4use proc_macro2::Ident;
5use quote::{format_ident, quote, ToTokens};
6use syn::{parse_macro_input, DeriveInput, LitStr};
7
8mod dfa;
9mod nfa;
10
11#[proc_macro_attribute]
12pub fn bird_machine(args: TokenStream, input: TokenStream) -> TokenStream {
13 let input = parse_macro_input!(input as DeriveInput);
14 let input_regex = parse_macro_input!(args as LitStr);
15
16 let input_type_name = &input.ident;
17 let input_lifetimes: Vec<_> = input.generics.lifetimes().collect();
18 let lifetime = match input_lifetimes.as_slice() {
19 [] => quote! { 'unrestricted },
20 [lt] => quote! { #lt },
21 _ => panic!("multiple lifetime generics, what is this, pls to halp"),
22 };
23
24 let machine_fn = format_ident!("bird_machine_for_{}", input_type_name);
25 let machine = build_machine(&input_regex, &machine_fn);
26 eprintln!("{}", &machine);
27
28 let (_, ty_generics, where_clause) = input.generics.split_for_impl();
29
30 let impl_decl = quote! {
31 impl<#lifetime> ::bird_machine::Machine<#lifetime> for #input_type_name #ty_generics #where_clause
32 };
33 let original_regex = quote! {
34 const ORIGINAL_REGEX: &'static str = #input_regex;
35 };
36 let captures = quote! {
37 fn captures(text: &#lifetime str) -> Option<Self> {
38 todo!()
39 }
40 };
41 let captures_iter = quote! {
42 type CaptureIterator = ::std::iter::Empty<Self>;
43 fn captures_iter(text: &#lifetime str) -> Self::CaptureIterator {
44 todo!()
45 }
46 };
47 let find = quote! {
48 fn find(text: &#lifetime str) -> Option<::bird_machine::Match<#lifetime>> {
49 todo!()
50 }
51 };
52 let find_at = quote! {
53 fn find_at(text: &#lifetime str, start: usize) -> Option<::bird_machine::Match<#lifetime>> {
54 todo!()
55 }
56 };
57 let find_iter = quote! {
58 type FindIterator = ::std::iter::Empty<::bird_machine::Match<#lifetime>>;
59 fn find_iter(text: &#lifetime str) -> Self::FindIterator {
60 todo!()
61 }
62 };
63 let is_match = quote! {
64 fn is_match(text: &#lifetime str) -> bool {
65 #machine_fn(text)
66 }
67 };
68 let is_match_at = quote! {
69 fn is_match_at(text: &#lifetime str, start: usize) -> bool {
70 todo!()
71 }
72 };
73 let replace = quote! {
74 fn replace(
75 text: &#lifetime str,
76 rep: impl ::bird_machine::Replacer<#lifetime, Self>,
77 ) -> ::std::borrow::Cow<#lifetime, str> {
78 todo!()
79 }
80 };
81 let replace_all = quote! {
82 fn replace_all(
83 text: &#lifetime str,
84 rep: impl ::bird_machine::Replacer<#lifetime, Self>,
85 ) -> ::std::borrow::Cow<#lifetime, str> {
86 todo!()
87 }
88 };
89 let replacen = quote! {
90 fn replacen(
91 text: &#lifetime str,
92 limit: usize,
93 rep: impl ::bird_machine::Replacer<#lifetime, Self>,
94 ) -> ::std::borrow::Cow<#lifetime, str> {
95 todo!()
96 }
97 };
98 let split = quote! {
99 type SplitIterator = ::std::iter::Empty<&#lifetime str>;
100 fn split(text: &#lifetime str) -> Self::SplitIterator {
101 todo!()
102 }
103 };
104 let splitn = quote! {
105 type SplitNIterator = ::std::iter::Empty<&#lifetime str>;
106 fn splitn(text: &#lifetime str, limit: usize) -> Self::SplitNIterator {
107 todo!()
108 }
109 };
110
111 let tokens = quote! {
112 #input
113
114 #machine
115
116 #impl_decl {
117 #original_regex
118 #captures
119 #captures_iter
120 #find
121 #find_at
122 #find_iter
123 #is_match
124 #is_match_at
125 #replace
126 #replace_all
127 #replacen
128 #split
129 #splitn
130 }
131 };
132
133 eprintln!(
134 "{impl_decl} {{\n\n\
135 {original_regex}\n\n\
136 {captures}\n\n\
137 {captures_iter}\n\n\
138 {find}\n\n\
139 {find_at}\n\n\
140 {find_iter}\n\n\
141 {is_match}\n\n\
142 {is_match_at}\n\n\
143 {replace}\n\n\
144 {replace_all}\n\n\
145 {replacen}\n\n\
146 {split}\n\n\
147 {splitn}\n\n\
148 }}",
149 impl_decl = impl_decl,
150 original_regex = original_regex,
151 captures = captures,
152 captures_iter = captures_iter,
153 find = find,
154 find_at = find_at,
155 find_iter = find_iter,
156 is_match = is_match,
157 is_match_at = is_match_at,
158 replace = replace,
159 replace_all = replace_all,
160 replacen = replacen,
161 split = split,
162 splitn = splitn,
163 );
164
165 tokens.into()
166}
167
168fn build_machine(regex: &LitStr, fn_name: &Ident) -> proc_macro2::TokenStream {
169 let regex_text = regex.value();
170 let regex_ir = regex_syntax::Parser::new().parse(®ex_text);
171 let regex_ir = match regex_ir {
172 Ok(x) => x,
173 Err(err) => panic!("error compiling regex {}: {}", regex.to_token_stream(), err),
174 };
175
176 let built_nfa = nfa::NFA::from(®ex_ir);
177 let dfa = dfa::DFA::from(built_nfa);
178
179 quote! {
180 fn #fn_name(input: &str) -> bool {
181 #dfa
182 }
183 }
184}