oxidate 0.1.0

Turns strings into a Rust AST
Documentation
pub mod literal;
pub mod punctuation;
pub mod word;

use std::borrow::Cow;

use ::proc_macro2::{self, Group};
use oxidate_macros::data;
use quote::ToTokens;

use crate::AstSpan;

pub use self::{
    literal::{Literal, UnspannedLiteral},
    punctuation::Punctuation,
    word::Word,
};

#[data]
pub enum Lexed<'a> {
    Delimited(Delimited<'a>),
    Word(Word<'a>),
    Punctuation(Punctuation<'a>),
    Literal(Literal),
}

impl<'a> AstSpan for Lexed<'a> {
    type Unspanned = Self;

    fn span(&self) -> crate::Span {
        match self {
            Lexed::Delimited(delimited) => delimited.span(),
            Lexed::Word(word) => word.span(),
            Lexed::Punctuation(punctuation) => punctuation.span(),
            Lexed::Literal(literal) => literal.span(),
        }
    }

    fn unspanned(&self) -> &Self::Unspanned {
        self
    }
}

impl<'a> Lexed<'a> {
    pub fn as_punctuation(&self, char: &str) -> Option<&Punctuation> {
        match self {
            Lexed::Punctuation(p) if p == char => Some(p),
            _ => None,
        }
    }

    pub fn as_word(&self, word: &str) -> Option<&Word> {
        match self {
            Lexed::Word(ident) if ident == word => Some(ident),
            _ => None,
        }
    }
}

impl Into<Lexed<'static>> for proc_macro2::TokenTree {
    fn into(self) -> Lexed<'static> {
        match self {
            proc_macro2::TokenTree::Group(group) => Lexed::Delimited(group.into()),
            proc_macro2::TokenTree::Ident(ident) => Lexed::Word(ident.into()),
            proc_macro2::TokenTree::Punct(punct) => Lexed::Punctuation(punct.into()),
            proc_macro2::TokenTree::Literal(literal) => Lexed::Literal(literal.into()),
        }
    }
}

impl<'a> Into<Lexed<'a>> for &'a proc_macro2::TokenTree {
    fn into(self) -> Lexed<'a> {
        match self {
            proc_macro2::TokenTree::Group(group) => Lexed::Delimited(group.into()),
            proc_macro2::TokenTree::Ident(ident) => Lexed::Word(ident.into()),
            proc_macro2::TokenTree::Punct(punct) => Lexed::Punctuation(punct.into()),
            proc_macro2::TokenTree::Literal(literal) => Lexed::Literal(literal.into()),
        }
    }
}

#[data]
pub struct Delimited<'a> {
    inner: Cow<'a, Group>,
}

impl<'a> AstSpan for Delimited<'a> {
    type Unspanned = Self;

    fn span(&self) -> crate::Span {
        self.inner.span().into()
    }

    fn unspanned(&self) -> &Self::Unspanned {
        self
    }
}

impl<'a> ToTokens for Delimited<'a> {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        self.inner.to_tokens(tokens)
    }
}

impl Into<Delimited<'static>> for Group {
    fn into(self) -> Delimited<'static> {
        Delimited {
            inner: Cow::Owned(self),
        }
    }
}

impl<'a> Into<Delimited<'a>> for &'a Group {
    fn into(self) -> Delimited<'a> {
        Delimited {
            inner: Cow::Borrowed(self),
        }
    }
}