Merge synom into syn
diff --git a/src/attr.rs b/src/attr.rs
index 56fa087..74ed01f 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -292,7 +292,8 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use synom::{PResult, Cursor, parse_error};
+ use cursor::Cursor;
+ use {PResult, parse_error};
use proc_macro2::{TokenNode, Spacing, TokenTree};
fn eq() -> TokenTree {
diff --git a/src/cursor.rs b/src/cursor.rs
new file mode 100644
index 0000000..3732454
--- /dev/null
+++ b/src/cursor.rs
@@ -0,0 +1,356 @@
+//! This module defines a cheaply-copyable cursor into a TokenStream's data.
+//!
+//! It does this by copying the data into a stably-addressed structured buffer,
+//! and holding raw pointers into that buffer to allow walking through delimited
+//! sequences cheaply.
+//!
+//! This module is heavily commented as it contains the only unsafe code in
+//! `syn`, and caution should be made when editing it. It provides a safe
+//! interface, but is fragile internally.
+
+use proc_macro2::*;
+
+use std::ptr;
+use std::fmt;
+use std::marker::PhantomData;
+
+/// Internal type which is used instead of `TokenTree` to represent a single
+/// `TokenTree` within a `SynomBuffer`.
+#[derive(Debug)]
+enum Entry {
+ /// Mimicing types from proc-macro.
+ Group(Span, Delimiter, SynomBuffer),
+ Term(Span, Term),
+ Op(Span, char, Spacing),
+ Literal(Span, Literal),
+ /// End entries contain a raw pointer to the entry from the containing
+ /// TokenTree.
+ End(*const Entry),
+}
+
+/// A buffer of data which contains a structured representation of the input
+/// `TokenStream` object.
+#[derive(Debug)]
+pub struct SynomBuffer {
+ // NOTE: Do not derive clone on this - there are raw pointers inside which
+ // will be messed up. Moving the `SynomBuffer` itself is safe as the actual
+ // backing slices won't be moved.
+ data: Box<[Entry]>,
+}
+
+impl SynomBuffer {
+ // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
+ // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
+ fn inner_new(stream: TokenStream, up: *const Entry) -> SynomBuffer {
+ // Build up the entries list, recording the locations of any Groups
+ // in the list to be processed later.
+ let mut entries = Vec::new();
+ let mut seqs = Vec::new();
+ for tt in stream.into_iter() {
+ 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) => {
+ // Record the index of the interesting entry, and store an
+ // `End(null)` there temporarially.
+ seqs.push((entries.len(), tt.span, delim, seq_stream));
+ entries.push(Entry::End(ptr::null()));
+ }
+ }
+ }
+ // Add an `End` entry to the end with a reference to the enclosing token
+ // stream which was passed in.
+ entries.push(Entry::End(up));
+
+ // NOTE: This is done to ensure that we don't accidentally modify the
+ // length of the backing buffer. The backing buffer must remain at a
+ // constant address after this point, as we are going to store a raw
+ // pointer into it.
+ let mut entries = entries.into_boxed_slice();
+ for (idx, span, delim, seq_stream) in seqs {
+ // We know that this index refers to one of the temporary
+ // `End(null)` entries, and we know that the last entry is
+ // `End(up)`, so the next index is also valid.
+ let seq_up = &entries[idx + 1] as *const Entry;
+
+ // The end entry stored at the end of this Entry::Group should
+ // point to the Entry which follows the Group in the list.
+ let inner = Self::inner_new(seq_stream, seq_up);
+ entries[idx] = Entry::Group(span, delim, inner);
+ }
+
+ SynomBuffer {
+ data: entries
+ }
+ }
+
+ /// Create a new SynomBuffer, which contains the data from the given
+ /// TokenStream.
+ pub fn new(stream: TokenStream) -> SynomBuffer {
+ Self::inner_new(stream, ptr::null())
+ }
+
+ /// Create a cursor referencing the first token in the input.
+ pub fn begin(&self) -> Cursor {
+ unsafe {
+ Cursor::create(&self.data[0], &self.data[self.data.len() - 1])
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct SeqInfo<'a> {
+ pub span: Span,
+ pub inside: Cursor<'a>,
+ pub outside: Cursor<'a>,
+}
+
+/// A cursor into an input `TokenStream`'s data. This cursor holds a reference
+/// into the immutable data which is used internally to represent a
+/// `TokenStream`, and can be efficiently manipulated and copied around.
+///
+/// An empty `Cursor` can be created directly, or one may create a `SynomBuffer`
+/// object and get a cursor to its first token with `begin()`.
+///
+/// Two cursors are equal if they have the same location in the same input
+/// stream, and have the same scope.
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct Cursor<'a> {
+ /// The current entry which the `Cursor` is pointing at.
+ ptr: *const Entry,
+ /// This is the only `Entry::End(..)` object which this cursor is allowed to
+ /// point at. All other `End` objects are skipped over in `Cursor::create`.
+ scope: *const Entry,
+ /// This uses the &'a reference which guarantees that these pointers are
+ /// still valid.
+ marker: PhantomData<&'a Entry>,
+}
+
+impl<'a> Cursor<'a> {
+ /// Create a cursor referencing a static empty TokenStream.
+ pub fn empty() -> Self {
+ // It's safe in this situation for us to put an `Entry` object in global
+ // storage, despite it not actually being safe to send across threads
+ // (`Term` is a reference into a thread-local table). This is because
+ // this entry never includes a `Term` object.
+ //
+ // This wrapper struct allows us to break the rules and put a `Sync`
+ // object in global storage.
+ 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,
+ }
+ }
+
+ /// This create method intelligently exits non-explicitly-entered
+ /// `None`-delimited scopes when the cursor reaches the end of them,
+ /// allowing for them to be treated transparently.
+ unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
+ // NOTE: If we're looking at a `End(..)`, we want to advance the cursor
+ // past it, unless `ptr == scope`, which means that we're at the edge of
+ // our cursor's scope. We should only have `ptr != scope` at the exit
+ // from None-delimited sequences entered with `ignore_none`.
+ while let Entry::End(exit) = *ptr {
+ if ptr == scope {
+ break;
+ }
+ ptr = exit;
+ }
+
+ Cursor {
+ ptr: ptr,
+ scope: scope,
+ marker: PhantomData,
+ }
+ }
+
+ /// Get the current entry.
+ fn entry(self) -> &'a Entry {
+ unsafe { &*self.ptr }
+ }
+
+ /// Bump the cursor to point at the next token after the current one. This
+ /// is undefined behavior if the cursor is currently looking at an
+ /// `Entry::End`.
+ unsafe fn bump(self) -> Cursor<'a> {
+ Cursor::create(self.ptr.offset(1), self.scope)
+ }
+
+ /// If the cursor is looking at a `None`-delimited sequence, move it to look
+ /// at the first token inside instead. If the sequence is empty, this will
+ /// move the cursor past the `None`-delimited sequence.
+ ///
+ /// WARNING: This mutates its argument.
+ fn ignore_none(&mut self) {
+ if let Entry::Group(_, Delimiter::None, ref buf) = *self.entry() {
+ // NOTE: We call `Cursor::create` here to make sure that situations
+ // where we should immediately exit the span after entering it are
+ // handled correctly.
+ unsafe {
+ *self = Cursor::create(&buf.data[0], self.scope);
+ }
+ }
+ }
+
+ /// Check if the cursor is currently pointing at the end of its valid scope.
+ #[inline]
+ pub fn eof(self) -> bool {
+ // We're at eof if we're at the end of our scope.
+ self.ptr == self.scope
+ }
+
+ /// If the cursor is pointing at a Seq with the given `Delimiter`, return a
+ /// cursor into that sequence, and one pointing to the next `TokenTree`.
+ pub fn seq(mut self, seq_delim: Delimiter) -> Option<SeqInfo<'a>> {
+ // If we're not trying to enter a none-delimited sequence, we want to
+ // ignore them. We have to make sure to _not_ ignore them when we want
+ // to enter them, of course. For obvious reasons.
+ if seq_delim != Delimiter::None {
+ self.ignore_none();
+ }
+
+ match *self.entry() {
+ Entry::Group(span, delim, ref buf) => {
+ if delim != seq_delim {
+ return None;
+ }
+
+ Some(SeqInfo {
+ span: span,
+ inside: buf.begin(),
+ outside: unsafe { self.bump() },
+ })
+ }
+ _ => None
+ }
+ }
+
+ /// If the cursor is pointing at a Term, return it and a cursor pointing at
+ /// the next `TokenTree`.
+ pub fn word(mut self) -> Option<(Cursor<'a>, Span, Term)> {
+ self.ignore_none();
+ match *self.entry() {
+ Entry::Term(span, sym) => {
+ Some((
+ unsafe { self.bump() },
+ span,
+ sym,
+ ))
+ }
+ _ => None
+ }
+ }
+
+ /// If the cursor is pointing at an Op, return it and a cursor pointing
+ /// at the next `TokenTree`.
+ pub fn op(mut self) -> Option<(Cursor<'a>, Span, char, Spacing)> {
+ self.ignore_none();
+ match *self.entry() {
+ Entry::Op(span, chr, kind) => {
+ Some((
+ unsafe { self.bump() },
+ span,
+ chr,
+ kind,
+ ))
+ }
+ _ => None
+ }
+ }
+
+ /// If the cursor is pointing at a Literal, return it and a cursor pointing
+ /// at the next `TokenTree`.
+ pub fn literal(mut self) -> Option<(Cursor<'a>, Span, Literal)> {
+ self.ignore_none();
+ match *self.entry() {
+ Entry::Literal(span, ref lit) => {
+ Some((
+ unsafe { self.bump() },
+ span,
+ lit.clone(),
+ ))
+ }
+ _ => None
+ }
+ }
+
+ /// Copy all remaining tokens visible from this cursor into a `TokenStream`.
+ pub fn token_stream(self) -> TokenStream {
+ let mut tts = Vec::new();
+ let mut cursor = self;
+ while let Some((next, tt)) = cursor.token_tree() {
+ tts.push(tt);
+ cursor = next;
+ }
+ tts.into_iter().collect()
+ }
+
+ /// If the cursor is looking at a `TokenTree`, returns it along with a
+ /// cursor pointing to the next token in the sequence, otherwise returns
+ /// `None`.
+ ///
+ /// This method does not treat `None`-delimited sequences as invisible, and
+ /// will return a `Group(None, ..)` if the cursor is looking at one.
+ pub fn token_tree(self) -> Option<(Cursor<'a>, TokenTree)> {
+ 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, kind) => {
+ TokenTree {
+ span: span,
+ kind: TokenNode::Op(chr, kind),
+ }
+ }
+ Entry::End(..) => {
+ return None;
+ }
+ };
+
+ Some((
+ unsafe { self.bump() },
+ tree
+ ))
+ }
+}
+
+// We do a custom implementation for `Debug` as the default implementation is
+// pretty useless.
+impl<'a> fmt::Debug for Cursor<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // Print what the cursor is currently looking at.
+ // This will look like Cursor("some remaining tokens here")
+ f.debug_tuple("Cursor")
+ .field(&self.token_stream().to_string())
+ .finish()
+ }
+}
diff --git a/src/delimited.rs b/src/delimited.rs
new file mode 100644
index 0000000..044ffc9
--- /dev/null
+++ b/src/delimited.rs
@@ -0,0 +1,495 @@
+use std::iter::FromIterator;
+use std::slice;
+use std::vec;
+#[cfg(feature = "extra-traits")]
+use std::fmt::{self, Debug};
+
+#[cfg_attr(feature = "extra-traits", derive(Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct Delimited<T, D> {
+ inner: Vec<(T, Option<D>)>
+}
+
+impl<T, D> Delimited<T, D> {
+ pub fn new() -> Delimited<T, D> {
+ Delimited {
+ inner: Vec::new(),
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.inner.len() == 0
+ }
+
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ pub fn get(&self, idx: usize) -> Element<&T, &D> {
+ let (ref t, ref d) = self.inner[idx];
+ match *d {
+ Some(ref d) => Element::Delimited(t, d),
+ None => Element::End(t),
+ }
+ }
+
+ pub fn get_mut(&mut self, idx: usize) -> Element<&mut T, &mut D> {
+ let (ref mut t, ref mut d) = self.inner[idx];
+ match *d {
+ Some(ref mut d) => Element::Delimited(t, d),
+ None => Element::End(t),
+ }
+ }
+
+ pub fn first(&self) -> Option<Element<&T, &D>> {
+ self.inner.first().map(|&(ref t, ref d)| {
+ match *d {
+ Some(ref d) => Element::Delimited(t, d),
+ None => Element::End(t),
+ }
+ })
+ }
+
+ pub fn first_mut(&mut self) -> Option<Element<&mut T, &mut D>> {
+ self.inner.first_mut().map(|&mut (ref mut t, ref mut d)| {
+ match *d {
+ Some(ref mut d) => Element::Delimited(t, d),
+ None => Element::End(t),
+ }
+ })
+ }
+
+ pub fn last(&self) -> Option<Element<&T, &D>> {
+ self.inner.last().map(|&(ref t, ref d)| {
+ match *d {
+ Some(ref d) => Element::Delimited(t, d),
+ None => Element::End(t),
+ }
+ })
+ }
+
+ pub fn last_mut(&mut self) -> Option<Element<&mut T, &mut D>> {
+ self.inner.last_mut().map(|&mut (ref mut t, ref mut d)| {
+ match *d {
+ Some(ref mut d) => Element::Delimited(t, d),
+ None => Element::End(t),
+ }
+ })
+ }
+
+ pub fn iter(&self) -> Iter<T, D> {
+ Iter { inner: self.inner.iter() }
+ }
+
+ pub fn iter_mut(&mut self) -> IterMut<T, D> {
+ IterMut { inner: self.inner.iter_mut() }
+ }
+
+ pub fn items(&self) -> Items<T, D> {
+ Items { inner: self.inner.iter() }
+ }
+
+ pub fn push(&mut self, token: Element<T, D>) {
+ assert!(self.is_empty() || self.trailing_delim());
+ match token {
+ Element::Delimited(t, d) => self.inner.push((t, Some(d))),
+ Element::End(t) => self.inner.push((t, None)),
+ }
+ }
+
+ pub fn push_first(&mut self, token: T) {
+ assert!(self.is_empty());
+ self.inner.push((token, None));
+ }
+
+ pub fn push_next(&mut self, token: T, delimiter: D) {
+ self.push_trailing(delimiter);
+ self.inner.push((token, None));
+ }
+
+ pub fn push_trailing(&mut self, delimiter: D) {
+ let len = self.len();
+ assert!(self.inner[len - 1].1.is_none());
+ self.inner[len - 1].1 = Some(delimiter);
+ }
+
+ pub fn push_default(&mut self, token: T) where D: Default {
+ if self.is_empty() || self.trailing_delim() {
+ self.inner.push((token, None));
+ } else {
+ self.push_next(token, D::default());
+ }
+ }
+
+ pub fn pop(&mut self) -> Option<Element<T, D>> {
+ self.inner.pop().map(|e| {
+ match e {
+ (t, Some(d)) => Element::Delimited(t, d),
+ (t, None) => Element::End(t),
+ }
+ })
+ }
+
+ pub fn into_vec(self) -> Vec<T> {
+ self.inner.into_iter().map(|t| t.0).collect()
+ }
+
+ pub fn trailing_delim(&self) -> bool {
+ self.inner[self.inner.len() - 1].1.is_some()
+ }
+
+ /// Returns true if either this `Delimited` is empty, or it has a trailing
+ /// delimiter. This is useful within `ToTokens` implementations for `syn`.
+ #[doc(hidden)]
+ pub fn empty_or_trailing(&self) -> bool {
+ self.is_empty() || self.trailing_delim()
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl<T: Debug, D: Debug> Debug for Delimited<T, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl<T, D> From<Vec<(T, Option<D>)>> for Delimited<T, D> {
+ fn from(v: Vec<(T, Option<D>)>) -> Self {
+ Delimited {
+ inner: v,
+ }
+ }
+}
+
+impl<T, D> From<Vec<T>> for Delimited<T, D>
+ where D: Default,
+{
+ fn from(v: Vec<T>) -> Self {
+ let len = v.len();
+ Delimited {
+ inner: v.into_iter().enumerate().map(|(i, item)| {
+ (item, if i + 1 == len {None} else {Some(D::default())})
+ }).collect(),
+ }
+ }
+}
+
+impl<T, D> FromIterator<Element<T, D>> for Delimited<T, D> {
+ fn from_iter<I: IntoIterator<Item = Element<T, D>>>(i: I) -> Self {
+ let mut ret = Delimited::new();
+ ret.extend(i);
+ ret
+ }
+}
+
+impl<T, D> FromIterator<T> for Delimited<T, D>
+ where D: Default,
+{
+ fn from_iter<I: IntoIterator<Item = T>>(i: I) -> Self {
+ let mut ret = Delimited::new();
+ ret.extend(i);
+ ret
+ }
+}
+
+impl<T, D> Extend<Element<T, D>> for Delimited<T, D> {
+ fn extend<I: IntoIterator<Item = Element<T, D>>>(&mut self, i: I) {
+ for element in i {
+ match element {
+ Element::Delimited(a, b) => self.inner.push((a, Some(b))),
+ Element::End(a) => self.inner.push((a, None)),
+ }
+ }
+ }
+}
+
+impl<T, D> Extend<T> for Delimited<T, D>
+ where D: Default,
+{
+ fn extend<I: IntoIterator<Item = T>>(&mut self, i: I) {
+ for element in i {
+ self.push_default(element);
+ }
+ }
+}
+
+impl<'a, T, D> IntoIterator for &'a Delimited<T, D> {
+ type Item = Element<&'a T, &'a D>;
+ type IntoIter = Iter<'a, T, D>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ <Delimited<T, D>>::iter(self)
+ }
+}
+
+impl<'a, T, D> IntoIterator for &'a mut Delimited<T, D> {
+ type Item = Element<&'a mut T, &'a mut D>;
+ type IntoIter = IterMut<'a, T, D>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ <Delimited<T, D>>::iter_mut(self)
+ }
+}
+
+impl<T, D> IntoIterator for Delimited<T, D> {
+ type Item = Element<T, D>;
+ type IntoIter = IntoIter<T, D>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ IntoIter { inner: self.inner.into_iter() }
+ }
+}
+
+impl<T, D> Default for Delimited<T, D> {
+ fn default() -> Self {
+ Delimited::new()
+ }
+}
+
+pub struct Iter<'a, T: 'a, D: 'a> {
+ inner: slice::Iter<'a, (T, Option<D>)>,
+}
+
+impl<'a, T, D> Iterator for Iter<'a, T, D> {
+ type Item = Element<&'a T, &'a D>;
+
+ fn next(&mut self) -> Option<Element<&'a T, &'a D>> {
+ self.inner.next().map(|pair| {
+ match pair.1 {
+ Some(ref delimited) => Element::Delimited(&pair.0, delimited),
+ None => Element::End(&pair.0),
+ }
+ })
+ }
+}
+
+pub struct IterMut<'a, T: 'a, D: 'a> {
+ inner: slice::IterMut<'a, (T, Option<D>)>,
+}
+
+impl<'a, T, D> Iterator for IterMut<'a, T, D> {
+ type Item = Element<&'a mut T, &'a mut D>;
+
+ fn next(&mut self) -> Option<Element<&'a mut T, &'a mut D>> {
+ self.inner.next().map(|pair| {
+ match pair.1 {
+ Some(ref mut delimited) => Element::Delimited(&mut pair.0, delimited),
+ None => Element::End(&mut pair.0),
+ }
+ })
+ }
+}
+
+pub struct Items<'a, T: 'a, D: 'a> {
+ inner: slice::Iter<'a, (T, Option<D>)>,
+}
+
+impl<'a, T, D> Iterator for Items<'a, T, D> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<&'a T> {
+ self.inner.next().map(|pair| &pair.0)
+ }
+}
+
+pub struct IntoIter<T, D> {
+ inner: vec::IntoIter<(T, Option<D>)>,
+}
+
+impl<T, D> Iterator for IntoIter<T, D> {
+ type Item = Element<T, D>;
+
+ fn next(&mut self) -> Option<Element<T, D>> {
+ self.inner.next().map(|pair| {
+ match pair.1 {
+ Some(v) => Element::Delimited(pair.0, v),
+ None => Element::End(pair.0)
+ }
+ })
+ }
+}
+
+pub enum Element<T, D> {
+ Delimited(T, D),
+ End(T),
+}
+
+impl<T, D> Element<T, D> {
+ pub fn into_item(self) -> T {
+ match self {
+ Element::Delimited(t, _) |
+ Element::End(t) => t,
+ }
+ }
+
+ pub fn item(&self) -> &T {
+ match *self {
+ Element::Delimited(ref t, _) |
+ Element::End(ref t) => t,
+ }
+ }
+
+ pub fn item_mut(&mut self) -> &mut T {
+ match *self {
+ Element::Delimited(ref mut t, _) |
+ Element::End(ref mut t) => t,
+ }
+ }
+
+ pub fn delimiter(&self) -> Option<&D> {
+ match *self {
+ Element::Delimited(_, ref d) => Some(d),
+ Element::End(_) => None,
+ }
+ }
+
+ pub fn into_tuple(self) -> (T, Option<D>) {
+ match self {
+ Element::Delimited(t, d) => (t, Some(d)),
+ Element::End(t) => (t, None),
+ }
+ }
+}
+
+#[cfg(feature = "parsing")]
+mod parsing {
+ use super::Delimited;
+ use synom::Synom;
+ use cursor::Cursor;
+ use {PResult, parse_error};
+
+ impl<T, D> Delimited<T, D>
+ where T: Synom,
+ D: Synom,
+ {
+ pub fn parse_separated(input: Cursor) -> PResult<Self>
+ {
+ Self::parse(input, T::parse, false)
+ }
+
+ pub fn parse_separated_nonempty(input: Cursor) -> PResult<Self>
+ {
+ Self::parse_separated_nonempty_with(input, T::parse)
+ }
+
+ pub fn parse_terminated(input: Cursor) -> PResult<Self>
+ {
+ Self::parse_terminated_with(input, T::parse)
+ }
+
+ pub fn parse_terminated_nonempty(input: Cursor) -> PResult<Self>
+ {
+ Self::parse_terminated_nonempty_with(input, T::parse)
+ }
+ }
+
+ impl<T, D> Delimited<T, D>
+ where D: Synom,
+ {
+ pub fn parse_separated_nonempty_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>)
+ -> PResult<Self>
+ {
+ match Self::parse(input, parse, false) {
+ Ok((_, ref b)) if b.is_empty() => parse_error(),
+ other => other,
+ }
+ }
+
+ pub fn parse_terminated_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>)
+ -> PResult<Self>
+ {
+ Self::parse(input, parse, true)
+ }
+
+ pub fn parse_terminated_nonempty_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>)
+ -> PResult<Self>
+ {
+ match Self::parse(input, parse, true) {
+ Ok((_, ref b)) if b.is_empty() => parse_error(),
+ other => other,
+ }
+ }
+
+ fn parse(mut input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ terminated: bool)
+ -> PResult<Self>
+ {
+ let mut res = Delimited::new();
+
+ // get the first element
+ match parse(input) {
+ Err(_) => Ok((input, res)),
+ Ok((i, o)) => {
+ if i == input {
+ return parse_error();
+ }
+ input = i;
+ res.push_first(o);
+
+ // get the separator first
+ while let Ok((i2, s)) = D::parse(input) {
+ if i2 == input {
+ break;
+ }
+
+ // get the element next
+ if let Ok((i3, o3)) = parse(i2) {
+ if i3 == i2 {
+ break;
+ }
+ res.push_next(o3, s);
+ input = i3;
+ } else {
+ break;
+ }
+ }
+ if terminated {
+ if let Ok((after, sep)) = D::parse(input) {
+ res.push_trailing(sep);
+ input = after;
+ }
+ }
+ Ok((input, res))
+ }
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use quote::{Tokens, ToTokens};
+
+
+ impl<T, D> ToTokens for Delimited<T, D>
+ where T: ToTokens,
+ D: ToTokens,
+ {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append_all(self.iter())
+ }
+ }
+
+ impl<T, D> ToTokens for Element<T, D>
+ where T: ToTokens,
+ D: ToTokens,
+ {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ match *self {
+ Element::Delimited(ref a, ref b) => {
+ a.to_tokens(tokens);
+ b.to_tokens(tokens);
+ }
+ Element::End(ref a) => a.to_tokens(tokens),
+ }
+ }
+ }
+}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..d1bb670
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,54 @@
+use proc_macro;
+use proc_macro2;
+use std::error::Error;
+use cursor::Cursor;
+use std::fmt::{self, Display};
+
+/// The result of a parser
+pub type PResult<'a, O> = Result<(Cursor<'a>, O), ParseError>;
+
+/// An error with a default error message.
+///
+/// NOTE: We should provide better error messages in the future.
+pub fn parse_error<O>() -> PResult<'static, O> {
+ Err(ParseError(None))
+}
+
+#[derive(Debug)]
+pub struct ParseError(Option<String>);
+
+impl Error for ParseError {
+ fn description(&self) -> &str {
+ match self.0 {
+ Some(ref desc) => desc,
+ None => "failed to parse",
+ }
+ }
+}
+
+impl Display for ParseError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ <str as fmt::Display>::fmt(self.description(), f)
+ }
+}
+
+impl From<proc_macro2::LexError> for ParseError {
+ fn from(_: proc_macro2::LexError) -> ParseError {
+ ParseError(Some("error while lexing input string".to_owned()))
+ }
+}
+
+impl From<proc_macro::LexError> for ParseError {
+ fn from(_: proc_macro::LexError) -> ParseError {
+ ParseError(Some("error while lexing input string".to_owned()))
+ }
+}
+
+impl ParseError {
+ // For syn use only. Not public API.
+ #[doc(hidden)]
+ pub fn new<T: Into<String>>(msg: T) -> Self {
+ ParseError(Some(msg.into()))
+ }
+}
+
diff --git a/src/expr.rs b/src/expr.rs
index 16f277c..a0505a4 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -660,9 +660,11 @@
#[cfg(feature = "full")]
use proc_macro2::{TokenStream, TokenNode, Delimiter, Term};
- use synom::{PResult, Cursor, Synom};
+ use synom::Synom;
+ use cursor::Cursor;
#[cfg(feature = "full")]
- use synom::parse_error;
+ use parse_error;
+ use PResult;
// When we're parsing expressions which occur before blocks, like in an if
// statement's condition, we cannot parse a struct literal.
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index 84f213d..9fc80a7 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -9,7 +9,7 @@
#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
use *;
-use synom::delimited::Delimited;
+use delimited::Delimited;
trait FoldHelper {
type Item;
diff --git a/src/generics.rs b/src/generics.rs
index 2c116fa..12d33d0 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -202,7 +202,7 @@
use super::*;
use synom::Synom;
- use synom::delimited::Element;
+ use delimited::Element;
impl Synom for Generics {
named!(parse -> Self, map!(
diff --git a/src/helper.rs b/src/helper.rs
new file mode 100644
index 0000000..50595d9
--- /dev/null
+++ b/src/helper.rs
@@ -0,0 +1,247 @@
+/// Turn a failed parse into `None` and a successful parse into `Some`.
+///
+/// - **Syntax:** `option!(THING)`
+/// - **Output:** `Option<THING>`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::tokens::Bang;
+///
+/// named!(maybe_bang -> Option<Bang>, option!(punct!(!)));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! option {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((i, o)) =>
+ ::std::result::Result::Ok((i, Some(o))),
+ ::std::result::Result::Err(_) =>
+ ::std::result::Result::Ok(($i, None)),
+ }
+ };
+
+ ($i:expr, $f:expr) => {
+ option!($i, call!($f));
+ };
+}
+
+/// Turn a failed parse into an empty vector. The argument parser must itself
+/// return a vector.
+///
+/// This is often more convenient than `option!(...)` when the argument produces
+/// a vector.
+///
+/// - **Syntax:** `opt_vec!(THING)`
+/// - **Output:** `THING`, which must be `Vec<T>`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Lifetime, Type};
+/// use syn::delimited::Delimited;
+/// use syn::tokens::*;
+///
+/// named!(bound_lifetimes -> (Vec<Lifetime>, Type), tuple!(
+/// opt_vec!(do_parse!(
+/// keyword!(for) >>
+/// punct!(<) >>
+/// lifetimes: call!(Delimited::<Lifetime, Comma>::parse_terminated) >>
+/// punct!(>) >>
+/// (lifetimes.into_vec())
+/// )),
+/// syn!(Type)
+/// ));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! opt_vec {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((i, o)) =>
+ ::std::result::Result::Ok((i, o)),
+ ::std::result::Result::Err(_) =>
+ ::std::result::Result::Ok(($i, Vec::new()))
+ }
+ };
+}
+
+/// Parses nothing and always succeeds.
+///
+/// This can be useful as a fallthrough case in `alt!`.
+///
+/// - **Syntax:** `epsilon!()`
+/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Mutability;
+///
+/// named!(mutability -> Mutability, alt!(
+/// keyword!(mut) => { Mutability::Mutable }
+/// |
+/// epsilon!() => { |_| Mutability::Immutable }
+/// ));
+///
+/// # fn main() {}
+#[macro_export]
+macro_rules! epsilon {
+ ($i:expr,) => {
+ ::std::result::Result::Ok(($i, ()))
+ };
+}
+
+/// Run a parser, binding the result to a name, and then evaluating an
+/// expression.
+///
+/// Discards the result of the expression and parser.
+///
+/// - **Syntax:** `tap!(NAME : THING => EXPR)`
+/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Expr, ExprCall};
+/// use syn::tokens::RArrow;
+///
+/// named!(expr_with_arrow_call -> Expr, do_parse!(
+/// mut e: syn!(Expr) >>
+/// many0!(tap!(arg: tuple!(punct!(->), syn!(Expr)) => {
+/// e = Expr {
+/// node: ExprCall {
+/// func: Box::new(e),
+/// args: vec![arg.1].into(),
+/// paren_token: Default::default(),
+/// }.into(),
+/// attrs: Vec::new(),
+/// };
+/// })) >>
+/// (e)
+/// ));
+///
+/// # fn main() {}
+/// ```
+#[doc(hidden)]
+#[macro_export]
+macro_rules! tap {
+ ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((i, o)) => {
+ let $name = o;
+ $e;
+ ::std::result::Result::Ok((i, ()))
+ }
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ }
+ };
+
+ ($i:expr, $name:ident : $f:expr => $e:expr) => {
+ tap!($i, $name: call!($f) => $e);
+ };
+}
+
+/// Parse a type through the `Synom` trait.
+///
+/// This is a convenience macro used to invoke the `Synom::parse` method for a
+/// type, you'll find this in quite a few parsers. This is also the primary way
+/// to parse punctuation.
+///
+/// - **Syntax:** `syn!(TYPE)`
+/// - **Output:** `TYPE`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+///
+/// named!(expression -> Expr, syn!(Expr));
+///
+/// named!(expression_dot -> (Expr, Token![.]), tuple!(syn!(Expr), punct!(.)));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! syn {
+ ($i:expr, $t:ty) => {
+ call!($i, <$t as $crate::synom::Synom>::parse)
+ };
+}
+
+/// Parse a parenthesized-surrounded subtree.
+///
+/// This macro will invoke a sub-parser inside of all tokens contained in
+/// parenthesis. The sub-parser is required to consume all tokens within the
+/// parens or else this parser will return an error.
+///
+/// - **Syntax:** `parens!(SUBPARSER)`
+/// - **Output:** `(SUBPARSER_RET, Paren)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::tokens::Paren;
+///
+/// named!(expr_paren -> (Expr, Paren), parens!(syn!(Expr)));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! parens {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::tokens::Paren::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ parens!($i, call!($f));
+ };
+}
+
+
+/// Same as the `parens` macro, but for brackets.
+#[macro_export]
+macro_rules! brackets {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::tokens::Bracket::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ brackets!($i, call!($f));
+ };
+}
+
+/// Same as the `parens` macro, but for braces.
+#[macro_export]
+macro_rules! braces {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::tokens::Brace::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ braces!($i, call!($f));
+ };
+}
+
+/// Same as the `parens` macro, but for none-delimited sequences (groups).
+#[macro_export]
+macro_rules! grouped {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::tokens::Group::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ grouped!($i, call!($f));
+ };
+}
diff --git a/src/ident.rs b/src/ident.rs
index 5d55957..2555a72 100644
--- a/src/ident.rs
+++ b/src/ident.rs
@@ -226,7 +226,9 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use synom::{Synom, PResult, Cursor, parse_error};
+ use synom::Synom;
+ use cursor::Cursor;
+ use {PResult, parse_error};
impl Synom for Ident {
fn parse(input: Cursor) -> PResult<Self> {
diff --git a/src/lib.rs b/src/lib.rs
index 820c4fd..3f150b7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,11 +15,20 @@
extern crate quote;
#[macro_use]
-extern crate synom;
+#[doc(hidden)]
+pub mod parsers;
#[macro_use]
mod macros;
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[macro_use]
+pub mod helper;
+
+#[macro_use]
+pub mod tokens;
+
mod attr;
pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
MetaNameValue};
@@ -98,9 +107,12 @@
#[cfg(feature = "printing")]
pub use ty::PathTokens;
-pub use synom::span::Span;
-pub use synom::tokens;
-pub use synom::delimited;
+mod cursor;
+pub mod synom;
+pub mod delimited;
+
+mod span;
+pub use span::Span;
mod gen {
#[cfg(feature = "visit")]
@@ -117,10 +129,18 @@
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "parsing")]
-pub use synom::ParseError;
+use synom::Synom;
+#[cfg(feature = "parsing")]
+use cursor::SynomBuffer;
#[cfg(feature = "parsing")]
-use synom::{Synom, SynomBuffer};
+mod error;
+#[cfg(feature = "parsing")]
+pub use error::{PResult, ParseError};
+
+// Not public API.
+#[doc(hidden)]
+pub use error::parse_error;
/// Parse tokens of source code into the chosen syn data type.
///
diff --git a/src/lifetime.rs b/src/lifetime.rs
index 0c975ff..31af27d 100644
--- a/src/lifetime.rs
+++ b/src/lifetime.rs
@@ -92,7 +92,9 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use synom::{Synom, PResult, Cursor, parse_error};
+ use synom::Synom;
+ use cursor::Cursor;
+ use {PResult, parse_error};
impl Synom for Lifetime {
fn parse(input: Cursor) -> PResult<Self> {
diff --git a/src/lit.rs b/src/lit.rs
index a3ddc12..850a8b0 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -101,7 +101,9 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use synom::{Synom, PResult, Cursor, parse_error};
+ use synom::Synom;
+ use cursor::Cursor;
+ use {PResult, parse_error};
impl Synom for Lit {
fn parse(input: Cursor) -> PResult<Self> {
diff --git a/src/mac.rs b/src/mac.rs
index d32f0a5..e370acd 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -133,7 +133,9 @@
use super::*;
use proc_macro2::{TokenNode, TokenTree};
- use synom::{Synom, PResult, Cursor, parse_error};
+ use synom::Synom;
+ use cursor::Cursor;
+ use {PResult, parse_error};
impl Synom for Macro {
named!(parse -> Self, do_parse!(
diff --git a/src/parsers.rs b/src/parsers.rs
new file mode 100644
index 0000000..492d16f
--- /dev/null
+++ b/src/parsers.rs
@@ -0,0 +1,749 @@
+use cursor::Cursor;
+use error::{PResult, parse_error};
+
+/// Define a function from a parser combination.
+///
+/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate syn;
+/// #
+/// # use syn::Type;
+/// # use syn::delimited::Delimited;
+/// #
+/// // One or more Rust types separated by commas.
+/// named!(pub comma_separated_types -> Delimited<Type, Token![,]>,
+/// call!(Delimited::parse_separated_nonempty)
+/// );
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! named {
+ ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ fn $name(i: $crate::synom::Cursor) -> $crate::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+
+ (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ pub fn $name(i: $crate::synom::Cursor) -> $crate::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+
+ // These two variants are for defining named parsers which have custom
+ // arguments, and are called with `call!()`
+ ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ fn $name(i: $crate::synom::Cursor, $($params)*) -> $crate::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+
+ (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ pub fn $name(i: $crate::synom::Cursor, $($params)*) -> $crate::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+}
+
+#[cfg(all(feature = "verbose-trace", not(feature = "all-features")))]
+#[macro_export]
+macro_rules! call {
+ ($i:expr, $fun:expr $(, $args:expr)*) => {
+ {
+ let i = $i;
+ eprintln!(concat!(" -> ", stringify!($fun), " @ {:?}"), i);
+ let r = $fun(i $(, $args)*);
+ match r {
+ Ok((i, _)) => eprintln!(concat!("OK ", stringify!($fun), " @ {:?}"), i),
+ Err(_) => eprintln!(concat!("ERR ", stringify!($fun), " @ {:?}"), i),
+ }
+ r
+ }
+ };
+}
+
+/// Invoke the given parser function with the passed in arguments.
+///
+/// - **Syntax:** `call!(FUNCTION, ARGS...)`
+///
+/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
+/// - **Output:** `T`, the result of invoking the function `FUNCTION`
+#[cfg(any(not(feature = "verbose-trace"), feature = "all-features"))]
+#[macro_export]
+macro_rules! call {
+ ($i:expr, $fun:expr $(, $args:expr)*) => {
+ $fun($i $(, $args)*)
+ };
+}
+
+/// Transform the result of a parser by applying a function or closure.
+///
+/// - **Syntax:** `map!(THING, FN)`
+/// - **Output:** the return type of function FN applied to THING
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Expr, ExprIf};
+///
+/// fn get_cond(if_: ExprIf) -> Expr {
+/// *if_.cond
+/// }
+///
+/// // Parses an `if` statement but returns the condition part only.
+/// named!(if_condition -> Expr,
+/// map!(syn!(ExprIf), get_cond)
+/// );
+///
+/// // Or equivalently:
+/// named!(if_condition2 -> Expr,
+/// map!(syn!(ExprIf), |if_| *if_.cond)
+/// );
+/// #
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! map {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, o)) =>
+ ::std::result::Result::Ok((i, $crate::parsers::invoke($g, o))),
+ }
+ };
+
+ ($i:expr, $f:expr, $g:expr) => {
+ map!($i, call!($f), $g)
+ };
+}
+
+// Somehow this helps with type inference in `map!` and `alt!`.
+//
+// Not public API.
+#[doc(hidden)]
+pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
+ f(t)
+}
+
+/// Parses successfully if the given parser fails to parse. Does not consume any
+/// of the input.
+///
+/// - **Syntax:** `not!(THING)`
+/// - **Output:** `()`
+#[macro_export]
+macro_rules! not {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok(_) => $crate::parse_error(),
+ ::std::result::Result::Err(_) =>
+ ::std::result::Result::Ok(($i, ())),
+ }
+ };
+}
+
+/// Conditionally execute the given parser.
+///
+/// If you are familiar with nom, this is nom's `cond_with_error` parser.
+///
+/// - **Syntax:** `cond!(CONDITION, THING)`
+/// - **Output:** `Some(THING)` if the condition is true, else `None`
+#[macro_export]
+macro_rules! cond {
+ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
+ if $cond {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((i, o)) =>
+ ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
+ ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
+ }
+ } else {
+ ::std::result::Result::Ok(($i, ::std::option::Option::None))
+ }
+ };
+
+ ($i:expr, $cond:expr, $f:expr) => {
+ cond!($i, $cond, call!($f))
+ };
+}
+
+/// Fail to parse if condition is false, otherwise parse the given parser.
+///
+/// This is typically used inside of `option!` or `alt!`.
+///
+/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
+/// - **Output:** `THING`
+#[macro_export]
+macro_rules! cond_reduce {
+ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
+ if $cond {
+ $submac!($i, $($args)*)
+ } else {
+ $crate::parse_error()
+ }
+ };
+
+ ($i:expr, $cond:expr, $f:expr) => {
+ cond_reduce!($i, $cond, call!($f))
+ };
+}
+
+/// Parse two things, returning the value of the first.
+///
+/// - **Syntax:** `terminated!(THING, AFTER)`
+/// - **Output:** `THING`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+///
+/// // An expression terminated by ##.
+/// named!(expr_pound_pound -> Expr,
+/// terminated!(syn!(Expr), tuple!(punct!(#), punct!(#)))
+/// );
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! terminated {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
+ match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
+ ::std::result::Result::Ok((i, (o, _))) =>
+ ::std::result::Result::Ok((i, o)),
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ }
+ };
+
+ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
+ terminated!($i, $submac!($($args)*), call!($g))
+ };
+
+ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
+ terminated!($i, call!($f), $submac!($($args)*))
+ };
+
+ ($i:expr, $f:expr, $g:expr) => {
+ terminated!($i, call!($f), call!($g))
+ };
+}
+
+/// Parse zero or more values using the given parser.
+///
+/// - **Syntax:** `many0!(THING)`
+/// - **Output:** `Vec<THING>`
+///
+/// You may also be looking for:
+///
+/// - `call!(Delimited::parse_separated)` - zero or more values with separator
+/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
+/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Item;
+///
+/// named!(items -> Vec<Item>, many0!(syn!(Item)));
+///
+/// # fn main() {}
+#[macro_export]
+macro_rules! many0 {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {{
+ let ret;
+ let mut res = ::std::vec::Vec::new();
+ let mut input = $i;
+
+ loop {
+ if input.eof() {
+ ret = ::std::result::Result::Ok((input, res));
+ break;
+ }
+
+ match $submac!(input, $($args)*) {
+ ::std::result::Result::Err(_) => {
+ ret = ::std::result::Result::Ok((input, res));
+ break;
+ }
+ ::std::result::Result::Ok((i, o)) => {
+ // loop trip must always consume (otherwise infinite loops)
+ if i == input {
+ ret = $crate::parse_error();
+ break;
+ }
+
+ res.push(o);
+ input = i;
+ }
+ }
+ }
+
+ ret
+ }};
+
+ ($i:expr, $f:expr) => {
+ $crate::parsers::many0($i, $f)
+ };
+}
+
+// Improve compile time by compiling this loop only once per type it is used
+// with.
+//
+// Not public API.
+#[doc(hidden)]
+pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
+ let mut res = Vec::new();
+
+ loop {
+ if input.eof() {
+ return Ok((input, res));
+ }
+
+ match f(input) {
+ Err(_) => {
+ return Ok((input, res));
+ }
+ Ok((i, o)) => {
+ // loop trip must always consume (otherwise infinite loops)
+ if i == input {
+ return parse_error();
+ }
+
+ res.push(o);
+ input = i;
+ }
+ }
+ }
+}
+
+/// Parse a value without consuming it from the input data.
+///
+/// - **Syntax:** `peek!(THING)`
+/// - **Output:** `THING`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Expr, Ident};
+///
+/// // Parse an expression that begins with an identifier.
+/// named!(ident_expr -> (Ident, Expr),
+/// tuple!(peek!(syn!(Ident)), syn!(Expr))
+/// );
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! peek {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
+ ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
+ }
+ };
+
+ ($i:expr, $f:expr) => {
+ peek!($i, call!($f))
+ };
+}
+
+/// Pattern-match the result of a parser to select which other parser to run.
+///
+/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
+/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Ident, Type};
+///
+/// #[derive(Debug)]
+/// enum UnitType {
+/// Struct {
+/// name: Ident,
+/// },
+/// Enum {
+/// name: Ident,
+/// variant: Ident,
+/// },
+/// }
+///
+/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
+/// named!(unit_type -> UnitType, do_parse!(
+/// which: alt!(
+/// keyword!(struct) => { |_| 0 }
+/// |
+/// keyword!(enum) => { |_| 1 }
+/// ) >>
+/// id: syn!(Ident) >>
+/// item: switch!(value!(which),
+/// 0 => map!(
+/// punct!(;),
+/// move |_| UnitType::Struct {
+/// name: id,
+/// }
+/// )
+/// |
+/// 1 => map!(
+/// braces!(syn!(Ident)),
+/// move |(variant, _)| UnitType::Enum {
+/// name: id,
+/// variant: variant,
+/// }
+/// )
+/// |
+/// _ => reject!()
+/// ) >>
+/// (item)
+/// ));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! switch {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, o)) => match o {
+ $(
+ $p => $subrule!(i, $($args2)*),
+ )*
+ }
+ }
+ };
+}
+
+
+/// Produce the given value without parsing anything. Useful as an argument to
+/// `switch!`.
+///
+/// - **Syntax:** `value!(VALUE)`
+/// - **Output:** `VALUE`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Ident;
+///
+/// #[derive(Debug)]
+/// enum UnitType {
+/// Struct {
+/// name: Ident,
+/// },
+/// Enum {
+/// name: Ident,
+/// variant: Ident,
+/// },
+/// }
+///
+/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
+/// named!(unit_type -> UnitType, do_parse!(
+/// is_struct: alt!(
+/// keyword!(struct) => { |_| true }
+/// |
+/// keyword!(enum) => { |_| false }
+/// ) >>
+/// id: syn!(Ident) >>
+/// item: switch!(value!(is_struct),
+/// true => map!(
+/// punct!(;),
+/// move |_| UnitType::Struct {
+/// name: id,
+/// }
+/// )
+/// |
+/// false => map!(
+/// braces!(syn!(Ident)),
+/// move |(variant, _)| UnitType::Enum {
+/// name: id,
+/// variant: variant,
+/// }
+/// )
+/// ) >>
+/// (item)
+/// ));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! value {
+ ($i:expr, $res:expr) => {
+ ::std::result::Result::Ok(($i, $res))
+ };
+}
+
+/// Unconditionally fail to parse anything. This may be useful in ignoring some
+/// arms of a `switch!` parser.
+///
+/// - **Syntax:** `reject!()`
+/// - **Output:** never succeeds
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Item;
+///
+/// // Parse any item, except for a module.
+/// named!(almost_any_item -> Item,
+/// switch!(syn!(Item),
+/// Item::Mod(_) => reject!()
+/// |
+/// ok => value!(ok)
+/// )
+/// );
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! reject {
+ ($i:expr,) => {{
+ let _ = $i;
+ $crate::parse_error()
+ }}
+}
+
+/// Run a series of parsers and produce all of the results in a tuple.
+///
+/// - **Syntax:** `tuple!(A, B, C, ...)`
+/// - **Output:** `(A, B, C, ...)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+///
+/// named!(two_types -> (Type, Type), tuple!(syn!(Type), syn!(Type)));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! tuple {
+ ($i:expr, $($rest:tt)*) => {
+ tuple_parser!($i, (), $($rest)*)
+ };
+}
+
+/// Internal parser, do not use directly.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! tuple_parser {
+ ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
+ tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
+ };
+
+ ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, o)) =>
+ tuple_parser!(i, (o), $($rest)*),
+ }
+ };
+
+ ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, o)) =>
+ tuple_parser!(i, ($($parsed)* , o), $($rest)*),
+ }
+ };
+
+ ($i:expr, ($($parsed:tt),*), $e:ident) => {
+ tuple_parser!($i, ($($parsed),*), call!($e))
+ };
+
+ ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
+ $submac!($i, $($args)*)
+ };
+
+ ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, o)) =>
+ ::std::result::Result::Ok((i, ($($parsed),*, o))),
+ }
+ };
+
+ ($i:expr, ($($parsed:expr),*)) => {
+ ::std::result::Result::Ok(($i, ($($parsed),*)))
+ };
+}
+
+/// Run a series of parsers, returning the result of the first one which
+/// succeeds.
+///
+/// Optionally allows for the result to be transformed.
+///
+/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
+/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Ident;
+///
+/// named!(ident_or_bang -> Ident,
+/// alt!(
+/// syn!(Ident)
+/// |
+/// punct!(!) => { |_| "BANG".into() }
+/// )
+/// );
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! alt {
+ ($i:expr, $e:ident | $($rest:tt)*) => {
+ alt!($i, call!($e) | $($rest)*)
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
+ match $subrule!($i, $($args)*) {
+ res @ ::std::result::Result::Ok(_) => res,
+ _ => alt!($i, $($rest)*)
+ }
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
+ match $subrule!($i, $($args)*) {
+ ::std::result::Result::Ok((i, o)) =>
+ ::std::result::Result::Ok((i, $crate::parsers::invoke($gen, o))),
+ ::std::result::Result::Err(_) => alt!($i, $($rest)*),
+ }
+ };
+
+ ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
+ alt!($i, call!($e) => { $gen } | $($rest)*)
+ };
+
+ ($i:expr, $e:ident => { $gen:expr }) => {
+ alt!($i, call!($e) => { $gen })
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
+ match $subrule!($i, $($args)*) {
+ ::std::result::Result::Ok((i, o)) =>
+ ::std::result::Result::Ok((i, $crate::parsers::invoke($gen, o))),
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ }
+ };
+
+ ($i:expr, $e:ident) => {
+ alt!($i, call!($e))
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)*)) => {
+ $subrule!($i, $($args)*)
+ };
+}
+
+/// Run a series of parsers, one after another, optionally assigning the results
+/// a name. Fail if any of the parsers fails.
+///
+/// Produces the result of evaluating the final expression in parentheses with
+/// all of the previously named results bound.
+///
+/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
+/// - **Output:** `RESULT`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+/// extern crate proc_macro2;
+///
+/// use syn::{Ident, TokenTree};
+/// use syn::tokens::Paren;
+/// use proc_macro2::TokenStream;
+///
+/// // Parse a macro invocation like `stringify!($args)`.
+/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
+/// name: syn!(Ident) >>
+/// punct!(!) >>
+/// body: parens!(syn!(TokenStream)) >>
+/// (name, body)
+/// ));
+///
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! do_parse {
+ ($i:expr, ( $($rest:expr),* )) => {
+ ::std::result::Result::Ok(($i, ( $($rest),* )))
+ };
+
+ ($i:expr, $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, _)) =>
+ do_parse!(i, $($rest)*),
+ }
+ };
+
+ ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, $field: call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, o)) => {
+ let $field = o;
+ do_parse!(i, $($rest)*)
+ },
+ }
+ };
+
+ ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, mut $field: call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((i, o)) => {
+ let mut $field = o;
+ do_parse!(i, $($rest)*)
+ },
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! input_end {
+ ($i:expr,) => {
+ $crate::parsers::input_end($i)
+ };
+}
+
+// Not a public API
+#[doc(hidden)]
+pub fn input_end(input: Cursor) -> PResult<'static, ()> {
+ if input.eof() {
+ Ok((Cursor::empty(), ()))
+ } else {
+ parse_error()
+ }
+}
diff --git a/src/span.rs b/src/span.rs
new file mode 100644
index 0000000..f78cff7
--- /dev/null
+++ b/src/span.rs
@@ -0,0 +1,26 @@
+use std::hash::{Hash, Hasher};
+use std::fmt::{self, Debug};
+
+use proc_macro2;
+
+#[derive(Clone, Copy, Default)]
+pub struct Span(pub proc_macro2::Span);
+
+impl Debug for Span {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl PartialEq for Span {
+ fn eq(&self, _other: &Span) -> bool {
+ true
+ }
+}
+
+impl Eq for Span {}
+
+impl Hash for Span {
+ fn hash<H: Hasher>(&self, _hasher: &mut H) {
+ }
+}
diff --git a/src/synom.rs b/src/synom.rs
new file mode 100644
index 0000000..77bd295
--- /dev/null
+++ b/src/synom.rs
@@ -0,0 +1,42 @@
+//! Adapted from [`nom`](https://github.com/Geal/nom) by removing the
+//! `IPResult::Incomplete` variant which:
+//!
+//! - we don't need,
+//! - is an unintuitive footgun when working with non-streaming use cases, and
+//! - more than doubles compilation time.
+//!
+//! ## Whitespace handling strategy
+//!
+//! As (sy)nom is a parser combinator library, the parsers provided here and
+//! that you implement yourself are all made up of successively more primitive
+//! parsers, eventually culminating in a small number of fundamental parsers
+//! that are implemented in Rust. Among these are `punct!` and `keyword!`.
+//!
+//! All synom fundamental parsers (those not combined out of other parsers)
+//! should be written to skip over leading whitespace in their input. This way,
+//! as long as every parser eventually boils down to some combination of
+//! fundamental parsers, we get correct whitespace handling at all levels for
+//! free.
+//!
+//! For our use case, this strategy is a huge improvement in usability,
+//! correctness, and compile time over nom's `ws!` strategy.
+
+use proc_macro2::TokenStream;
+
+pub use cursor::*;
+
+use PResult;
+
+pub trait Synom: Sized {
+ fn parse(input: Cursor) -> PResult<Self>;
+
+ fn description() -> Option<&'static str> {
+ None
+ }
+}
+
+impl Synom for TokenStream {
+ fn parse(input: Cursor) -> PResult<Self> {
+ Ok((Cursor::empty(), input.token_stream()))
+ }
+}
diff --git a/src/tokens.rs b/src/tokens.rs
new file mode 100644
index 0000000..a40bd60
--- /dev/null
+++ b/src/tokens.rs
@@ -0,0 +1,539 @@
+//! Discrete tokens that can be parsed out by synom.
+//!
+//! This module contains a number of useful tokens like `+=` and `/` along with
+//! keywords like `crate` and such. These structures are used to track the spans
+//! of these tokens and all implment the `ToTokens` and `Synom` traits when the
+//! corresponding feature is activated.
+
+use Span;
+
+macro_rules! tokens {
+ (
+ ops: {
+ $(($($op:tt)*),)*
+ }
+ delim: {
+ $(($($delim:tt)*),)*
+ }
+ syms: {
+ $(($($sym:tt)*),)*
+ }
+ ) => (
+ $(op! { $($op)* })*
+ $(delim! { $($delim)* })*
+ $(sym! { $($sym)* })*
+ )
+}
+
+macro_rules! op {
+ (pub struct $name:ident($($contents:tt)*) => $s:expr) => {
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[cfg_attr(feature = "extra-traits", derive(Eq, PartialEq, Hash))]
+ #[derive(Default)]
+ pub struct $name(pub $($contents)*);
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::fmt::Debug for $name {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ let mut t = f.debug_tuple(stringify!($name));
+ for span in &self.0 {
+ t.field(span);
+ }
+ t.finish()
+ }
+ }
+
+ #[cfg(feature = "printing")]
+ impl ::quote::ToTokens for $name {
+ fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
+ printing::op($s, &self.0, tokens);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl ::Synom for $name {
+ fn parse(tokens: $crate::synom::Cursor) -> $crate::PResult<$name> {
+ parsing::op($s, tokens, $name)
+ }
+ }
+ }
+}
+
+macro_rules! sym {
+ (pub struct $name:ident => $s:expr) => {
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[derive(Default)]
+ pub struct $name(pub Span);
+
+ #[cfg(feature = "printing")]
+ impl ::quote::ToTokens for $name {
+ fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
+ printing::sym($s, &self.0, tokens);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl ::Synom for $name {
+ fn parse(tokens: $crate::synom::Cursor) -> $crate::PResult<$name> {
+ parsing::sym($s, tokens, $name)
+ }
+ }
+ }
+}
+
+macro_rules! delim {
+ (pub struct $name:ident => $s:expr) => {
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[derive(Default)]
+ pub struct $name(pub Span);
+
+ impl $name {
+ #[cfg(feature = "printing")]
+ pub fn surround<F>(&self,
+ tokens: &mut ::quote::Tokens,
+ f: F)
+ where F: FnOnce(&mut ::quote::Tokens)
+ {
+ printing::delim($s, &self.0, tokens, f);
+ }
+
+ #[cfg(feature = "parsing")]
+ pub fn parse<F, R>(tokens: $crate::synom::Cursor, f: F) -> $crate::PResult<(R, $name)>
+ where F: FnOnce($crate::synom::Cursor) -> $crate::PResult<R>
+ {
+ parsing::delim($s, tokens, $name, f)
+ }
+ }
+ }
+}
+
+tokens! {
+ ops: {
+ (pub struct Add([Span; 1]) => "+"),
+ (pub struct AddEq([Span; 2]) => "+="),
+ (pub struct And([Span; 1]) => "&"),
+ (pub struct AndAnd([Span; 2]) => "&&"),
+ (pub struct AndEq([Span; 2]) => "&="),
+ (pub struct At([Span; 1]) => "@"),
+ (pub struct Bang([Span; 1]) => "!"),
+ (pub struct Caret([Span; 1]) => "^"),
+ (pub struct CaretEq([Span; 2]) => "^="),
+ (pub struct Colon([Span; 1]) => ":"),
+ (pub struct Colon2([Span; 2]) => "::"),
+ (pub struct Comma([Span; 1]) => ","),
+ (pub struct Div([Span; 1]) => "/"),
+ (pub struct DivEq([Span; 2]) => "/="),
+ (pub struct Dot([Span; 1]) => "."),
+ (pub struct Dot2([Span; 2]) => ".."),
+ (pub struct Dot3([Span; 3]) => "..."),
+ (pub struct DotDotEq([Span; 3]) => "..="),
+ (pub struct Eq([Span; 1]) => "="),
+ (pub struct EqEq([Span; 2]) => "=="),
+ (pub struct Ge([Span; 2]) => ">="),
+ (pub struct Gt([Span; 1]) => ">"),
+ (pub struct Le([Span; 2]) => "<="),
+ (pub struct Lt([Span; 1]) => "<"),
+ (pub struct MulEq([Span; 2]) => "*="),
+ (pub struct Ne([Span; 2]) => "!="),
+ (pub struct Or([Span; 1]) => "|"),
+ (pub struct OrEq([Span; 2]) => "|="),
+ (pub struct OrOr([Span; 2]) => "||"),
+ (pub struct Pound([Span; 1]) => "#"),
+ (pub struct Question([Span; 1]) => "?"),
+ (pub struct RArrow([Span; 2]) => "->"),
+ (pub struct LArrow([Span; 2]) => "<-"),
+ (pub struct Rem([Span; 1]) => "%"),
+ (pub struct RemEq([Span; 2]) => "%="),
+ (pub struct Rocket([Span; 2]) => "=>"),
+ (pub struct Semi([Span; 1]) => ";"),
+ (pub struct Shl([Span; 2]) => "<<"),
+ (pub struct ShlEq([Span; 3]) => "<<="),
+ (pub struct Shr([Span; 2]) => ">>"),
+ (pub struct ShrEq([Span; 3]) => ">>="),
+ (pub struct Star([Span; 1]) => "*"),
+ (pub struct Sub([Span; 1]) => "-"),
+ (pub struct SubEq([Span; 2]) => "-="),
+ (pub struct Underscore([Span; 1]) => "_"),
+ }
+ delim: {
+ (pub struct Brace => "{"),
+ (pub struct Bracket => "["),
+ (pub struct Paren => "("),
+ (pub struct Group => " "),
+ }
+ syms: {
+ (pub struct As => "as"),
+ (pub struct Auto => "auto"),
+ (pub struct Box => "box"),
+ (pub struct Break => "break"),
+ (pub struct CapSelf => "Self"),
+ (pub struct Catch => "catch"),
+ (pub struct Const => "const"),
+ (pub struct Continue => "continue"),
+ (pub struct Crate => "crate"),
+ (pub struct Default => "default"),
+ (pub struct Do => "do"),
+ (pub struct Dyn => "dyn"),
+ (pub struct Else => "else"),
+ (pub struct Enum => "enum"),
+ (pub struct Extern => "extern"),
+ (pub struct Fn => "fn"),
+ (pub struct For => "for"),
+ (pub struct If => "if"),
+ (pub struct Impl => "impl"),
+ (pub struct In => "in"),
+ (pub struct Let => "let"),
+ (pub struct Loop => "loop"),
+ (pub struct Macro => "macro"),
+ (pub struct Match => "match"),
+ (pub struct Mod => "mod"),
+ (pub struct Move => "move"),
+ (pub struct Mut => "mut"),
+ (pub struct Pub => "pub"),
+ (pub struct Ref => "ref"),
+ (pub struct Return => "return"),
+ (pub struct Self_ => "self"),
+ (pub struct Static => "static"),
+ (pub struct Struct => "struct"),
+ (pub struct Super => "super"),
+ (pub struct Trait => "trait"),
+ (pub struct Type => "type"),
+ (pub struct Union => "union"),
+ (pub struct Unsafe => "unsafe"),
+ (pub struct Use => "use"),
+ (pub struct Where => "where"),
+ (pub struct While => "while"),
+ (pub struct Yield => "yield"),
+ }
+}
+
+// Unfortunate duplication due to a rustdoc bug.
+// https://github.com/rust-lang/rust/issues/45939
+#[macro_export]
+macro_rules! Token {
+ (+) => { $crate::tokens::Add };
+ (+=) => { $crate::tokens::AddEq };
+ (&) => { $crate::tokens::And };
+ (&&) => { $crate::tokens::AndAnd };
+ (&=) => { $crate::tokens::AndEq };
+ (@) => { $crate::tokens::At };
+ (!) => { $crate::tokens::Bang };
+ (^) => { $crate::tokens::Caret };
+ (^=) => { $crate::tokens::CaretEq };
+ (:) => { $crate::tokens::Colon };
+ (::) => { $crate::tokens::Colon2 };
+ (,) => { $crate::tokens::Comma };
+ (/) => { $crate::tokens::Div };
+ (/=) => { $crate::tokens::DivEq };
+ (.) => { $crate::tokens::Dot };
+ (..) => { $crate::tokens::Dot2 };
+ (...) => { $crate::tokens::Dot3 };
+ (..=) => { $crate::tokens::DotDotEq };
+ (=) => { $crate::tokens::Eq };
+ (==) => { $crate::tokens::EqEq };
+ (>=) => { $crate::tokens::Ge };
+ (>) => { $crate::tokens::Gt };
+ (<=) => { $crate::tokens::Le };
+ (<) => { $crate::tokens::Lt };
+ (*=) => { $crate::tokens::MulEq };
+ (!=) => { $crate::tokens::Ne };
+ (|) => { $crate::tokens::Or };
+ (|=) => { $crate::tokens::OrEq };
+ (||) => { $crate::tokens::OrOr };
+ (#) => { $crate::tokens::Pound };
+ (?) => { $crate::tokens::Question };
+ (->) => { $crate::tokens::RArrow };
+ (<-) => { $crate::tokens::LArrow };
+ (%) => { $crate::tokens::Rem };
+ (%=) => { $crate::tokens::RemEq };
+ (=>) => { $crate::tokens::Rocket };
+ (;) => { $crate::tokens::Semi };
+ (<<) => { $crate::tokens::Shl };
+ (<<=) => { $crate::tokens::ShlEq };
+ (>>) => { $crate::tokens::Shr };
+ (>>=) => { $crate::tokens::ShrEq };
+ (*) => { $crate::tokens::Star };
+ (-) => { $crate::tokens::Sub };
+ (-=) => { $crate::tokens::SubEq };
+ (_) => { $crate::tokens::Underscore };
+ (as) => { $crate::tokens::As };
+ (auto) => { $crate::tokens::Auto };
+ (box) => { $crate::tokens::Box };
+ (break) => { $crate::tokens::Break };
+ (Self) => { $crate::tokens::CapSelf };
+ (catch) => { $crate::tokens::Catch };
+ (const) => { $crate::tokens::Const };
+ (continue) => { $crate::tokens::Continue };
+ (crate) => { $crate::tokens::Crate };
+ (default) => { $crate::tokens::Default };
+ (do) => { $crate::tokens::Do };
+ (dyn) => { $crate::tokens::Dyn };
+ (else) => { $crate::tokens::Else };
+ (enum) => { $crate::tokens::Enum };
+ (extern) => { $crate::tokens::Extern };
+ (fn) => { $crate::tokens::Fn };
+ (for) => { $crate::tokens::For };
+ (if) => { $crate::tokens::If };
+ (impl) => { $crate::tokens::Impl };
+ (in) => { $crate::tokens::In };
+ (let) => { $crate::tokens::Let };
+ (loop) => { $crate::tokens::Loop };
+ (macro) => { $crate::tokens::Macro };
+ (match) => { $crate::tokens::Match };
+ (mod) => { $crate::tokens::Mod };
+ (move) => { $crate::tokens::Move };
+ (mut) => { $crate::tokens::Mut };
+ (pub) => { $crate::tokens::Pub };
+ (ref) => { $crate::tokens::Ref };
+ (return) => { $crate::tokens::Return };
+ (self) => { $crate::tokens::Self_ };
+ (static) => { $crate::tokens::Static };
+ (struct) => { $crate::tokens::Struct };
+ (super) => { $crate::tokens::Super };
+ (trait) => { $crate::tokens::Trait };
+ (type) => { $crate::tokens::Type };
+ (union) => { $crate::tokens::Union };
+ (unsafe) => { $crate::tokens::Unsafe };
+ (use) => { $crate::tokens::Use };
+ (where) => { $crate::tokens::Where };
+ (while) => { $crate::tokens::While };
+ (yield) => { $crate::tokens::Yield };
+}
+
+#[macro_export]
+macro_rules! punct {
+ ($i:expr, +) => { call!($i, <$crate::tokens::Add as $crate::synom::Synom>::parse) };
+ ($i:expr, +=) => { call!($i, <$crate::tokens::AddEq as $crate::synom::Synom>::parse) };
+ ($i:expr, &) => { call!($i, <$crate::tokens::And as $crate::synom::Synom>::parse) };
+ ($i:expr, &&) => { call!($i, <$crate::tokens::AndAnd as $crate::synom::Synom>::parse) };
+ ($i:expr, &=) => { call!($i, <$crate::tokens::AndEq as $crate::synom::Synom>::parse) };
+ ($i:expr, @) => { call!($i, <$crate::tokens::At as $crate::synom::Synom>::parse) };
+ ($i:expr, !) => { call!($i, <$crate::tokens::Bang as $crate::synom::Synom>::parse) };
+ ($i:expr, ^) => { call!($i, <$crate::tokens::Caret as $crate::synom::Synom>::parse) };
+ ($i:expr, ^=) => { call!($i, <$crate::tokens::CaretEq as $crate::synom::Synom>::parse) };
+ ($i:expr, :) => { call!($i, <$crate::tokens::Colon as $crate::synom::Synom>::parse) };
+ ($i:expr, ::) => { call!($i, <$crate::tokens::Colon2 as $crate::synom::Synom>::parse) };
+ ($i:expr, ,) => { call!($i, <$crate::tokens::Comma as $crate::synom::Synom>::parse) };
+ ($i:expr, /) => { call!($i, <$crate::tokens::Div as $crate::synom::Synom>::parse) };
+ ($i:expr, /=) => { call!($i, <$crate::tokens::DivEq as $crate::synom::Synom>::parse) };
+ ($i:expr, .) => { call!($i, <$crate::tokens::Dot as $crate::synom::Synom>::parse) };
+ ($i:expr, ..) => { call!($i, <$crate::tokens::Dot2 as $crate::synom::Synom>::parse) };
+ ($i:expr, ...) => { call!($i, <$crate::tokens::Dot3 as $crate::synom::Synom>::parse) };
+ ($i:expr, ..=) => { call!($i, <$crate::tokens::DotDotEq as $crate::synom::Synom>::parse) };
+ ($i:expr, =) => { call!($i, <$crate::tokens::Eq as $crate::synom::Synom>::parse) };
+ ($i:expr, ==) => { call!($i, <$crate::tokens::EqEq as $crate::synom::Synom>::parse) };
+ ($i:expr, >=) => { call!($i, <$crate::tokens::Ge as $crate::synom::Synom>::parse) };
+ ($i:expr, >) => { call!($i, <$crate::tokens::Gt as $crate::synom::Synom>::parse) };
+ ($i:expr, <=) => { call!($i, <$crate::tokens::Le as $crate::synom::Synom>::parse) };
+ ($i:expr, <) => { call!($i, <$crate::tokens::Lt as $crate::synom::Synom>::parse) };
+ ($i:expr, *=) => { call!($i, <$crate::tokens::MulEq as $crate::synom::Synom>::parse) };
+ ($i:expr, !=) => { call!($i, <$crate::tokens::Ne as $crate::synom::Synom>::parse) };
+ ($i:expr, |) => { call!($i, <$crate::tokens::Or as $crate::synom::Synom>::parse) };
+ ($i:expr, |=) => { call!($i, <$crate::tokens::OrEq as $crate::synom::Synom>::parse) };
+ ($i:expr, ||) => { call!($i, <$crate::tokens::OrOr as $crate::synom::Synom>::parse) };
+ ($i:expr, #) => { call!($i, <$crate::tokens::Pound as $crate::synom::Synom>::parse) };
+ ($i:expr, ?) => { call!($i, <$crate::tokens::Question as $crate::synom::Synom>::parse) };
+ ($i:expr, ->) => { call!($i, <$crate::tokens::RArrow as $crate::synom::Synom>::parse) };
+ ($i:expr, <-) => { call!($i, <$crate::tokens::LArrow as $crate::synom::Synom>::parse) };
+ ($i:expr, %) => { call!($i, <$crate::tokens::Rem as $crate::synom::Synom>::parse) };
+ ($i:expr, %=) => { call!($i, <$crate::tokens::RemEq as $crate::synom::Synom>::parse) };
+ ($i:expr, =>) => { call!($i, <$crate::tokens::Rocket as $crate::synom::Synom>::parse) };
+ ($i:expr, ;) => { call!($i, <$crate::tokens::Semi as $crate::synom::Synom>::parse) };
+ ($i:expr, <<) => { call!($i, <$crate::tokens::Shl as $crate::synom::Synom>::parse) };
+ ($i:expr, <<=) => { call!($i, <$crate::tokens::ShlEq as $crate::synom::Synom>::parse) };
+ ($i:expr, >>) => { call!($i, <$crate::tokens::Shr as $crate::synom::Synom>::parse) };
+ ($i:expr, >>=) => { call!($i, <$crate::tokens::ShrEq as $crate::synom::Synom>::parse) };
+ ($i:expr, *) => { call!($i, <$crate::tokens::Star as $crate::synom::Synom>::parse) };
+ ($i:expr, -) => { call!($i, <$crate::tokens::Sub as $crate::synom::Synom>::parse) };
+ ($i:expr, -=) => { call!($i, <$crate::tokens::SubEq as $crate::synom::Synom>::parse) };
+ ($i:expr, _) => { call!($i, <$crate::tokens::Underscore as $crate::synom::Synom>::parse) };
+}
+
+#[macro_export]
+macro_rules! keyword {
+ ($i:expr, as) => { call!($i, <$crate::tokens::As as $crate::synom::Synom>::parse) };
+ ($i:expr, auto) => { call!($i, <$crate::tokens::Auto as $crate::synom::Synom>::parse) };
+ ($i:expr, box) => { call!($i, <$crate::tokens::Box as $crate::synom::Synom>::parse) };
+ ($i:expr, break) => { call!($i, <$crate::tokens::Break as $crate::synom::Synom>::parse) };
+ ($i:expr, Self) => { call!($i, <$crate::tokens::CapSelf as $crate::synom::Synom>::parse) };
+ ($i:expr, catch) => { call!($i, <$crate::tokens::Catch as $crate::synom::Synom>::parse) };
+ ($i:expr, const) => { call!($i, <$crate::tokens::Const as $crate::synom::Synom>::parse) };
+ ($i:expr, continue) => { call!($i, <$crate::tokens::Continue as $crate::synom::Synom>::parse) };
+ ($i:expr, crate) => { call!($i, <$crate::tokens::Crate as $crate::synom::Synom>::parse) };
+ ($i:expr, default) => { call!($i, <$crate::tokens::Default as $crate::synom::Synom>::parse) };
+ ($i:expr, do) => { call!($i, <$crate::tokens::Do as $crate::synom::Synom>::parse) };
+ ($i:expr, dyn) => { call!($i, <$crate::tokens::Dyn as $crate::synom::Synom>::parse) };
+ ($i:expr, else) => { call!($i, <$crate::tokens::Else as $crate::synom::Synom>::parse) };
+ ($i:expr, enum) => { call!($i, <$crate::tokens::Enum as $crate::synom::Synom>::parse) };
+ ($i:expr, extern) => { call!($i, <$crate::tokens::Extern as $crate::synom::Synom>::parse) };
+ ($i:expr, fn) => { call!($i, <$crate::tokens::Fn as $crate::synom::Synom>::parse) };
+ ($i:expr, for) => { call!($i, <$crate::tokens::For as $crate::synom::Synom>::parse) };
+ ($i:expr, if) => { call!($i, <$crate::tokens::If as $crate::synom::Synom>::parse) };
+ ($i:expr, impl) => { call!($i, <$crate::tokens::Impl as $crate::synom::Synom>::parse) };
+ ($i:expr, in) => { call!($i, <$crate::tokens::In as $crate::synom::Synom>::parse) };
+ ($i:expr, let) => { call!($i, <$crate::tokens::Let as $crate::synom::Synom>::parse) };
+ ($i:expr, loop) => { call!($i, <$crate::tokens::Loop as $crate::synom::Synom>::parse) };
+ ($i:expr, macro) => { call!($i, <$crate::tokens::Macro as $crate::synom::Synom>::parse) };
+ ($i:expr, match) => { call!($i, <$crate::tokens::Match as $crate::synom::Synom>::parse) };
+ ($i:expr, mod) => { call!($i, <$crate::tokens::Mod as $crate::synom::Synom>::parse) };
+ ($i:expr, move) => { call!($i, <$crate::tokens::Move as $crate::synom::Synom>::parse) };
+ ($i:expr, mut) => { call!($i, <$crate::tokens::Mut as $crate::synom::Synom>::parse) };
+ ($i:expr, pub) => { call!($i, <$crate::tokens::Pub as $crate::synom::Synom>::parse) };
+ ($i:expr, ref) => { call!($i, <$crate::tokens::Ref as $crate::synom::Synom>::parse) };
+ ($i:expr, return) => { call!($i, <$crate::tokens::Return as $crate::synom::Synom>::parse) };
+ ($i:expr, self) => { call!($i, <$crate::tokens::Self_ as $crate::synom::Synom>::parse) };
+ ($i:expr, static) => { call!($i, <$crate::tokens::Static as $crate::synom::Synom>::parse) };
+ ($i:expr, struct) => { call!($i, <$crate::tokens::Struct as $crate::synom::Synom>::parse) };
+ ($i:expr, super) => { call!($i, <$crate::tokens::Super as $crate::synom::Synom>::parse) };
+ ($i:expr, trait) => { call!($i, <$crate::tokens::Trait as $crate::synom::Synom>::parse) };
+ ($i:expr, type) => { call!($i, <$crate::tokens::Type as $crate::synom::Synom>::parse) };
+ ($i:expr, union) => { call!($i, <$crate::tokens::Union as $crate::synom::Synom>::parse) };
+ ($i:expr, unsafe) => { call!($i, <$crate::tokens::Unsafe as $crate::synom::Synom>::parse) };
+ ($i:expr, use) => { call!($i, <$crate::tokens::Use as $crate::synom::Synom>::parse) };
+ ($i:expr, where) => { call!($i, <$crate::tokens::Where as $crate::synom::Synom>::parse) };
+ ($i:expr, while) => { call!($i, <$crate::tokens::While as $crate::synom::Synom>::parse) };
+ ($i:expr, yield) => { call!($i, <$crate::tokens::Yield as $crate::synom::Synom>::parse) };
+}
+
+#[cfg(feature = "parsing")]
+mod parsing {
+ use proc_macro2::{Delimiter, Spacing};
+
+ use cursor::Cursor;
+ use {PResult, Span, parse_error};
+
+ pub trait FromSpans: Sized {
+ fn from_spans(spans: &[Span]) -> Self;
+ }
+
+ impl FromSpans for [Span; 1] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0]]
+ }
+ }
+
+ impl FromSpans for [Span; 2] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0], spans[1]]
+ }
+ }
+
+ impl FromSpans for [Span; 3] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0], spans[1], spans[2]]
+ }
+ }
+
+ pub fn op<'a, T, R>(s: &str,
+ mut tokens: Cursor<'a>,
+ new: fn(T) -> R)
+ -> PResult<'a, R>
+ where T: FromSpans,
+ {
+ let mut spans = [Span::default(); 3];
+ assert!(s.len() <= spans.len());
+ let chars = s.chars();
+
+ for (i, (ch, slot)) in chars.zip(&mut spans).enumerate() {
+ match tokens.op() {
+ Some((rest, span, c, kind)) if c == ch => {
+ if i != s.len() - 1 {
+ match kind {
+ Spacing::Joint => {}
+ _ => return parse_error(),
+ }
+ }
+ *slot = Span(span);
+ tokens = rest;
+ }
+ _ => return parse_error()
+ }
+ }
+ Ok((tokens, new(T::from_spans(&spans))))
+ }
+
+ pub fn sym<'a, T>(sym: &str,
+ tokens: Cursor<'a>,
+ new: fn(Span) -> T)
+ -> PResult<'a, T>
+ {
+ if let Some((rest, span, s)) = tokens.word() {
+ if s.as_str() == sym {
+ return Ok((rest, new(Span(span))));
+ }
+ }
+ parse_error()
+ }
+
+ pub fn delim<'a, F, R, T>(delim: &str,
+ tokens: Cursor<'a>,
+ new: fn(Span) -> T,
+ f: F)
+ -> PResult<'a, (R, T)>
+ where F: FnOnce(Cursor) -> PResult<R>
+ {
+ // NOTE: We should support none-delimited sequences here.
+ let delim = match delim {
+ "(" => Delimiter::Parenthesis,
+ "{" => Delimiter::Brace,
+ "[" => Delimiter::Bracket,
+ " " => Delimiter::None,
+ _ => panic!("unknown delimiter: {}", delim),
+ };
+
+ if let Some(seqinfo) = tokens.seq(delim) {
+ match f(seqinfo.inside) {
+ Ok((remaining, ret)) => {
+ if remaining.eof() {
+ return Ok((seqinfo.outside, (ret, new(Span(seqinfo.span)))));
+ }
+ }
+ Err(err) => return Err(err),
+ }
+ }
+ parse_error()
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use proc_macro2::{TokenTree, TokenNode, Spacing, Term};
+ use quote::Tokens;
+
+ use Span;
+
+ pub fn op(s: &str, spans: &[Span], tokens: &mut Tokens) {
+ assert_eq!(s.len(), spans.len());
+
+ let mut chars = s.chars();
+ let mut spans = spans.iter();
+ let ch = chars.next_back().unwrap();
+ let span = spans.next_back().unwrap();
+ for (ch, span) in chars.zip(spans) {
+ tokens.append(TokenTree {
+ span: span.0,
+ kind: TokenNode::Op(ch, Spacing::Joint),
+ });
+ }
+
+ tokens.append(TokenTree {
+ span: span.0,
+ kind: TokenNode::Op(ch, Spacing::Alone),
+ });
+ }
+
+ pub fn sym(s: &str, span: &Span, tokens: &mut Tokens) {
+ tokens.append(TokenTree {
+ span: span.0,
+ kind: TokenNode::Term(Term::intern(s)),
+ });
+ }
+
+ pub fn delim<F>(s: &str, span: &Span, tokens: &mut Tokens, f: F)
+ where F: FnOnce(&mut Tokens)
+ {
+ tokens.append_delimited(s, span.0, f)
+ }
+}