#[cfg(feature = "proc-macro")]
use proc_macro as pm;
use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream};
use proc_macro2::{Group, Punct, TokenTree};
use std::marker::PhantomData;
use std::ptr;
#[cfg(synom_verbose_trace)]
use std::fmt::{self, Debug};
enum Entry {
Group(Span, Delimiter, TokenBuffer),
Ident(Ident),
Punct(Punct),
Literal(Literal),
End(*const Entry),
}
pub struct TokenBuffer {
data: Box<[Entry]>,
}
impl TokenBuffer {
fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
let mut entries = Vec::new();
let mut seqs = Vec::new();
for tt in stream {
match tt {
TokenTree::Ident(sym) => {
entries.push(Entry::Ident(sym));
}
TokenTree::Punct(op) => {
entries.push(Entry::Punct(op));
}
TokenTree::Literal(l) => {
entries.push(Entry::Literal(l));
}
TokenTree::Group(g) => {
seqs.push((entries.len(), g.span(), g.delimiter(), g.stream().clone()));
entries.push(Entry::End(ptr::null()));
}
}
}
entries.push(Entry::End(up));
let mut entries = entries.into_boxed_slice();
for (idx, span, delim, seq_stream) in seqs {
let seq_up = &entries[idx + 1] as *const Entry;
let inner = Self::inner_new(seq_stream, seq_up);
entries[idx] = Entry::Group(span, delim, inner);
}
TokenBuffer { data: entries }
}
#[cfg(feature = "proc-macro")]
pub fn new(stream: pm::TokenStream) -> TokenBuffer {
Self::new2(stream.into())
}
pub fn new2(stream: TokenStream) -> TokenBuffer {
Self::inner_new(stream, ptr::null())
}
pub fn begin(&self) -> Cursor {
unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Cursor<'a> {
ptr: *const Entry,
scope: *const Entry,
marker: PhantomData<&'a Entry>,
}
impl<'a> Cursor<'a> {
pub fn empty() -> Self {
struct UnsafeSyncEntry(Entry);
unsafe impl Sync for UnsafeSyncEntry {}
static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));
Cursor {
ptr: &EMPTY_ENTRY.0,
scope: &EMPTY_ENTRY.0,
marker: PhantomData,
}
}
unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
while let Entry::End(exit) = *ptr {
if ptr == scope {
break;
}
ptr = exit;
}
Cursor {
ptr: ptr,
scope: scope,
marker: PhantomData,
}
}
fn entry(self) -> &'a Entry {
unsafe { &*self.ptr }
}
unsafe fn bump(self) -> Cursor<'a> {
Cursor::create(self.ptr.offset(1), self.scope)
}
fn ignore_none(&mut self) {
if let Entry::Group(_, Delimiter::None, ref buf) = *self.entry() {
unsafe {
*self = Cursor::create(&buf.data[0], self.scope);
}
}
}
#[inline]
pub fn eof(self) -> bool {
self.ptr == self.scope
}
pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
if delim != Delimiter::None {
self.ignore_none();
}
if let Entry::Group(span, group_delim, ref buf) = *self.entry() {
if group_delim == delim {
return Some((buf.begin(), span, unsafe { self.bump() }));
}
}
None
}
pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
self.ignore_none();
match *self.entry() {
Entry::Ident(ref ident) => Some((ident.clone(), unsafe { self.bump() })),
_ => None,
}
}
pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
self.ignore_none();
match *self.entry() {
Entry::Punct(ref op) => Some((op.clone(), unsafe { self.bump() })),
_ => None,
}
}
pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
self.ignore_none();
match *self.entry() {
Entry::Literal(ref lit) => Some((lit.clone(), unsafe { self.bump() })),
_ => None,
}
}
pub fn token_stream(self) -> TokenStream {
let mut tts = Vec::new();
let mut cursor = self;
while let Some((tt, rest)) = cursor.token_tree() {
tts.push(tt);
cursor = rest;
}
tts.into_iter().collect()
}
pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
let tree = match *self.entry() {
Entry::Group(span, delim, ref buf) => {
let stream = buf.begin().token_stream();
let mut g = Group::new(delim, stream);
g.set_span(span);
TokenTree::from(g)
}
Entry::Literal(ref lit) => lit.clone().into(),
Entry::Ident(ref ident) => ident.clone().into(),
Entry::Punct(ref op) => op.clone().into(),
Entry::End(..) => {
return None;
}
};
Some((tree, unsafe { self.bump() }))
}
pub fn span(self) -> Span {
match *self.entry() {
Entry::Group(span, ..) => span,
Entry::Literal(ref l) => l.span(),
Entry::Ident(ref t) => t.span(),
Entry::Punct(ref o) => o.span(),
Entry::End(..) => Span::call_site(),
}
}
}
#[cfg(synom_verbose_trace)]
impl<'a> Debug for Cursor<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Cursor")
.field(&self.token_stream().to_string())
.finish()
}
}