1#![doc = include_str!("../README.md")]
2
3extern crate proc_macro;
4
5use std::{
6 collections::VecDeque,
7 iter::{once, FusedIterator},
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_puncts(self, puncts: impl AsRef<[u8]>) -> (
166 Self,
167 ParseIter<Self::IntoIter>,
168 )
169 {
170 let mut left = Self::default();
171 let puncts = puncts.as_ref();
172
173 let mut iter = self.parse_iter();
174 while iter.next_puncts(puncts).is_none() {
175 left.push(iter.next().unwrap());
176 }
177
178 (left, iter)
179 }
180}
181impl TokenStreamExt for TokenStream { }
182
183pub trait TokenTreeExt: Sized {
184 fn as_ident(&self) -> Option<&Ident>;
185 fn as_punct(&self) -> Option<&Punct>;
186 fn as_group(&self) -> Option<&Group>;
187 fn as_literal(&self) -> Option<&Literal>;
188 fn into_ident(self) -> Result<Ident, Self>;
189 fn into_punct(self) -> Result<Punct, Self>;
190 fn into_group(self) -> Result<Group, Self>;
191 fn into_literal(self) -> Result<Literal, Self>;
192
193 fn is_ident(&self) -> bool {
194 self.as_ident().is_some()
195 }
196
197 fn is_punct(&self) -> bool {
198 self.as_punct().is_some()
199 }
200
201 fn is_group(&self) -> bool {
202 self.as_group().is_some()
203 }
204
205 fn is_literal(&self) -> bool {
206 self.as_literal().is_some()
207 }
208
209 fn is_keyword(&self, keyword: &str) -> bool {
213 self.as_ident().is_some_and(|i| i.to_string() == keyword)
214 }
215
216 fn is_punch(&self, ch: char) -> bool {
220 self.as_punct().is_some_and(|p| p.as_char() == ch)
221 }
222
223 fn is_solid_group(&self) -> bool {
227 self.as_group().is_some_and(|g| g.is_solid_group())
228 }
229
230 fn is_joint(&self) -> bool {
234 self.as_punct().is_some_and(|p| p.spacing() == Joint)
235 }
236
237 fn as_punct_char(&self) -> Option<char> {
238 self.as_punct().map(|p| p.as_char())
239 }
240}
241impl TokenTreeExt for TokenTree {
242 fn as_ident(&self) -> Option<&Ident> {
243 match self {
244 TokenTree::Ident(i) => Some(i),
245 _ => None,
246 }
247 }
248
249 fn as_punct(&self) -> Option<&Punct> {
250 match self {
251 TokenTree::Punct(i) => Some(i),
252 _ => None,
253 }
254 }
255
256 fn as_group(&self) -> Option<&Group> {
257 match self {
258 TokenTree::Group(i) => Some(i),
259 _ => None,
260 }
261 }
262
263 fn as_literal(&self) -> Option<&Literal> {
264 match self {
265 TokenTree::Literal(i) => Some(i),
266 _ => None,
267 }
268 }
269
270 fn into_ident(self) -> Result<Ident, Self> {
271 match self {
272 TokenTree::Ident(i) => Ok(i),
273 _ => Err(self),
274 }
275 }
276
277 fn into_punct(self) -> Result<Punct, Self> {
278 match self {
279 TokenTree::Punct(i) => Ok(i),
280 _ => Err(self),
281 }
282 }
283
284 fn into_group(self) -> Result<Group, Self> {
285 match self {
286 TokenTree::Group(i) => Ok(i),
287 _ => Err(self),
288 }
289 }
290
291 fn into_literal(self) -> Result<Literal, Self> {
292 match self {
293 TokenTree::Literal(i) => Ok(i),
294 _ => Err(self),
295 }
296 }
297}
298
299pub trait GroupExt {
300 fn is_solid_group(&self) -> bool;
302}
303impl GroupExt for Group {
304 fn is_solid_group(&self) -> bool {
305 self.delimiter() != Delimiter::None
306 }
307}
308
309#[derive(Debug, Clone)]
310pub struct ParseIter<I: Iterator<Item = TokenTree>> {
311 iter: I,
312 buf: VecDeque<TokenTree>,
313}
314
315impl<I: Iterator<Item = TokenTree>> ParseIter<I> {
316 pub fn peek(&mut self) -> Option<&TokenTree> {
317 self.peek_i(0)
318 }
319
320 pub fn next_if<F>(&mut self, f: F) -> Option<TokenTree>
321 where F: FnOnce(&TokenTree) -> bool,
322 {
323 let peek = self.peek()?;
324
325 if f(peek) {
326 self.next()
327 } else {
328 None
329 }
330 }
331
332 pub fn peek_i(&mut self, i: usize) -> Option<&TokenTree> {
333 for _ in self.buf.len()..=i {
334 self.buf.push_back(self.iter.next()?);
335 }
336 Some(&self.buf[i])
337 }
338
339 pub fn peek_is<F>(&mut self, f: F) -> bool
340 where F: FnOnce(&TokenTree) -> bool,
341 {
342 self.peek().is_some_and(f)
343 }
344
345 pub fn peek_i_is<F>(&mut self, i: usize, f: F) -> bool
346 where F: FnOnce(&TokenTree) -> bool,
347 {
348 self.peek_i(i).is_some_and(f)
349 }
350
351 pub fn peek_puncts(&mut self, puncts: impl AsRef<[u8]>) -> Option<
353 impl Iterator<Item = &TokenTree>
354 > {
355 let mut prev = None;
356
357 for (i, ch) in puncts.as_ref().iter()
358 .copied().map(char::from).enumerate()
359 {
360 if let Some(prev) = prev {
361 if prev == Alone { return None }
362 }
363
364 let tt = self.peek_i(i)?;
365 let TokenTree::Punct(p) = tt else { return None };
366 if p.as_char() != ch { return None }
367
368 prev = Some(p.spacing());
369 }
370 Some(self.buf.iter())
371 }
372
373 pub fn next_puncts(&mut self, puncts: impl AsRef<[u8]>) -> Option<
375 impl Iterator<Item = TokenTree> + '_
376 > {
377 let _ = self.peek_puncts(puncts.as_ref())?;
378 Some(self.buf.drain(..puncts.as_ref().len()))
379 }
380}
381pub trait ParseIterExt: Iterator<Item = TokenTree> + Sized {
382 fn parse_iter(self) -> ParseIter<Self> {
383 ParseIter { iter: self, buf: VecDeque::new() }
384 }
385}
386impl<I: Iterator<Item = TokenTree>> ParseIterExt for I { }
387
388impl<I: Iterator<Item = TokenTree>> Iterator for ParseIter<I> {
389 type Item = TokenTree;
390
391 fn next(&mut self) -> Option<Self::Item> {
392 self.buf.pop_front()
393 .or_else(|| self.iter.next())
394 }
395
396 fn count(self) -> usize
397 where Self: Sized,
398 {
399 self.buf.len() + self.iter.count()
400 }
401
402 fn fold<B, F>(self, init: B, f: F) -> B
403 where Self: Sized,
404 F: FnMut(B, Self::Item) -> B,
405 {
406 self.buf.into_iter().chain(self.iter).fold(init, f)
407 }
408
409 fn size_hint(&self) -> (usize, Option<usize>) {
410 let (lo, hi) = self.iter.size_hint();
411 let lo = lo.saturating_add(self.buf.len());
412 let hi = hi.and_then(|hi| hi.checked_add(self.buf.len()));
413 (lo, hi)
414 }
415}
416impl<I: DoubleEndedIterator<Item = TokenTree>> DoubleEndedIterator for ParseIter<I> {
417 fn next_back(&mut self) -> Option<Self::Item> {
418 self.iter.next_back()
419 .or_else(|| self.buf.pop_back())
420 }
421
422 fn rfold<B, F>(self, init: B, f: F) -> B
423 where Self: Sized,
424 F: FnMut(B, Self::Item) -> B,
425 {
426 self.buf.into_iter().chain(self.iter).rfold(init, f)
427 }
428}
429impl<I: ExactSizeIterator<Item = TokenTree>> ExactSizeIterator for ParseIter<I> { }
430impl<I: FusedIterator<Item = TokenTree>> FusedIterator for ParseIter<I> { }
431
432fn pfunc_impl<F, R>(
433 input: TokenStream,
434 proc_input: bool,
435 names: &[&str],
436 f: &mut F,
437) -> Result<TokenStream, R>
438where F: FnMut(Ident, Group) -> Result<TokenStream, R>,
439{
440 let mut iter = input.into_iter().parse_iter();
441 let mut result = TokenStream::new();
442
443 while let Some(tt) = iter.next() {
444 match tt {
445 TokenTree::Punct(p)
446 if p.as_char() == '#'
447 && iter.peek_is(|i| i.as_ident()
448 .is_some_and(|i| names.contains(&&*i.to_string())))
449 && iter.peek_i_is(1, |t| t.is_solid_group())
450 =>
451 {
452 let ident = iter.next().unwrap().into_ident().unwrap();
453 let mut group = iter.next().unwrap().into_group().unwrap();
454 if proc_input {
455 let sub = pfunc_impl(
456 group.stream(), proc_input, names, f)?;
457 group = Group::new(group.delimiter(), sub)
458 .set_spaned(group.span());
459 }
460 result.add(f(ident, group)?);
461 },
462 TokenTree::Group(g) => {
463 let sub = pfunc_impl(g.stream(), proc_input, names, f)?;
464 let tt = Group::new(g.delimiter(), sub);
465 result.push(tt.set_spaned(g.span()).into());
466 },
467 _ => _ = result.push(tt),
468 }
469 }
470
471 Ok(result)
472}
473
474pub fn pfunc<'a>(
478 input: TokenStream,
479 proc_input: bool,
480 names: impl AsRef<[&'a str]>,
481 mut f: impl FnMut(Ident, Group) -> TokenStream,
482) -> TokenStream {
483 let f = &mut |i, g| {
484 Ok::<_, ()>(f(i, g))
485 };
486 pfunc_impl(input, proc_input, names.as_ref(), f).unwrap()
487}
488
489pub fn try_pfunc<'a, R>(
493 input: TokenStream,
494 proc_input: bool,
495 names: impl AsRef<[&'a str]>,
496 mut f: impl FnMut(Ident, Group) -> Result<TokenStream, R>,
497) -> Result<TokenStream, R> {
498 pfunc_impl(input, proc_input, names.as_ref(), &mut f)
499}