core_extensions_proc_macros/
parsing_shared.rs
1#[allow(unused_imports)]
2use crate::used_proc_macro::{
3 token_stream::IntoIter,
4 Delimiter, Ident, Group, Punct, Spacing, Span, TokenStream, TokenTree
5};
6
7use core::iter::{Peekable, once};
8
9
10pub(crate) fn parse_paren_args(tt: &TokenTree) -> Peekable<IntoIter> {
12 match tt {
13 TokenTree::Group(group) if group.delimiter() == Delimiter::Parenthesis => {
14 let stream = group.stream();
15 let mut iter = stream.clone().into_iter();
16 match (iter.next(), iter.next()) {
17 (Some(TokenTree::Group(group)), None) if group.delimiter() == Delimiter::None => {
18 group.stream()
19 }
20 _ => stream,
21 }
22 }
23 x => panic!("Expected a parentheses-delimited group, found:\n{}", x),
24 }.into_iter().peekable()
25}
26
27pub(crate) fn parenthesize_ts(ts: TokenStream, span: Span) -> TokenTree {
28 let mut group = Group::new(Delimiter::Parenthesis, ts);
29 group.set_span(span);
30 TokenTree::Group(group)
31}
32
33pub(crate) fn out_parenthesized(ts: TokenStream, span: Span, out: &mut TokenStream) {
34 out.extend(once(parenthesize_ts(ts, span)));
35}
36
37#[allow(dead_code)]
38pub(crate) fn out_ident(value: &str, span: Span, out: &mut TokenStream) {
39 let ident = Ident::new(value, span);
40 out.extend(once(TokenTree::Ident(ident)));
41}
42
43#[allow(dead_code)]
44pub(crate) fn out_colon2(span: Span, out: &mut TokenStream) {
45 out_punct(':', Spacing::Joint, span, out);
46 out_punct(':', Spacing::Alone, span, out);
47}
48
49#[allow(dead_code)]
50pub(crate) fn out_punct(char: char, spacing: Spacing, span: Span, out: &mut TokenStream) {
51 let mut token = TokenTree::Punct(Punct::new(char, spacing));
52 token.set_span(span);
53 out.extend(once(token));
54}
55
56
57pub(crate) fn parse_path_and_args<F>(
58 macro_name: &str,
59 iter: &mut IntoIter,
60 mut args: TokenStream,
61 f: F,
62) -> TokenStream
63where
64 F: FnOnce(&mut TokenStream)
65{
66 let mut out = TokenStream::new();
67 loop {
68 match iter
69 .next()
70 .unwrap_or_else(|| panic!("{} expected more tokens", macro_name) )
71 {
72 TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
73 out.extend(group.stream());
74 }
75 TokenTree::Group(group) => {
76 let mut pre = group.stream();
77 pre.extend(args);
78 args = pre;
79
80 f(&mut args);
81
82 let mut args = TokenTree::Group(Group::new(group.delimiter(), args));
83 args.set_span(group.span());
84 out.extend(once(args));
85
86 return out;
87 }
88 x => {
89 out.extend(once(x));
90 }
91 }
92 }
93}
94
95
96
97
98
99pub(crate) struct MacroInvocation {
103 pub(crate) path_bang: TokenStream,
104 pub(crate) delimiter: Delimiter,
105 pub(crate) delim_span: Span,
106 pub(crate) args: TokenStream,
107}
108
109impl MacroInvocation {
110 pub(crate) fn into_token_stream(mut self) -> TokenStream {
111 let mut args = Group::new(self.delimiter, self.args);
112 args.set_span(self.delim_span);
113 self.path_bang.extend(once(TokenTree::Group(args)));
114 self.path_bang
115 }
116
117 pub(crate) fn expand_with_extra_args<F>(mut self, f: F) -> TokenStream
118 where
119 F: FnOnce(&mut TokenStream)
120 {
121 f(&mut self.args);
122 let mut args = Group::new(self.delimiter, self.args);
123 args.set_span(self.delim_span);
124 self.path_bang.extend(once(TokenTree::Group(args)));
125 self.path_bang
126 }
127}
128
129const PARSE_MACRO_CALL_ERR: &str = "could not parse last tokens as a macro invocation";
130
131#[cfg(feature = "macro_utils")]
132pub(crate) fn parse_macro_invocation<I>(
133 iter: I
134) -> crate::Result<MacroInvocation>
135where
136 I: IntoIterator<Item = TokenTree>
137{
138 let mut path_bang = TokenStream::new();
139
140 let mut iter = iter.into_iter();
141
142 loop {
143 match iter.next() {
144 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => {
145 path_bang.extend(group.stream());
146 }
147 Some(TokenTree::Group(group)) => {
148 return Ok(MacroInvocation{
149 path_bang,
150 delimiter: group.delimiter(),
151 delim_span: group.span(),
152 args: group.stream(),
153 });
154 }
155 Some(x) => {
156 path_bang.extend(once(x));
157 }
158 None => {
159 return Err(crate::Error::end(PARSE_MACRO_CALL_ERR));
160 }
161 }
162 }
163}
164
165pub(crate) fn panicking_parse_macro_invocation<I>(
166 iter: I
167) -> MacroInvocation
168where
169 I: IntoIterator<Item = TokenTree>
170{
171 let mut path_bang = TokenStream::new();
172
173 let mut iter = iter.into_iter();
174
175 loop {
176 match iter.next() {
177 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => {
178 path_bang.extend(group.stream());
179 }
180 Some(TokenTree::Group(group)) => {
181 return MacroInvocation{
182 path_bang,
183 delimiter: group.delimiter(),
184 delim_span: group.span(),
185 args: group.stream(),
186 };
187 }
188 Some(x) => {
189 path_bang.extend(once(x));
190 }
191 None => panic!("{}", PARSE_MACRO_CALL_ERR),
192 }
193 }
194}
195