1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use proc_macro2::{Delimiter, Group, Spacing, TokenStream, TokenTree};
use quote::quote;
use std::{iter, mem};
pub fn flag_evaluated(input: TokenStream) -> TokenStream {
fn do_flagging(input: TokenStream) -> TokenStream {
let mut iter = input.into_iter().peekable();
let mut cur = None;
iter::from_fn(move || {
loop {
let prev = mem::take(&mut cur);
if let Some(token) = iter.next() {
let next = iter.peek_mut();
cur = Some(token);
match (&prev, cur.as_ref().unwrap(), next) {
// #identifier
(_, TokenTree::Punct(p), Some(tt))
if p.as_char() == '#' && p.spacing() == Spacing::Alone =>
{
let wrapped: TokenStream = quote!(::tank::evaluated!(#tt)).into();
iter.next(); // Consume the following token
return Some(TokenTree::Group(Group::new(
Delimiter::None,
wrapped.into(),
)));
}
// Asterisk preceeded by '.' or ','
(Some(TokenTree::Punct(a)), TokenTree::Punct(b), _)
if matches!(a.as_char(), '.' | ',') && b.as_char() == '*' =>
{
return Some(TokenTree::Group(Group::new(
Delimiter::None,
quote!(::tank::asterisk!()),
)));
}
// Asterisk as the first character
(None, TokenTree::Punct(p), None) if p.as_char() == '*' => {
return Some(TokenTree::Group(Group::new(
Delimiter::None,
quote!(::tank::asterisk!()),
)));
}
// Question mark
(_, TokenTree::Punct(punct), _) if punct.as_char() == '?' => {
return Some(TokenTree::Group(Group::new(
Delimiter::None,
quote!(::tank::question_mark!()),
)));
}
// Nested
(_, TokenTree::Group(group), _) => {
let content = do_flagging(group.stream());
return Some(TokenTree::Group(Group::new(group.delimiter(), content)));
}
// NOT
(Some(..), TokenTree::Ident(cur), Some(TokenTree::Ident(next)))
if cur == "NOT"
&& matches!(next.to_string().as_str(), "LIKE" | "IN") =>
{
// Do not emit the NOT, just skip it
continue;
}
_ => {}
}
return cur.clone();
} else {
return None;
}
}
})
.collect()
}
do_flagging(input)
}