use proc_macro2 as p;
pub(crate) const S: Punct = Punct::new("::");
pub(crate) const MACROS: RuneModule = RuneModule("macros");
pub(crate) const AST: RuneModule = RuneModule("ast");
use crate::RUNE;
pub(crate) trait ToTokens {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span);
}
impl ToTokens for &'static str {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
stream.extend(Some(p::TokenTree::Ident(p::Ident::new(self, span))))
}
}
impl ToTokens for char {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
let mut p = p::Punct::new(self, p::Spacing::Alone);
p.set_span(span);
stream.extend(Some(p::TokenTree::Punct(p)));
}
}
impl ToTokens for p::Literal {
fn to_tokens(mut self, stream: &mut p::TokenStream, span: p::Span) {
self.set_span(span);
stream.extend(Some(p::TokenTree::Literal(self)));
}
}
macro_rules! impl_tuple {
() => {};
($f_ident:ident $f_var:ident, $($ident:ident $var:ident),* $(,)?) => {
impl<$f_ident, $( $ident,)*> ToTokens for ($f_ident, $($ident,)*)
where
$f_ident: ToTokens,
$($ident: ToTokens,)*
{
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
let ($f_var, $($var,)*) = self;
$f_var.to_tokens(stream, span);
$($var.to_tokens(stream, span);)*
}
}
impl_tuple!($($ident $var,)*);
}
}
impl ToTokens for () {
fn to_tokens(self, _: &mut p::TokenStream, _: p::Span) {}
}
impl_tuple!(A a, B b, C c, D d, E e, F f, G g, H h);
impl ToTokens for p::Ident {
fn to_tokens(self, stream: &mut p::TokenStream, _: p::Span) {
stream.extend(std::iter::once(p::TokenTree::Ident(self)));
}
}
impl ToTokens for p::TokenStream {
fn to_tokens(self, stream: &mut p::TokenStream, _: p::Span) {
stream.extend(self);
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct RuneModule(&'static str);
impl ToTokens for RuneModule {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
(RUNE, S, self.0).to_tokens(stream, span);
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ToTokensFn;
impl ToTokens for ToTokensFn {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
(MACROS, S, "ToTokens", S, "to_tokens").to_tokens(stream, span);
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Kind(pub(crate) &'static str);
impl ToTokens for Kind {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
(AST, S, "Kind", S, self.0).to_tokens(stream, span);
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Delimiter(pub(crate) &'static str);
impl Delimiter {
pub(crate) fn from_proc_macro(d: p::Delimiter) -> Option<Self> {
match d {
p::Delimiter::Parenthesis => Some(Delimiter("Parenthesis")),
p::Delimiter::Brace => Some(Delimiter("Brace")),
p::Delimiter::Bracket => Some(Delimiter("Bracket")),
p::Delimiter::None => None,
}
}
}
impl ToTokens for Delimiter {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
(AST, S, "Delimiter", S).to_tokens(stream, span);
self.0.to_tokens(stream, span);
}
}
#[derive(Clone, Copy)]
pub(crate) struct Punct(&'static str, p::Spacing);
impl Punct {
pub(crate) const fn new(s: &'static str) -> Punct {
Punct(s, p::Spacing::Alone)
}
}
impl ToTokens for Punct {
fn to_tokens(self, stream: &mut proc_macro2::TokenStream, span: p::Span) {
let mut it = self.0.chars();
let last = it.next_back();
for c in it {
let mut p = p::Punct::new(c, p::Spacing::Joint);
p.set_span(span);
stream.extend(Some(p::TokenTree::Punct(p)));
}
if let Some(c) = last {
let mut p = p::Punct::new(c, self.1);
p.set_span(span);
stream.extend(Some(p::TokenTree::Punct(p)));
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct Group<T>(p::Delimiter, T);
pub(crate) fn p<T>(inner: T) -> Group<T> {
Group(p::Delimiter::Parenthesis, inner)
}
pub(crate) fn braced<T>(inner: T) -> Group<T> {
Group(p::Delimiter::Brace, inner)
}
impl<T> ToTokens for Group<T>
where
T: ToTokens,
{
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
let mut inner = p::TokenStream::new();
self.1.to_tokens(&mut inner, span);
let mut group = p::Group::new(self.0, inner);
group.set_span(span);
stream.extend(Some(p::TokenTree::Group(group)));
}
}
pub(crate) struct NewIdent<'a>(pub(crate) &'static str, pub(crate) &'a str);
impl ToTokens for NewIdent<'_> {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
(self.0, '.', "ident", p(p::Literal::string(self.1)), '?').to_tokens(stream, span);
}
}
pub(crate) struct NewLit(pub(crate) &'static str, pub(crate) p::Literal);
impl ToTokens for NewLit {
fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) {
(self.0, '.', "lit", p(self.1), '?').to_tokens(stream, span);
}
}