ruast 0.0.23

A printable & modifiable Rust AST
Documentation
use proc_macro2::{Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::ToTokens;

use crate::{BinOpToken, Lit, LitKind, Token};

impl BinOpToken {
    fn to_tokens_spacing(&self, spacing: Spacing, tokens: &mut TokenStream) {
        match self {
            Self::Plus => tokens.extend([TokenTree::Punct(Punct::new('+', spacing))]),
            Self::Minus => tokens.extend([TokenTree::Punct(Punct::new('-', spacing))]),
            Self::Star => tokens.extend([TokenTree::Punct(Punct::new('*', spacing))]),
            Self::Slash => tokens.extend([TokenTree::Punct(Punct::new('/', spacing))]),
            Self::Percent => tokens.extend([TokenTree::Punct(Punct::new('%', spacing))]),
            Self::Caret => tokens.extend([TokenTree::Punct(Punct::new('^', spacing))]),
            Self::LazyAnd => tokens.extend([
                TokenTree::Punct(Punct::new('&', Spacing::Joint)),
                TokenTree::Punct(Punct::new('&', spacing)),
            ]),
            Self::LazyOr => tokens.extend([
                TokenTree::Punct(Punct::new('|', Spacing::Joint)),
                TokenTree::Punct(Punct::new('|', spacing)),
            ]),
            Self::BitAnd => tokens.extend([TokenTree::Punct(Punct::new('&', spacing))]),
            Self::BitOr => tokens.extend([TokenTree::Punct(Punct::new('|', spacing))]),
            Self::BitXor => tokens.extend([TokenTree::Punct(Punct::new('^', spacing))]),
            Self::Shl => tokens.extend([
                TokenTree::Punct(Punct::new('<', Spacing::Joint)),
                TokenTree::Punct(Punct::new('<', spacing)),
            ]),
            Self::Shr => tokens.extend([
                TokenTree::Punct(Punct::new('>', Spacing::Joint)),
                TokenTree::Punct(Punct::new('>', spacing)),
            ]),
        }
    }
}

impl ToTokens for BinOpToken {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        self.to_tokens_spacing(Spacing::Alone, tokens)
    }
}

impl ToTokens for Token {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            Self::Eq => tokens.extend([TokenTree::Punct(Punct::new('=', Spacing::Alone))]),
            Self::Lt => tokens.extend([TokenTree::Punct(Punct::new('<', Spacing::Alone))]),
            Self::Le => tokens.extend([
                TokenTree::Punct(Punct::new('<', Spacing::Joint)),
                TokenTree::Punct(Punct::new('=', Spacing::Alone)),
            ]),
            Self::EqEq => tokens.extend([
                TokenTree::Punct(Punct::new('=', Spacing::Joint)),
                TokenTree::Punct(Punct::new('=', Spacing::Alone)),
            ]),
            Self::Ne => tokens.extend([
                TokenTree::Punct(Punct::new('!', Spacing::Joint)),
                TokenTree::Punct(Punct::new('=', Spacing::Alone)),
            ]),
            Self::Gt => tokens.extend([TokenTree::Punct(Punct::new('>', Spacing::Alone))]),
            Self::Ge => tokens.extend([
                TokenTree::Punct(Punct::new('>', Spacing::Joint)),
                TokenTree::Punct(Punct::new('=', Spacing::Alone)),
            ]),
            Self::And => tokens.extend([TokenTree::Punct(Punct::new('&', Spacing::Alone))]),
            Self::Or => tokens.extend([TokenTree::Punct(Punct::new('|', Spacing::Alone))]),
            Self::Not => tokens.extend([TokenTree::Punct(Punct::new('!', Spacing::Alone))]),
            Self::Tilde => tokens.extend([TokenTree::Punct(Punct::new('~', Spacing::Alone))]),
            Self::BinOp(bin) => bin.to_tokens(tokens),
            Self::BinOpEq(bin) => {
                bin.to_tokens_spacing(Spacing::Joint, tokens);
                tokens.extend([TokenTree::Punct(Punct::new('=', Spacing::Alone))])
            }
            Self::At => tokens.extend([TokenTree::Punct(Punct::new('@', Spacing::Alone))]),
            Self::Dot => tokens.extend([TokenTree::Punct(Punct::new('.', Spacing::Alone))]),
            Self::DotDot => tokens.extend([
                TokenTree::Punct(Punct::new('.', Spacing::Joint)),
                TokenTree::Punct(Punct::new('.', Spacing::Alone)),
            ]),
            Self::DotDotDot => tokens.extend([
                TokenTree::Punct(Punct::new('.', Spacing::Joint)),
                TokenTree::Punct(Punct::new('.', Spacing::Joint)),
                TokenTree::Punct(Punct::new('.', Spacing::Alone)),
            ]),
            Self::DotDotEq => tokens.extend([
                TokenTree::Punct(Punct::new('.', Spacing::Joint)),
                TokenTree::Punct(Punct::new('.', Spacing::Joint)),
                TokenTree::Punct(Punct::new('=', Spacing::Alone)),
            ]),
            Self::Comma => tokens.extend([TokenTree::Punct(Punct::new(',', Spacing::Alone))]),
            Self::Semi => tokens.extend([TokenTree::Punct(Punct::new(';', Spacing::Alone))]),
            Self::Colon => tokens.extend([TokenTree::Punct(Punct::new(':', Spacing::Alone))]),
            Self::ModSep => tokens.extend([
                TokenTree::Punct(Punct::new(':', Spacing::Joint)),
                TokenTree::Punct(Punct::new(':', Spacing::Alone)),
            ]),
            Self::LArrow => tokens.extend([
                TokenTree::Punct(Punct::new('<', Spacing::Joint)),
                TokenTree::Punct(Punct::new('-', Spacing::Alone)),
            ]),
            Self::RArrow => tokens.extend([
                TokenTree::Punct(Punct::new('-', Spacing::Joint)),
                TokenTree::Punct(Punct::new('>', Spacing::Alone)),
            ]),
            Self::FatArrow => tokens.extend([
                TokenTree::Punct(Punct::new('=', Spacing::Joint)),
                TokenTree::Punct(Punct::new('>', Spacing::Alone)),
            ]),
            Self::Pound => tokens.extend([TokenTree::Punct(Punct::new('#', Spacing::Alone))]),
            Self::Dollar => tokens.extend([TokenTree::Punct(Punct::new('$', Spacing::Alone))]),
            Self::Question => tokens.extend([TokenTree::Punct(Punct::new('?', Spacing::Alone))]),
            Self::SingleQuote => {
                tokens.extend([TokenTree::Punct(Punct::new('\'', Spacing::Alone))])
            }
            Self::OpenDelim(_) => unreachable!("OpenDelim should not be used in ToTokens"),
            Self::CloseDelim(_) => unreachable!("CloseDelim should not be used in ToTokens"),
            Self::Lit(lit) => lit.to_tokens(tokens),
            Self::Ident(ident) => {
                tokens.extend([TokenTree::Ident(Ident::new(ident, Span::call_site()))])
            }
            Self::Lifetime(lifetime) => tokens.extend([
                TokenTree::Punct(Punct::new('\'', Spacing::Joint)),
                TokenTree::Ident(Ident::new(lifetime, Span::call_site())),
            ]),
            Self::Keyword(keyword) => tokens.extend([TokenTree::Ident(Ident::new(
                &keyword.to_string(),
                Span::call_site(),
            ))]),
            Self::DocComment(_) => {}
            Self::Joint(token) => token.to_tokens(tokens),
            Self::Eof => {}
        }
    }
}

impl ToTokens for Lit {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self.kind {
            LitKind::Integer => tokens.extend([TokenTree::Literal(Literal::isize_unsuffixed(
                self.symbol.parse().unwrap(),
            ))]),
            LitKind::Float => tokens.extend([TokenTree::Literal(Literal::f64_unsuffixed(
                self.symbol.parse().unwrap(),
            ))]),
            LitKind::Char => tokens.extend([TokenTree::Literal(Literal::character(
                self.symbol.chars().next().unwrap(),
            ))]),
            LitKind::Str => tokens.extend([TokenTree::Literal(Literal::string(&self.symbol))]),
            _ => todo!(),
        }
    }
}

impl ToTokens for crate::TokenStream {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let mut iter = self.iter();
        while let Some(token) = iter.next() {
            match token.as_unjoint() {
                Token::OpenDelim(open) => {
                    let ts = crate::TokenStream::get_until_closed(&mut iter);
                    let group = TokenTree::Group(Group::new((*open).into(), ts));
                    group.to_tokens(tokens);
                }
                _ => {
                    token.to_tokens(tokens);
                }
            }
        }
    }
}

impl crate::TokenStream {
    fn get_until_closed<'a>(iter: &mut impl Iterator<Item = &'a Token>) -> TokenStream {
        let mut tokens = TokenStream::new();
        while let Some(token) = iter.next() {
            match token.as_unjoint() {
                Token::CloseDelim(_) => break,
                Token::OpenDelim(open) => {
                    let ts = Self::get_until_closed(iter);
                    let group = TokenTree::Group(Group::new((*open).into(), ts));
                    group.to_tokens(&mut tokens);
                }
                _ => {
                    token.to_tokens(&mut tokens);
                }
            }
        }
        tokens
    }
}