#![cfg_attr(feature = "nightly-doc", feature(external_doc))]
#![cfg_attr(feature = "nightly-doc", doc(include = "../README.md"))]
use pm::Span;
extern crate proc_macro;
use proc_macro2 as pm;
use quote::ToTokens;
mod bigint;
mod literal;
#[derive(Debug, Clone)]
pub struct TokenStream {
pub tokens: Vec<TokenTree>,
}
#[derive(Debug, Clone)]
pub enum TokenTree {
Group(Group),
Ident(Ident),
Punct(Punct),
Literal(Literal),
}
pub use literal::{LitFloat, LitInt, LitKind, Literal};
#[derive(Debug, Clone)]
pub struct Group {
pub stream: TokenStream,
pub delimiter: Delimiter,
pub span: Span,
pub span_open: Span,
pub span_close: Span,
}
pub use pm::Delimiter;
#[derive(Debug, Clone)]
pub struct Ident {
pub span: Span,
pub ident: String,
}
#[derive(Debug, Clone)]
pub struct Punct {
pub kind: PunctKind,
pub span: Span,
pub spacing: Spacing,
}
pub use pm::Spacing;
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub enum PunctKind {
Semicolon,
Comma,
Dot,
At,
Tilde,
Question,
Colon,
Dollar,
Eq,
Not,
Lt,
Gt,
Minus,
And,
Or,
Plus,
Star,
Slash,
Caret,
Percent,
}
pub trait AsNative {
type Native;
fn as_native(&self) -> Self::Native;
}
impl TokenTree {
pub fn span(&self) -> Span {
match self {
TokenTree::Group(ref g) => g.span,
TokenTree::Ident(ref i) => i.span,
TokenTree::Punct(ref p) => p.span,
TokenTree::Literal(ref l) => l.span,
}
}
}
impl From<pm::TokenStream> for TokenStream {
fn from(p: pm::TokenStream) -> Self {
Self {
tokens: p.into_iter().map(|t| t.into()).collect(),
}
}
}
impl From<proc_macro::TokenStream> for TokenStream {
fn from(p: proc_macro::TokenStream) -> Self {
let p: pm::TokenStream = p.into();
p.into()
}
}
impl AsNative for TokenStream {
type Native = pm::TokenStream;
fn as_native(&self) -> pm::TokenStream {
self.tokens.iter().map(|t| t.as_native()).collect()
}
}
impl From<pm::TokenTree> for TokenTree {
fn from(p: pm::TokenTree) -> Self {
match p {
pm::TokenTree::Group(g) => TokenTree::Group(g.into()),
pm::TokenTree::Ident(i) => TokenTree::Ident(i.into()),
pm::TokenTree::Punct(p) => TokenTree::Punct(p.into()),
pm::TokenTree::Literal(l) => TokenTree::Literal(l.into()),
}
}
}
impl AsNative for TokenTree {
type Native = pm::TokenTree;
fn as_native(&self) -> pm::TokenTree {
match self {
TokenTree::Group(ref g) => pm::TokenTree::Group(g.as_native()),
TokenTree::Ident(ref i) => pm::TokenTree::Ident(i.as_native()),
TokenTree::Punct(ref p) => pm::TokenTree::Punct(p.as_native()),
TokenTree::Literal(ref l) => pm::TokenTree::Literal(l.as_native()),
}
}
}
impl From<pm::Group> for Group {
fn from(p: pm::Group) -> Self {
let span = p.span();
let span_open = p.span_open();
let span_close = p.span_close();
let delimiter = p.delimiter();
let stream = p.stream().into();
Self {
span,
span_open,
span_close,
delimiter,
stream,
}
}
}
impl AsNative for Group {
type Native = pm::Group;
fn as_native(&self) -> pm::Group {
let mut g = pm::Group::new(self.delimiter, self.stream.as_native());
g.set_span(self.span);
g
}
}
impl From<pm::Ident> for Ident {
fn from(p: pm::Ident) -> Self {
let span = p.span();
let ident = p.to_string();
Self { span, ident }
}
}
impl AsNative for Ident {
type Native = pm::Ident;
fn as_native(&self) -> pm::Ident {
pm::Ident::new(&self.ident, self.span)
}
}
impl From<pm::Punct> for Punct {
fn from(p: pm::Punct) -> Self {
use PunctKind::*;
let span = p.span();
let spacing = p.spacing();
let kind = match p.as_char() {
';' => Semicolon,
',' => Comma,
'.' => Dot,
'@' => At,
'~' => Tilde,
'?' => Question,
':' => Colon,
'$' => Dollar,
'=' => Eq,
'!' => Not,
'<' => Lt,
'>' => Gt,
'-' => Minus,
'&' => And,
'|' => Or,
'+' => Plus,
'*' => Star,
'/' => Slash,
'^' => Caret,
'%' => Percent,
x => panic!("Found unknown punctuation token: `{}`", x),
};
Self {
kind,
spacing,
span,
}
}
}
impl AsNative for Punct {
type Native = pm::Punct;
fn as_native(&self) -> pm::Punct {
pm::Punct::new(self.kind.as_char(), self.spacing)
}
}
impl PunctKind {
pub fn as_char(&self) -> char {
use PunctKind::*;
match *self {
Semicolon => ';',
Comma => ',',
Dot => '.',
At => '@',
Tilde => '~',
Question => '?',
Colon => ':',
Dollar => '$',
Eq => '=',
Not => '!',
Lt => '<',
Gt => '>',
Minus => '-',
And => '&',
Or => '|',
Plus => '+',
Star => '*',
Slash => '/',
Caret => '^',
Percent => '%',
}
}
}
macro_rules! totokens_impl {
($($ty:ident),+) => {
$(
impl ToTokens for $ty {
fn to_tokens(&self, tokens: &mut pm::TokenStream) {
self.as_native().to_tokens(tokens)
}
}
)+
};
}
totokens_impl!(TokenStream, TokenTree, Group, Ident, Punct, Literal);