use proc_macro as pm;
use proc_macro2::{Delimiter, Literal, Spacing, Span, Term, TokenNode, TokenStream, TokenTree};
use std::ptr;
use std::marker::PhantomData;
#[cfg(synom_verbose_trace)]
use std::fmt::{self, Debug};
enum Entry {
Group(Span, Delimiter, TokenBuffer),
Term(Span, Term),
Op(Span, char, Spacing),
Literal(Span, 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.kind {
TokenNode::Term(sym) => {
entries.push(Entry::Term(tt.span, sym));
}
TokenNode::Op(chr, ok) => {
entries.push(Entry::Op(tt.span, chr, ok));
}
TokenNode::Literal(lit) => {
entries.push(Entry::Literal(tt.span, lit));
}
TokenNode::Group(delim, seq_stream) => {
seqs.push((entries.len(), tt.span, delim, seq_stream));
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 }
}
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 term(mut self) -> Option<(Span, Term, Cursor<'a>)> {
self.ignore_none();
match *self.entry() {
Entry::Term(span, term) => Some((span, term, unsafe { self.bump() })),
_ => None,
}
}
pub fn op(mut self) -> Option<(Span, char, Spacing, Cursor<'a>)> {
self.ignore_none();
match *self.entry() {
Entry::Op(span, op, spacing) => Some((span, op, spacing, unsafe { self.bump() })),
_ => None,
}
}
pub fn literal(mut self) -> Option<(Span, Literal, Cursor<'a>)> {
self.ignore_none();
match *self.entry() {
Entry::Literal(span, ref lit) => Some((span, 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();
TokenTree {
span: span,
kind: TokenNode::Group(delim, stream),
}
}
Entry::Literal(span, ref lit) => TokenTree {
span: span,
kind: TokenNode::Literal(lit.clone()),
},
Entry::Term(span, sym) => TokenTree {
span: span,
kind: TokenNode::Term(sym),
},
Entry::Op(span, chr, spacing) => TokenTree {
span: span,
kind: TokenNode::Op(chr, spacing),
},
Entry::End(..) => {
return None;
}
};
Some((tree, unsafe { self.bump() }))
}
pub fn span(self) -> Span {
match *self.entry() {
Entry::Group(span, ..)
| Entry::Literal(span, ..)
| Entry::Term(span, ..)
| Entry::Op(span, ..) => 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()
}
}