1#[doc = include_str!("../README.md")]
2#[cfg(not(doctest))]
3extern crate proc_macro;
4
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::{parse_macro_input, Expr, ExprLit, ExprMacro, Lit};
8
9#[proc_macro]
10pub fn dot(input: TokenStream) -> TokenStream {
11 let inputs = parse_macro_input!(input with syn::punctuated::Punctuated::<Expr, syn::Token![,]>::parse_terminated);
12
13 let nodes = inputs.iter().map(|expr| {
14 match expr {
15 Expr::Macro(ExprMacro { mac, .. }) => {
16 quote! { #mac }
18 }
19 Expr::Lit(ExprLit { lit, .. }) => match lit {
20 Lit::Char(c) => {
21 let count = gregex_logic::TERMINAL_COUNT
22 .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
23 quote! {
24 gregex_logic::translation::node::Node::Terminal(#c, #count)
25 }
26 }
27 _ => panic!("Unsupported literal type"),
28 },
29 _ => panic!("Unsupported input type"),
30 }
31 });
32
33 let mut iter = nodes.into_iter();
35 let first = iter.next().expect("The input is empty");
36 let operations = iter.fold(first, |left, right| {
37 quote! {
38 gregex_logic::translation::node::Node::Operation(
39 gregex_logic::translation::operator::Operator::Concat,
40 Box::new(#left),
41 Some(Box::new(#right))
42 )
43 }
44 });
45
46 let gen = quote! {
48 #operations
49 };
50
51 gen.into()
52}
53
54#[proc_macro]
55pub fn or(input: TokenStream) -> TokenStream {
56 let inputs = parse_macro_input!(input with syn::punctuated::Punctuated::<Expr, syn::Token![,]>::parse_terminated);
57
58 let nodes = inputs.iter().map(|expr| {
59 match expr {
60 Expr::Macro(ExprMacro { mac, .. }) => {
61 quote! { #mac }
63 }
64 Expr::Lit(ExprLit { lit, .. }) => match lit {
65 Lit::Char(c) => {
66 let count = gregex_logic::TERMINAL_COUNT
67 .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
68 quote! {
69 gregex_logic::translation::node::Node::Terminal(#c, #count)
70 }
71 }
72 _ => panic!("Unsupported literal type"),
73 },
74 _ => panic!("Unsupported input type"),
75 }
76 });
77
78 let mut iter = nodes.into_iter();
80 let first = iter.next().expect("The input is empty");
81 let operations = iter.fold(first, |left, right| {
82 quote! {
83 gregex_logic::translation::node::Node::Operation(
84 gregex_logic::translation::operator::Operator::Or,
85 Box::new(#left),
86 Some(Box::new(#right))
87 )
88 }
89 });
90
91 let gen = quote! {
93 #operations
94 };
95
96 gen.into()
97}
98
99#[proc_macro]
100pub fn star(input: TokenStream) -> TokenStream {
101 let expr = parse_macro_input!(input as Expr);
102
103 let node = match expr {
104 Expr::Macro(ExprMacro { mac, .. }) => {
105 quote! { #mac }
107 }
108 Expr::Lit(ExprLit { lit, .. }) => match lit {
109 Lit::Char(c) => {
110 let count =
111 gregex_logic::TERMINAL_COUNT.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
112 quote! {
113 gregex_logic::translation::node::Node::Terminal(#c, #count)
114 }
115 }
116 _ => panic!("Unsupported literal type"),
117 },
118 _ => panic!("Unsupported input type"),
119 };
120
121 let operation = quote! {
123 gregex_logic::translation::node::Node::Operation(
124 gregex_logic::translation::operator::Operator::Production,
125 Box::new(#node),
126 None
127 )
128 };
129
130 let gen = quote! {
132 #operation
133 };
134
135 gen.into()
136}
137
138#[proc_macro]
139pub fn regex(input: TokenStream) -> TokenStream {
140 let expr = parse_macro_input!(input as Expr);
141
142 let node = match expr {
144 Expr::Macro(ExprMacro { mac, .. }) => {
145 quote! { #mac }
147 }
148 Expr::Lit(ExprLit { lit, .. }) => match lit {
149 Lit::Char(c) => {
150 let count =
151 gregex_logic::TERMINAL_COUNT.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
152 quote! {
153 gregex_logic::translation::node::Node::Terminal(#c, #count)
154 }
155 }
156 _ => panic!("Unsupported literal type"),
157 },
158 _ => panic!("Unsupported input type"),
159 };
160
161 let gen = quote! {
163 {
164 let regex_tree = #node;
165 let prefix_set = gregex_logic::translation::node::prefix_set(®ex_tree);
166 let suffix_set = gregex_logic::translation::node::suffix_set(®ex_tree);
167 let factors_set = gregex_logic::translation::node::factors_set(®ex_tree);
168 gregex_logic::nfa::NFA::set_to_nfa(&prefix_set, &suffix_set, &factors_set)
169 }
170 };
171
172 gen.into()
173}