rune_macros/quote/
inner.rs

1use proc_macro2 as p;
2
3pub(crate) const S: Punct = Punct::new("::");
4pub(crate) const MACROS: RuneModule = RuneModule("macros");
5pub(crate) const AST: RuneModule = RuneModule("ast");
6
7use crate::RUNE;
8pub(crate) trait ToTokens {
9    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span);
10}
11
12impl ToTokens for &'static str {
13    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
14        stream.extend(Some(p::TokenTree::Ident(p::Ident::new(self, span))))
15    }
16}
17
18impl ToTokens for char {
19    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
20        let mut p = p::Punct::new(self, p::Spacing::Alone);
21        p.set_span(span);
22        stream.extend(Some(p::TokenTree::Punct(p)));
23    }
24}
25
26impl ToTokens for p::Literal {
27    fn to_tokens(mut self, stream: &mut p::TokenStream, span: p::Span) {
28        self.set_span(span);
29        stream.extend(Some(p::TokenTree::Literal(self)));
30    }
31}
32
33macro_rules! impl_tuple {
34    () => {};
35
36    ($f_ident:ident $f_var:ident, $($ident:ident $var:ident),* $(,)?) => {
37        impl<$f_ident, $( $ident,)*> ToTokens for ($f_ident, $($ident,)*)
38        where
39            $f_ident: ToTokens,
40            $($ident: ToTokens,)*
41        {
42            fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
43                let ($f_var, $($var,)*) = self;
44                $f_var.to_tokens(stream, span);
45                $($var.to_tokens(stream, span);)*
46            }
47        }
48
49        impl_tuple!($($ident $var,)*);
50    }
51}
52
53impl ToTokens for () {
54    fn to_tokens(self, _: &mut p::TokenStream, _: p::Span) {}
55}
56
57impl_tuple!(A a, B b, C c, D d, E e, F f, G g, H h);
58
59impl ToTokens for p::Ident {
60    fn to_tokens(self, stream: &mut p::TokenStream, _: p::Span) {
61        stream.extend(std::iter::once(p::TokenTree::Ident(self)));
62    }
63}
64
65impl ToTokens for p::TokenStream {
66    fn to_tokens(self, stream: &mut p::TokenStream, _: p::Span) {
67        stream.extend(self);
68    }
69}
70
71#[derive(Debug, Clone, Copy)]
72pub(crate) struct RuneModule(&'static str);
73
74impl ToTokens for RuneModule {
75    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
76        (RUNE, S, self.0).to_tokens(stream, span);
77    }
78}
79
80#[derive(Debug, Clone, Copy)]
81pub(crate) struct ToTokensFn;
82
83impl ToTokens for ToTokensFn {
84    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
85        (MACROS, S, "ToTokens", S, "to_tokens").to_tokens(stream, span);
86    }
87}
88
89#[derive(Debug, Clone, Copy)]
90pub(crate) struct Kind(pub(crate) &'static str);
91
92impl ToTokens for Kind {
93    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
94        (AST, S, "Kind", S, self.0).to_tokens(stream, span);
95    }
96}
97
98#[derive(Debug, Clone, Copy)]
99pub(crate) struct Delimiter(pub(crate) &'static str);
100
101impl Delimiter {
102    /// Convert from a proc macro.
103    pub(crate) fn from_proc_macro(d: p::Delimiter) -> Option<Self> {
104        match d {
105            p::Delimiter::Parenthesis => Some(Delimiter("Parenthesis")),
106            p::Delimiter::Brace => Some(Delimiter("Brace")),
107            p::Delimiter::Bracket => Some(Delimiter("Bracket")),
108            p::Delimiter::None => None,
109        }
110    }
111}
112
113impl ToTokens for Delimiter {
114    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
115        (AST, S, "Delimiter", S).to_tokens(stream, span);
116        self.0.to_tokens(stream, span);
117    }
118}
119
120/// Construct a joined punctuation out of the given string.
121#[derive(Clone, Copy)]
122pub(crate) struct Punct(&'static str, p::Spacing);
123
124impl Punct {
125    pub(crate) const fn new(s: &'static str) -> Punct {
126        Punct(s, p::Spacing::Alone)
127    }
128}
129
130impl ToTokens for Punct {
131    fn to_tokens(self, stream: &mut proc_macro2::TokenStream, span: p::Span) {
132        let mut it = self.0.chars();
133        let last = it.next_back();
134
135        for c in it {
136            let mut p = p::Punct::new(c, p::Spacing::Joint);
137            p.set_span(span);
138            stream.extend(Some(p::TokenTree::Punct(p)));
139        }
140
141        if let Some(c) = last {
142            let mut p = p::Punct::new(c, self.1);
143            p.set_span(span);
144            stream.extend(Some(p::TokenTree::Punct(p)));
145        }
146    }
147}
148
149#[derive(Debug, Clone)]
150pub(crate) struct Group<T>(p::Delimiter, T);
151
152/// `(T)`.
153pub(crate) fn p<T>(inner: T) -> Group<T> {
154    Group(p::Delimiter::Parenthesis, inner)
155}
156
157/// `{T}`.
158pub(crate) fn braced<T>(inner: T) -> Group<T> {
159    Group(p::Delimiter::Brace, inner)
160}
161
162impl<T> ToTokens for Group<T>
163where
164    T: ToTokens,
165{
166    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
167        let mut inner = p::TokenStream::new();
168        self.1.to_tokens(&mut inner, span);
169
170        let mut group = p::Group::new(self.0, inner);
171        group.set_span(span);
172        stream.extend(Some(p::TokenTree::Group(group)));
173    }
174}
175
176/// An identifier constructor.
177pub(crate) struct NewIdent<'a>(pub(crate) &'static str, pub(crate) &'a str);
178
179impl ToTokens for NewIdent<'_> {
180    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
181        (self.0, '.', "ident", p(p::Literal::string(self.1)), '?').to_tokens(stream, span);
182    }
183}
184
185/// An identifier constructor.
186pub(crate) struct NewLit(pub(crate) &'static str, pub(crate) p::Literal);
187
188impl ToTokens for NewLit {
189    fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
190        (self.0, '.', "lit", p(self.1), '?').to_tokens(stream, span);
191    }
192}