Calls the given parser function to parse a syntax tree node of type T
from this stream.
The parser below invokes Attribute::parse_outer
to parse a vector of
zero or more outer attributes.
#[macro_use]
extern crate syn;
use syn::{Attribute, Ident, Result};
use syn::parse::{Parse, ParseStream};
struct UnitStruct {
attrs: Vec<Attribute>,
struct_token: Token![struct],
name: Ident,
semi_token: Token![;],
}
impl Parse for UnitStruct {
fn parse(input: ParseStream) -> Result<Self> {
Ok(UnitStruct {
attrs: input.call(Attribute::parse_outer)?,
struct_token: input.parse()?,
name: input.parse()?,
semi_token: input.parse()?,
})
}
}
Looks at the next token in the parse stream to determine whether it
matches the requested type of token.
Does not advance the position of the parse stream.
Note that this method does not use turbofish syntax. Pass the peek type
inside of parentheses.
input.peek(Token![struct])
input.peek(Token![==])
input.peek(Ident)
input.peek(Lifetime)
input.peek(token::Brace)
In this example we finish parsing the list of supertraits when the next
token in the input is either where
or an opening curly brace.
#[macro_use]
extern crate syn;
use syn::{token, Generics, Ident, Result, TypeParamBound};
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
struct MarkerTrait {
trait_token: Token![trait],
ident: Ident,
generics: Generics,
colon_token: Option<Token![:]>,
supertraits: Punctuated<TypeParamBound, Token![+]>,
brace_token: token::Brace,
}
impl Parse for MarkerTrait {
fn parse(input: ParseStream) -> Result<Self> {
let trait_token: Token![trait] = input.parse()?;
let ident: Ident = input.parse()?;
let mut generics: Generics = input.parse()?;
let colon_token: Option<Token![:]> = input.parse()?;
let mut supertraits = Punctuated::new();
if colon_token.is_some() {
loop {
supertraits.push_value(input.parse()?);
if input.peek(Token![where]) || input.peek(token::Brace) {
break;
}
supertraits.push_punct(input.parse()?);
}
}
generics.where_clause = input.parse()?;
let content;
let empty_brace_token = braced!(content in input);
Ok(MarkerTrait {
trait_token: trait_token,
ident: ident,
generics: generics,
colon_token: colon_token,
supertraits: supertraits,
brace_token: empty_brace_token,
})
}
}
Looks at the second-next token in the parse stream.
This is commonly useful as a way to implement contextual keywords.
This example needs to use peek2
because the symbol union
is not a
keyword in Rust. We can't use just peek
and decide to parse a union if
the very next token is union
, because someone is free to write a mod union
and a macro invocation that looks like union::some_macro! { ... }
. In other words union
is a contextual keyword.
#[macro_use]
extern crate syn;
use syn::{Ident, ItemUnion, Macro, Result};
use syn::parse::{Parse, ParseStream};
enum UnionOrMacro {
Union(ItemUnion),
Macro(Macro),
}
impl Parse for UnionOrMacro {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Token![union]) && input.peek2(Ident) {
input.parse().map(UnionOrMacro::Union)
} else {
input.parse().map(UnionOrMacro::Macro)
}
}
}
Parses zero or more occurrences of T
separated by punctuation of type
P
, with optional trailing punctuation.
Parsing continues until the end of this parse stream. The entire content
of this parse stream must consist of T
and P
.
#[macro_use]
extern crate syn;
use syn::{token, Ident, Result, Type};
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
struct TupleStruct {
struct_token: Token![struct],
ident: Ident,
paren_token: token::Paren,
fields: Punctuated<Type, Token![,]>,
semi_token: Token![;],
}
impl Parse for TupleStruct {
fn parse(input: ParseStream) -> Result<Self> {
let content;
Ok(TupleStruct {
struct_token: input.parse()?,
ident: input.parse()?,
paren_token: parenthesized!(content in input),
fields: content.parse_terminated(Type::parse)?,
semi_token: input.parse()?,
})
}
}
Returns whether there are tokens remaining in this stream.
This method returns true at the end of the content of a set of
delimiters, as well as at the very end of the complete macro input.
#[macro_use]
extern crate syn;
use syn::{token, Ident, Item, Result};
use syn::parse::{Parse, ParseStream};
struct Mod {
mod_token: Token![mod],
name: Ident,
brace_token: token::Brace,
items: Vec<Item>,
}
impl Parse for Mod {
fn parse(input: ParseStream) -> Result<Self> {
let content;
Ok(Mod {
mod_token: input.parse()?,
name: input.parse()?,
brace_token: braced!(content in input),
items: {
let mut items = Vec::new();
while !content.is_empty() {
items.push(content.parse()?);
}
items
},
})
}
}
Constructs a helper for peeking at the next token in this stream and
building an error message if it is not one of a set of expected tokens.
#[macro_use]
extern crate syn;
use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, TypeParam};
use syn::parse::{Parse, ParseStream};
enum GenericParam {
Type(TypeParam),
Lifetime(LifetimeDef),
Const(ConstParam),
}
impl Parse for GenericParam {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Ident) {
input.parse().map(GenericParam::Type)
} else if lookahead.peek(Lifetime) {
input.parse().map(GenericParam::Lifetime)
} else if lookahead.peek(Token![const]) {
input.parse().map(GenericParam::Const)
} else {
Err(lookahead.error())
}
}
}
Forks a parse stream so that parsing tokens out of either the original
or the fork does not advance the position of the other.
Forking a parse stream is a cheap fixed amount of work and does not
involve copying token buffers. Where you might hit performance problems
is if your macro ends up parsing a large amount of content more than
once.
if input.fork().parse::<Expr>().is_ok() {
return input.parse::<Expr>();
}
As a rule, avoid parsing an unbounded amount of tokens out of a forked
parse stream. Only use a fork when the amount of work performed against
the fork is small and bounded.
For a lower level but occasionally more performant way to perform
speculative parsing, consider using ParseStream::step
instead.
The parse implementation shown here parses possibly restricted pub
visibilities.
pub
pub(crate)
pub(self)
pub(super)
pub(in some::path)
To handle the case of visibilities inside of tuple structs, the parser
needs to distinguish parentheses that specify visibility restrictions
from parentheses that form part of a tuple type.
struct S(pub(crate) A, pub (B, C));
In this example input the first tuple struct element of S
has
pub(crate)
visibility while the second tuple struct element has pub
visibility; the parentheses around (B, C)
are part of the type rather
than part of a visibility restriction.
The parser uses a forked parse stream to check the first token inside of
parentheses after the pub
keyword. This is a small bounded amount of
work performed against the forked parse stream.
#[macro_use]
extern crate syn;
use syn::{token, Ident, Path, Result};
use syn::ext::IdentExt;
use syn::parse::{Parse, ParseStream};
struct PubVisibility {
pub_token: Token![pub],
restricted: Option<Restricted>,
}
struct Restricted {
paren_token: token::Paren,
in_token: Option<Token![in]>,
path: Path,
}
impl Parse for PubVisibility {
fn parse(input: ParseStream) -> Result<Self> {
let pub_token: Token![pub] = input.parse()?;
if input.peek(token::Paren) {
let ahead = input.fork();
let mut content;
parenthesized!(content in ahead);
if content.peek(Token![crate])
|| content.peek(Token![self])
|| content.peek(Token![super])
{
return Ok(PubVisibility {
pub_token: pub_token,
restricted: Some(Restricted {
paren_token: parenthesized!(content in input),
in_token: None,
path: Path::from(content.call(Ident::parse_any)?),
}),
});
} else if content.peek(Token![in]) {
return Ok(PubVisibility {
pub_token: pub_token,
restricted: Some(Restricted {
paren_token: parenthesized!(content in input),
in_token: Some(content.parse()?),
path: content.call(Path::parse_mod_style)?,
}),
});
}
}
Ok(PubVisibility {
pub_token: pub_token,
restricted: None,
})
}
}
Triggers an error at the current position of the parse stream.
#[macro_use]
extern crate syn;
use syn::{Expr, Result};
use syn::parse::{Parse, ParseStream};
struct Loop {
expr: Expr,
}
impl Parse for Loop {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Token![while])
|| input.peek(Token![for])
|| input.peek(Token![loop])
{
Ok(Loop {
expr: input.parse()?,
})
} else {
Err(input.error("expected some kind of loop"))
}
}
}
Speculatively parses tokens from this parse stream, advancing the
position of this stream only if parsing succeeds.
This is a powerful low-level API used for defining the Parse
impls of
the basic built-in token types. It is not something that will be used
widely outside of the Syn codebase.
use proc_macro2::TokenTree;
use syn::Result;
use syn::parse::ParseStream;
fn skip_past_next_at(input: ParseStream) -> Result<()> {
input.step(|cursor| {
let mut rest = *cursor;
while let Some((tt, next)) = rest.token_tree() {
match tt {
TokenTree::Punct(ref punct) if punct.as_char() == '@' => {
return Ok(((), next));
}
_ => rest = next,
}
}
Err(cursor.error("no `@` was found after this point"))
})
}
Provides low-level access to the token representation underlying this
parse stream.
Cursors are immutable so no operations you perform against the cursor
will affect the state of this parse stream.