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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#![allow(clippy::or_fun_call)]
#![allow(clippy::useless_conversion)]
#![allow(irrefutable_let_patterns)]
extern crate proc_macro;
#[cfg(not(feature = "proc_macro2_"))]
use proc_macro as used_proc_macro;
#[cfg(feature = "proc_macro2_")]
use proc_macro2 as used_proc_macro;
use std::iter;
#[allow(unused_imports)]
use used_proc_macro::{
Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
mod parsing;
mod utils;
#[doc(hidden)]
#[proc_macro]
pub fn __priv_bstr_start(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
bstr_pattern(input_tokens.into(), StrAt::Start).into()
}
#[doc(hidden)]
#[proc_macro]
pub fn __priv_bstr_end(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
bstr_pattern(input_tokens.into(), StrAt::End).into()
}
fn bstr_pattern(input_tokens: TokenStream, str_at: StrAt) -> TokenStream {
use crate::utils::punct_token;
let parsed = parsing::parse_inputs(input_tokens);
match parsed {
Ok(Inputs { rem_ident, strings }) => {
let mut out = TokenStream::new();
for (i, patt) in strings.iter().enumerate() {
let span = patt.span(&rem_ident);
if i != 0 {
out.extend(punct_token('|', span));
}
let tt = crate::utils::bracket(Span::call_site(), |out| match str_at {
StrAt::Start => {
output_patt(patt, out);
output_remainder_pat(&rem_ident, out);
}
StrAt::End => {
output_remainder_pat(&rem_ident, out);
out.extend(punct_token(',', span));
output_patt(patt, out);
}
});
out.extend(iter::once(tt))
}
out
}
Err(e) => e.to_compile_error(),
}
}
fn output_patt(patt: &Pattern, out: &mut TokenStream) {
use crate::utils::punct_token;
match patt {
Pattern::String { string, span } => {
for b in string.bytes() {
let mut lit = Literal::u8_unsuffixed(b);
lit.set_span(*span);
out.extend(iter::once(TokenTree::from(lit)));
out.extend(punct_token(',', *span));
}
}
}
}
fn output_remainder_pat(patt: &Ident, out: &mut TokenStream) {
use crate::utils::{punct_joint_token2, punct_token};
out.extend(iter::once(TokenTree::from(patt.clone())));
out.extend(punct_token('@', patt.span()));
out.extend(punct_joint_token2('.', '.', patt.span()));
}
struct Inputs {
rem_ident: Ident,
strings: Vec<Pattern>,
}
enum Pattern {
String { string: String, span: Span },
}
enum StrAt {
Start,
End,
}
impl Pattern {
fn span(&self, _rem_ident: &Ident) -> Span {
match self {
Pattern::String { span, .. } => *span,
}
}
}