1#![doc = include_str!("../README.md")]
2
3extern crate proc_macro;
4
5use std::{
6 collections::VecDeque,
7 iter::{once, FusedIterator, Peekable},
8};
9
10use proc_macro::{
11 Delimiter, Group, Ident, Literal, Punct,
12 Spacing::*,
13 Span, TokenStream, TokenTree,
14};
15
16pub fn span_setter<T>(span: Span) -> impl Fn(T) -> T
18where T: SetSpan,
19{
20 move |tt| {
21 tt.set_spaned(span)
22 }
23}
24
25pub trait SetSpan: Sized {
26 fn set_span(&mut self, span: Span);
28
29 fn set_spaned(mut self, span: Span) -> Self {
30 self.set_span(span);
31 self
32 }
33}
34macro_rules! impl_set_span {
35 ($ty:ty) => {
36 impl SetSpan for $ty {
37 fn set_span(&mut self, span: Span) {
38 self.set_span(span);
39 }
40 }
41 };
42}
43impl_set_span!(TokenTree);
44impl_set_span!(Ident);
45impl_set_span!(Punct);
46impl_set_span!(Group);
47impl_set_span!(Literal);
48
49#[must_use]
51pub fn stream<I>(iter: I) -> TokenStream
52where I: IntoIterator<Item = TokenTree>,
53{
54 TokenStream::from_iter(iter)
55}
56
57#[must_use]
59pub fn streams<I>(iter: I) -> TokenStream
60where I: IntoIterator<Item = TokenStream>,
61{
62 TokenStream::from_iter(iter)
63}
64
65#[must_use]
67pub fn err(msg: &str, span: Span) -> TokenStream {
68 let s = span_setter(span);
69 stream([
70 s(Punct::new(':', Joint).into()),
71 s(Punct::new(':', Joint).into()),
72 s(Ident::new("core", span).into()),
73 s(Punct::new(':', Joint).into()),
74 s(Punct::new(':', Joint).into()),
75 s(Ident::new("compile_error", span).into()),
76 s(Punct::new('!', Joint).into()),
77 s(Group::new(Delimiter::Brace, stream([
78 s(Literal::string(msg).into()),
79 ])).into()),
80 ])
81}
82
83pub fn rerr<T>(msg: &str, span: Span) -> Result<T, TokenStream> {
88 Err(err(msg, span))
89}
90
91pub fn puncts(puncts: impl AsRef<[u8]>) -> TokenStream {
97 puncts_spanned(puncts, Span::call_site())
98}
99
100pub fn puncts_spanned(puncts: impl AsRef<[u8]>, span: Span) -> TokenStream {
104 let puncts = puncts.as_ref().trim_ascii_start();
105 let iter = &mut puncts.iter().copied().peekable();
106 let mut result = TokenStream::new();
107
108 while let Some(ch) = iter.next() {
109 debug_assert!(! ch.is_ascii_whitespace());
110 let mut s = None;
111 while iter.next_if(u8::is_ascii_whitespace).is_some() {
112 s = Some(Alone)
113 }
114 let spacing = s.or(iter.peek().map(|_| Joint))
115 .unwrap_or(Joint);
116 let p = Punct::new(ch.into(), spacing);
117 result.push(p.set_spaned(span).into());
118 }
119
120 result
121}
122
123#[macro_export]
125macro_rules! err {
126 ($msg:expr $(,)?) => { $crate::err!($msg, $crate::Span::call_site()) };
127 ($msg:expr , $($span:expr)? $(,)?) => {
128 return $crate::err($msg, $span)
129 };
130}
131
132#[macro_export]
134macro_rules! rerr {
135 ($msg:expr $(,)?) => { $crate::rerr!($msg, $crate::Span::call_site()) };
136 ($msg:expr , $($span:expr)? $(,)?) => {
137 return $crate::rerr($msg, $span)
138 };
139}
140
141pub trait TokenStreamExt
142 : Default
143 + Extend<TokenTree>
144 + Extend<TokenStream>
145 + IntoIterator<Item = TokenTree>
146 + Sized
147{
148 fn push(&mut self, tt: TokenTree) -> &mut Self {
149 self.extend(once(tt));
150 self
151 }
152
153 fn add(&mut self, stream: TokenStream) -> &mut Self {
154 self.extend(once(stream));
155 self
156 }
157
158 fn parse_iter(self) -> ParseIter<Self::IntoIter> {
159 ParseIter { iter: self.into_iter(), buf: VecDeque::new() }
160 }
161
162 fn split_with<F>(self, mut predicate: F) -> (Self, Peekable<Self::IntoIter>)
164 where F: FnMut(&TokenTree) -> bool,
165 {
166 let mut left = Self::default();
167
168 let mut iter = self.into_iter().peekable();
169 while let Some(tt) = iter
170 .next_if(|tt| ! predicate(tt))
171 {
172 left.push(tt);
173 }
174
175 (left, iter)
176 }
177}
178impl TokenStreamExt for TokenStream { }
179
180pub trait TokenTreeExt: Sized {
181 fn as_ident(&self) -> Option<&Ident>;
182 fn as_punct(&self) -> Option<&Punct>;
183 fn as_group(&self) -> Option<&Group>;
184 fn as_literal(&self) -> Option<&Literal>;
185 fn into_ident(self) -> Result<Ident, Self>;
186 fn into_punct(self) -> Result<Punct, Self>;
187 fn into_group(self) -> Result<Group, Self>;
188 fn into_literal(self) -> Result<Literal, Self>;
189
190 fn is_ident(&self) -> bool {
191 self.as_ident().is_some()
192 }
193
194 fn is_punct(&self) -> bool {
195 self.as_punct().is_some()
196 }
197
198 fn is_group(&self) -> bool {
199 self.as_group().is_some()
200 }
201
202 fn is_literal(&self) -> bool {
203 self.as_literal().is_some()
204 }
205
206 fn is_keyword(&self, keyword: &str) -> bool {
210 self.as_ident().is_some_and(|i| i.to_string() == keyword)
211 }
212
213 fn is_punch(&self, ch: char) -> bool {
217 self.as_punct().is_some_and(|p| p.as_char() == ch)
218 }
219
220 fn is_solid_group(&self) -> bool {
224 self.as_group().is_some_and(|g| g.is_solid_group())
225 }
226
227 fn is_joint(&self) -> bool {
231 self.as_punct().is_some_and(|p| p.spacing() == Joint)
232 }
233
234 fn as_punct_char(&self) -> Option<char> {
235 self.as_punct().map(|p| p.as_char())
236 }
237}
238impl TokenTreeExt for TokenTree {
239 fn as_ident(&self) -> Option<&Ident> {
240 match self {
241 TokenTree::Ident(i) => Some(i),
242 _ => None,
243 }
244 }
245
246 fn as_punct(&self) -> Option<&Punct> {
247 match self {
248 TokenTree::Punct(i) => Some(i),
249 _ => None,
250 }
251 }
252
253 fn as_group(&self) -> Option<&Group> {
254 match self {
255 TokenTree::Group(i) => Some(i),
256 _ => None,
257 }
258 }
259
260 fn as_literal(&self) -> Option<&Literal> {
261 match self {
262 TokenTree::Literal(i) => Some(i),
263 _ => None,
264 }
265 }
266
267 fn into_ident(self) -> Result<Ident, Self> {
268 match self {
269 TokenTree::Ident(i) => Ok(i),
270 _ => Err(self),
271 }
272 }
273
274 fn into_punct(self) -> Result<Punct, Self> {
275 match self {
276 TokenTree::Punct(i) => Ok(i),
277 _ => Err(self),
278 }
279 }
280
281 fn into_group(self) -> Result<Group, Self> {
282 match self {
283 TokenTree::Group(i) => Ok(i),
284 _ => Err(self),
285 }
286 }
287
288 fn into_literal(self) -> Result<Literal, Self> {
289 match self {
290 TokenTree::Literal(i) => Ok(i),
291 _ => Err(self),
292 }
293 }
294}
295
296pub trait GroupExt {
297 fn is_solid_group(&self) -> bool;
299}
300impl GroupExt for Group {
301 fn is_solid_group(&self) -> bool {
302 self.delimiter() != Delimiter::None
303 }
304}
305
306pub struct ParseIter<I: Iterator<Item = TokenTree>> {
307 iter: I,
308 buf: VecDeque<TokenTree>,
309}
310
311impl<I: Iterator<Item = TokenTree>> ParseIter<I> {
312 pub fn peek(&mut self) -> Option<&TokenTree> {
313 self.peek_i(0)
314 }
315
316 pub fn next_if<F>(&mut self, f: F) -> Option<TokenTree>
317 where F: FnOnce(&TokenTree) -> bool,
318 {
319 let peek = self.peek()?;
320
321 if f(peek) {
322 self.next()
323 } else {
324 None
325 }
326 }
327
328 pub fn peek_i(&mut self, i: usize) -> Option<&TokenTree> {
329 for _ in self.buf.len()..=i {
330 self.buf.push_back(self.iter.next()?);
331 }
332 Some(&self.buf[i])
333 }
334
335 pub fn peek_is<F>(&mut self, f: F) -> bool
336 where F: FnOnce(&TokenTree) -> bool,
337 {
338 self.peek().is_some_and(f)
339 }
340
341 pub fn peek_i_is<F>(&mut self, i: usize, f: F) -> bool
342 where F: FnOnce(&TokenTree) -> bool,
343 {
344 self.peek_i(i).is_some_and(f)
345 }
346
347 pub fn peek_puncts(&mut self, puncts: impl AsRef<[u8]>) -> Option<
349 impl Iterator<Item = &TokenTree>
350 > {
351 let mut prev = None;
352
353 for (i, ch) in puncts.as_ref().iter()
354 .copied().map(char::from).enumerate()
355 {
356 if let Some(prev) = prev {
357 if prev == Alone { return None }
358 }
359
360 let tt = self.peek_i(i)?;
361 let TokenTree::Punct(p) = tt else { return None };
362 if p.as_char() != ch { return None }
363
364 prev = Some(p.spacing());
365 }
366 Some(self.buf.iter())
367 }
368
369 pub fn next_puncts(&mut self, puncts: impl AsRef<[u8]>) -> Option<
371 impl Iterator<Item = TokenTree> + '_
372 > {
373 let _ = self.peek_puncts(puncts.as_ref())?;
374 Some(self.buf.drain(..puncts.as_ref().len()))
375 }
376}
377pub trait ParseIterExt: Iterator<Item = TokenTree> + Sized {
378 fn parse_iter(self) -> ParseIter<Self> {
379 ParseIter { iter: self, buf: VecDeque::new() }
380 }
381}
382impl<I: Iterator<Item = TokenTree>> ParseIterExt for I { }
383
384impl<I: Iterator<Item = TokenTree>> Iterator for ParseIter<I> {
385 type Item = TokenTree;
386
387 fn next(&mut self) -> Option<Self::Item> {
388 self.buf.pop_front()
389 .or_else(|| self.iter.next())
390 }
391
392 fn count(self) -> usize
393 where Self: Sized,
394 {
395 self.buf.len() + self.iter.count()
396 }
397
398 fn fold<B, F>(self, init: B, f: F) -> B
399 where Self: Sized,
400 F: FnMut(B, Self::Item) -> B,
401 {
402 self.buf.into_iter().chain(self.iter).fold(init, f)
403 }
404
405 fn size_hint(&self) -> (usize, Option<usize>) {
406 let (lo, hi) = self.iter.size_hint();
407 let lo = lo.saturating_add(self.buf.len());
408 let hi = hi.and_then(|hi| hi.checked_add(self.buf.len()));
409 (lo, hi)
410 }
411}
412impl<I: DoubleEndedIterator<Item = TokenTree>> DoubleEndedIterator for ParseIter<I> {
413 fn next_back(&mut self) -> Option<Self::Item> {
414 self.iter.next_back()
415 .or_else(|| self.buf.pop_back())
416 }
417
418 fn rfold<B, F>(self, init: B, f: F) -> B
419 where Self: Sized,
420 F: FnMut(B, Self::Item) -> B,
421 {
422 self.buf.into_iter().chain(self.iter).rfold(init, f)
423 }
424}
425impl<I: ExactSizeIterator<Item = TokenTree>> ExactSizeIterator for ParseIter<I> { }
426impl<I: FusedIterator<Item = TokenTree>> FusedIterator for ParseIter<I> { }
427
428fn pfunc_impl<F, R>(
429 input: TokenStream,
430 proc_input: bool,
431 names: &[&str],
432 f: &mut F,
433) -> Result<TokenStream, R>
434where F: FnMut(Ident, Group) -> Result<TokenStream, R>,
435{
436 let mut iter = input.into_iter().parse_iter();
437 let mut result = TokenStream::new();
438
439 while let Some(tt) = iter.next() {
440 match tt {
441 TokenTree::Punct(p)
442 if p.as_char() == '#'
443 && iter.peek_is(|i| i.as_ident()
444 .is_some_and(|i| names.contains(&&*i.to_string())))
445 && iter.peek_i_is(1, |t| t.is_solid_group())
446 =>
447 {
448 let ident = iter.next().unwrap().into_ident().unwrap();
449 let mut group = iter.next().unwrap().into_group().unwrap();
450 if proc_input {
451 let sub = pfunc_impl(
452 group.stream(), proc_input, names, f)?;
453 group = Group::new(group.delimiter(), sub)
454 .set_spaned(group.span());
455 }
456 result.add(f(ident, group)?);
457 },
458 TokenTree::Group(g) => {
459 let sub = pfunc_impl(g.stream(), proc_input, names, f)?;
460 let tt = Group::new(g.delimiter(), sub);
461 result.push(tt.set_spaned(g.span()).into());
462 },
463 _ => _ = result.push(tt),
464 }
465 }
466
467 Ok(result)
468}
469
470pub fn pfunc<'a>(
474 input: TokenStream,
475 proc_input: bool,
476 names: impl AsRef<[&'a str]>,
477 mut f: impl FnMut(Ident, Group) -> TokenStream,
478) -> TokenStream {
479 let f = &mut |i, g| {
480 Ok::<_, ()>(f(i, g))
481 };
482 pfunc_impl(input, proc_input, names.as_ref(), f).unwrap()
483}
484
485pub fn try_pfunc<'a, R>(
489 input: TokenStream,
490 proc_input: bool,
491 names: impl AsRef<[&'a str]>,
492 mut f: impl FnMut(Ident, Group) -> Result<TokenStream, R>,
493) -> Result<TokenStream, R> {
494 pfunc_impl(input, proc_input, names.as_ref(), &mut f)
495}