aboutsummaryrefslogtreecommitdiff
path: root/syn/src/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'syn/src/expr.rs')
-rw-r--r--syn/src/expr.rs3236
1 files changed, 3236 insertions, 0 deletions
diff --git a/syn/src/expr.rs b/syn/src/expr.rs
new file mode 100644
index 0000000..603dc32
--- /dev/null
+++ b/syn/src/expr.rs
@@ -0,0 +1,3236 @@
+use super::*;
+use crate::punctuated::Punctuated;
+#[cfg(feature = "extra-traits")]
+use crate::tt::TokenStreamHelper;
+use proc_macro2::{Span, TokenStream};
+#[cfg(feature = "printing")]
+use quote::IdentFragment;
+#[cfg(feature = "printing")]
+use std::fmt::{self, Display};
+use std::hash::{Hash, Hasher};
+#[cfg(all(feature = "parsing", feature = "full"))]
+use std::mem;
+
+ast_enum_of_structs! {
+ /// A Rust expression.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enums
+ ///
+ /// This type is a syntax tree enum. In Syn this and other syntax tree enums
+ /// are designed to be traversed using the following rebinding idiom.
+ ///
+ /// ```
+ /// # use syn::Expr;
+ /// #
+ /// # fn example(expr: Expr) {
+ /// # const IGNORE: &str = stringify! {
+ /// let expr: Expr = /* ... */;
+ /// # };
+ /// match expr {
+ /// Expr::MethodCall(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::Cast(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::If(expr) => {
+ /// /* ... */
+ /// }
+ ///
+ /// /* ... */
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// We begin with a variable `expr` of type `Expr` that has no fields
+ /// (because it is an enum), and by matching on it and rebinding a variable
+ /// with the same name `expr` we effectively imbue our variable with all of
+ /// the data fields provided by the variant that it turned out to be. So for
+ /// example above if we ended up in the `MethodCall` case then we get to use
+ /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get
+ /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`.
+ ///
+ /// This approach avoids repeating the variant names twice on every line.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprMethodCall};
+ /// #
+ /// # fn example(expr: Expr) {
+ /// // Repetitive; recommend not doing this.
+ /// match expr {
+ /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => {
+ /// # }
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// In general, the name to which a syntax tree enum variant is bound should
+ /// be a suitable name for the complete syntax tree enum type.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprField};
+ /// #
+ /// # fn example(discriminant: ExprField) {
+ /// // Binding is called `base` which is the name I would use if I were
+ /// // assigning `*discriminant.base` without an `if let`.
+ /// if let Expr::Tuple(base) = *discriminant.base {
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// A sign that you may not be choosing the right variable names is if you
+ /// see names getting repeated in your code, like accessing
+ /// `receiver.receiver` or `pat.pat` or `cond.cond`.
+ pub enum Expr #manual_extra_traits {
+ /// A slice literal expression: `[a, b, c, d]`.
+ Array(ExprArray),
+
+ /// An assignment expression: `a = compute()`.
+ Assign(ExprAssign),
+
+ /// A compound assignment expression: `counter += 1`.
+ AssignOp(ExprAssignOp),
+
+ /// An async block: `async { ... }`.
+ Async(ExprAsync),
+
+ /// An await expression: `fut.await`.
+ Await(ExprAwait),
+
+ /// A binary operation: `a + b`, `a * b`.
+ Binary(ExprBinary),
+
+ /// A blocked scope: `{ ... }`.
+ Block(ExprBlock),
+
+ /// A box expression: `box f`.
+ Box(ExprBox),
+
+ /// A `break`, with an optional label to break and an optional
+ /// expression.
+ Break(ExprBreak),
+
+ /// A function call expression: `invoke(a, b)`.
+ Call(ExprCall),
+
+ /// A cast expression: `foo as f64`.
+ Cast(ExprCast),
+
+ /// A closure expression: `|a, b| a + b`.
+ Closure(ExprClosure),
+
+ /// A `continue`, with an optional label.
+ Continue(ExprContinue),
+
+ /// Access of a named struct field (`obj.k`) or unnamed tuple struct
+ /// field (`obj.0`).
+ Field(ExprField),
+
+ /// A for loop: `for pat in expr { ... }`.
+ ForLoop(ExprForLoop),
+
+ /// An expression contained within invisible delimiters.
+ ///
+ /// This variant is important for faithfully representing the precedence
+ /// of expressions and is related to `None`-delimited spans in a
+ /// `TokenStream`.
+ Group(ExprGroup),
+
+ /// An `if` expression with an optional `else` block: `if expr { ... }
+ /// else { ... }`.
+ ///
+ /// The `else` branch expression may only be an `If` or `Block`
+ /// expression, not any of the other types of expression.
+ If(ExprIf),
+
+ /// A square bracketed indexing expression: `vector[2]`.
+ Index(ExprIndex),
+
+ /// A `let` guard: `let Some(x) = opt`.
+ Let(ExprLet),
+
+ /// A literal in place of an expression: `1`, `"foo"`.
+ Lit(ExprLit),
+
+ /// Conditionless loop: `loop { ... }`.
+ Loop(ExprLoop),
+
+ /// A macro invocation expression: `format!("{}", q)`.
+ Macro(ExprMacro),
+
+ /// A `match` expression: `match n { Some(n) => {}, None => {} }`.
+ Match(ExprMatch),
+
+ /// A method call expression: `x.foo::<T>(a, b)`.
+ MethodCall(ExprMethodCall),
+
+ /// A parenthesized expression: `(a + b)`.
+ Paren(ExprParen),
+
+ /// A path like `std::mem::replace` possibly containing generic
+ /// parameters and a qualified self-type.
+ ///
+ /// A plain identifier like `x` is a path of length 1.
+ Path(ExprPath),
+
+ /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`.
+ Range(ExprRange),
+
+ /// A referencing operation: `&a` or `&mut a`.
+ Reference(ExprReference),
+
+ /// An array literal constructed from one repeated element: `[0u8; N]`.
+ Repeat(ExprRepeat),
+
+ /// A `return`, with an optional value to be returned.
+ Return(ExprReturn),
+
+ /// A struct literal expression: `Point { x: 1, y: 1 }`.
+ ///
+ /// The `rest` provides the value of the remaining fields as in `S { a:
+ /// 1, b: 1, ..rest }`.
+ Struct(ExprStruct),
+
+ /// A try-expression: `expr?`.
+ Try(ExprTry),
+
+ /// A try block: `try { ... }`.
+ TryBlock(ExprTryBlock),
+
+ /// A tuple expression: `(a, b, c, d)`.
+ Tuple(ExprTuple),
+
+ /// A type ascription expression: `foo: f64`.
+ Type(ExprType),
+
+ /// A unary operation: `!x`, `*x`.
+ Unary(ExprUnary),
+
+ /// An unsafe block: `unsafe { ... }`.
+ Unsafe(ExprUnsafe),
+
+ /// Tokens in expression position not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ /// A while loop: `while expr { ... }`.
+ While(ExprWhile),
+
+ /// A yield expression: `yield expr`.
+ Yield(ExprYield),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// A slice literal expression: `[a, b, c, d]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprArray #full {
+ pub attrs: Vec<Attribute>,
+ pub bracket_token: token::Bracket,
+ pub elems: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// An assignment expression: `a = compute()`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAssign #full {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub eq_token: Token![=],
+ pub right: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A compound assignment expression: `counter += 1`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAssignOp #full {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub op: BinOp,
+ pub right: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An async block: `async { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAsync #full {
+ pub attrs: Vec<Attribute>,
+ pub async_token: Token![async],
+ pub capture: Option<Token![move]>,
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// An await expression: `fut.await`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAwait #full {
+ pub attrs: Vec<Attribute>,
+ pub base: Box<Expr>,
+ pub dot_token: Token![.],
+ pub await_token: token::Await,
+ }
+}
+
+ast_struct! {
+ /// A binary operation: `a + b`, `a * b`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprBinary {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub op: BinOp,
+ pub right: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A blocked scope: `{ ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprBlock #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// A box expression: `box f`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprBox #full {
+ pub attrs: Vec<Attribute>,
+ pub box_token: Token![box],
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `break`, with an optional label to break and an optional
+ /// expression.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprBreak #full {
+ pub attrs: Vec<Attribute>,
+ pub break_token: Token![break],
+ pub label: Option<Lifetime>,
+ pub expr: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A function call expression: `invoke(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprCall {
+ pub attrs: Vec<Attribute>,
+ pub func: Box<Expr>,
+ pub paren_token: token::Paren,
+ pub args: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A cast expression: `foo as f64`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprCast {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub as_token: Token![as],
+ pub ty: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A closure expression: `|a, b| a + b`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprClosure #full {
+ pub attrs: Vec<Attribute>,
+ pub asyncness: Option<Token![async]>,
+ pub movability: Option<Token![static]>,
+ pub capture: Option<Token![move]>,
+ pub or1_token: Token![|],
+ pub inputs: Punctuated<Pat, Token![,]>,
+ pub or2_token: Token![|],
+ pub output: ReturnType,
+ pub body: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `continue`, with an optional label.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprContinue #full {
+ pub attrs: Vec<Attribute>,
+ pub continue_token: Token![continue],
+ pub label: Option<Lifetime>,
+ }
+}
+
+ast_struct! {
+ /// Access of a named struct field (`obj.k`) or unnamed tuple struct
+ /// field (`obj.0`).
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprField {
+ pub attrs: Vec<Attribute>,
+ pub base: Box<Expr>,
+ pub dot_token: Token![.],
+ pub member: Member,
+ }
+}
+
+ast_struct! {
+ /// A for loop: `for pat in expr { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprForLoop #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub for_token: Token![for],
+ pub pat: Pat,
+ pub in_token: Token![in],
+ pub expr: Box<Expr>,
+ pub body: Block,
+ }
+}
+
+ast_struct! {
+ /// An expression contained within invisible delimiters.
+ ///
+ /// This variant is important for faithfully representing the precedence
+ /// of expressions and is related to `None`-delimited spans in a
+ /// `TokenStream`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprGroup #full {
+ pub attrs: Vec<Attribute>,
+ pub group_token: token::Group,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An `if` expression with an optional `else` block: `if expr { ... }
+ /// else { ... }`.
+ ///
+ /// The `else` branch expression may only be an `If` or `Block`
+ /// expression, not any of the other types of expression.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprIf #full {
+ pub attrs: Vec<Attribute>,
+ pub if_token: Token![if],
+ pub cond: Box<Expr>,
+ pub then_branch: Block,
+ pub else_branch: Option<(Token![else], Box<Expr>)>,
+ }
+}
+
+ast_struct! {
+ /// A square bracketed indexing expression: `vector[2]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprIndex {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub bracket_token: token::Bracket,
+ pub index: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `let` guard: `let Some(x) = opt`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprLet #full {
+ pub attrs: Vec<Attribute>,
+ pub let_token: Token![let],
+ pub pat: Pat,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A literal in place of an expression: `1`, `"foo"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprLit {
+ pub attrs: Vec<Attribute>,
+ pub lit: Lit,
+ }
+}
+
+ast_struct! {
+ /// Conditionless loop: `loop { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprLoop #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub loop_token: Token![loop],
+ pub body: Block,
+ }
+}
+
+ast_struct! {
+ /// A macro invocation expression: `format!("{}", q)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprMacro #full {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ }
+}
+
+ast_struct! {
+ /// A `match` expression: `match n { Some(n) => {}, None => {} }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprMatch #full {
+ pub attrs: Vec<Attribute>,
+ pub match_token: Token![match],
+ pub expr: Box<Expr>,
+ pub brace_token: token::Brace,
+ pub arms: Vec<Arm>,
+ }
+}
+
+ast_struct! {
+ /// A method call expression: `x.foo::<T>(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprMethodCall #full {
+ pub attrs: Vec<Attribute>,
+ pub receiver: Box<Expr>,
+ pub dot_token: Token![.],
+ pub method: Ident,
+ pub turbofish: Option<MethodTurbofish>,
+ pub paren_token: token::Paren,
+ pub args: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A parenthesized expression: `(a + b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprParen {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A path like `std::mem::replace` possibly containing generic
+ /// parameters and a qualified self-type.
+ ///
+ /// A plain identifier like `x` is a path of length 1.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprPath {
+ pub attrs: Vec<Attribute>,
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }
+}
+
+ast_struct! {
+ /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprRange #full {
+ pub attrs: Vec<Attribute>,
+ pub from: Option<Box<Expr>>,
+ pub limits: RangeLimits,
+ pub to: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A referencing operation: `&a` or `&mut a`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprReference #full {
+ pub attrs: Vec<Attribute>,
+ pub and_token: Token![&],
+ pub raw: Reserved,
+ pub mutability: Option<Token![mut]>,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An array literal constructed from one repeated element: `[0u8; N]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprRepeat #full {
+ pub attrs: Vec<Attribute>,
+ pub bracket_token: token::Bracket,
+ pub expr: Box<Expr>,
+ pub semi_token: Token![;],
+ pub len: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `return`, with an optional value to be returned.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprReturn #full {
+ pub attrs: Vec<Attribute>,
+ pub return_token: Token![return],
+ pub expr: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A struct literal expression: `Point { x: 1, y: 1 }`.
+ ///
+ /// The `rest` provides the value of the remaining fields as in `S { a:
+ /// 1, b: 1, ..rest }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprStruct #full {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ pub brace_token: token::Brace,
+ pub fields: Punctuated<FieldValue, Token![,]>,
+ pub dot2_token: Option<Token![..]>,
+ pub rest: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A try-expression: `expr?`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprTry #full {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub question_token: Token![?],
+ }
+}
+
+ast_struct! {
+ /// A try block: `try { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprTryBlock #full {
+ pub attrs: Vec<Attribute>,
+ pub try_token: Token![try],
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// A tuple expression: `(a, b, c, d)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprTuple #full {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A type ascription expression: `foo: f64`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprType #full {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A unary operation: `!x`, `*x`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprUnary {
+ pub attrs: Vec<Attribute>,
+ pub op: UnOp,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An unsafe block: `unsafe { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprUnsafe #full {
+ pub attrs: Vec<Attribute>,
+ pub unsafe_token: Token![unsafe],
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// A while loop: `while expr { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprWhile #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub while_token: Token![while],
+ pub cond: Box<Expr>,
+ pub body: Block,
+ }
+}
+
+ast_struct! {
+ /// A yield expression: `yield expr`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprYield #full {
+ pub attrs: Vec<Attribute>,
+ pub yield_token: Token![yield],
+ pub expr: Option<Box<Expr>>,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Expr {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Expr {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Expr::Array(this), Expr::Array(other)) => this == other,
+ (Expr::Assign(this), Expr::Assign(other)) => this == other,
+ (Expr::AssignOp(this), Expr::AssignOp(other)) => this == other,
+ (Expr::Async(this), Expr::Async(other)) => this == other,
+ (Expr::Await(this), Expr::Await(other)) => this == other,
+ (Expr::Binary(this), Expr::Binary(other)) => this == other,
+ (Expr::Block(this), Expr::Block(other)) => this == other,
+ (Expr::Box(this), Expr::Box(other)) => this == other,
+ (Expr::Break(this), Expr::Break(other)) => this == other,
+ (Expr::Call(this), Expr::Call(other)) => this == other,
+ (Expr::Cast(this), Expr::Cast(other)) => this == other,
+ (Expr::Closure(this), Expr::Closure(other)) => this == other,
+ (Expr::Continue(this), Expr::Continue(other)) => this == other,
+ (Expr::Field(this), Expr::Field(other)) => this == other,
+ (Expr::ForLoop(this), Expr::ForLoop(other)) => this == other,
+ (Expr::Group(this), Expr::Group(other)) => this == other,
+ (Expr::If(this), Expr::If(other)) => this == other,
+ (Expr::Index(this), Expr::Index(other)) => this == other,
+ (Expr::Let(this), Expr::Let(other)) => this == other,
+ (Expr::Lit(this), Expr::Lit(other)) => this == other,
+ (Expr::Loop(this), Expr::Loop(other)) => this == other,
+ (Expr::Macro(this), Expr::Macro(other)) => this == other,
+ (Expr::Match(this), Expr::Match(other)) => this == other,
+ (Expr::MethodCall(this), Expr::MethodCall(other)) => this == other,
+ (Expr::Paren(this), Expr::Paren(other)) => this == other,
+ (Expr::Path(this), Expr::Path(other)) => this == other,
+ (Expr::Range(this), Expr::Range(other)) => this == other,
+ (Expr::Reference(this), Expr::Reference(other)) => this == other,
+ (Expr::Repeat(this), Expr::Repeat(other)) => this == other,
+ (Expr::Return(this), Expr::Return(other)) => this == other,
+ (Expr::Struct(this), Expr::Struct(other)) => this == other,
+ (Expr::Try(this), Expr::Try(other)) => this == other,
+ (Expr::TryBlock(this), Expr::TryBlock(other)) => this == other,
+ (Expr::Tuple(this), Expr::Tuple(other)) => this == other,
+ (Expr::Type(this), Expr::Type(other)) => this == other,
+ (Expr::Unary(this), Expr::Unary(other)) => this == other,
+ (Expr::Unsafe(this), Expr::Unsafe(other)) => this == other,
+ (Expr::Verbatim(this), Expr::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ (Expr::While(this), Expr::While(other)) => this == other,
+ (Expr::Yield(this), Expr::Yield(other)) => this == other,
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Expr {
+ fn hash<H>(&self, hash: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ Expr::Array(expr) => {
+ hash.write_u8(0);
+ expr.hash(hash);
+ }
+ Expr::Assign(expr) => {
+ hash.write_u8(1);
+ expr.hash(hash);
+ }
+ Expr::AssignOp(expr) => {
+ hash.write_u8(2);
+ expr.hash(hash);
+ }
+ Expr::Async(expr) => {
+ hash.write_u8(3);
+ expr.hash(hash);
+ }
+ Expr::Await(expr) => {
+ hash.write_u8(4);
+ expr.hash(hash);
+ }
+ Expr::Binary(expr) => {
+ hash.write_u8(5);
+ expr.hash(hash);
+ }
+ Expr::Block(expr) => {
+ hash.write_u8(6);
+ expr.hash(hash);
+ }
+ Expr::Box(expr) => {
+ hash.write_u8(7);
+ expr.hash(hash);
+ }
+ Expr::Break(expr) => {
+ hash.write_u8(8);
+ expr.hash(hash);
+ }
+ Expr::Call(expr) => {
+ hash.write_u8(9);
+ expr.hash(hash);
+ }
+ Expr::Cast(expr) => {
+ hash.write_u8(10);
+ expr.hash(hash);
+ }
+ Expr::Closure(expr) => {
+ hash.write_u8(11);
+ expr.hash(hash);
+ }
+ Expr::Continue(expr) => {
+ hash.write_u8(12);
+ expr.hash(hash);
+ }
+ Expr::Field(expr) => {
+ hash.write_u8(13);
+ expr.hash(hash);
+ }
+ Expr::ForLoop(expr) => {
+ hash.write_u8(14);
+ expr.hash(hash);
+ }
+ Expr::Group(expr) => {
+ hash.write_u8(15);
+ expr.hash(hash);
+ }
+ Expr::If(expr) => {
+ hash.write_u8(16);
+ expr.hash(hash);
+ }
+ Expr::Index(expr) => {
+ hash.write_u8(17);
+ expr.hash(hash);
+ }
+ Expr::Let(expr) => {
+ hash.write_u8(18);
+ expr.hash(hash);
+ }
+ Expr::Lit(expr) => {
+ hash.write_u8(19);
+ expr.hash(hash);
+ }
+ Expr::Loop(expr) => {
+ hash.write_u8(20);
+ expr.hash(hash);
+ }
+ Expr::Macro(expr) => {
+ hash.write_u8(21);
+ expr.hash(hash);
+ }
+ Expr::Match(expr) => {
+ hash.write_u8(22);
+ expr.hash(hash);
+ }
+ Expr::MethodCall(expr) => {
+ hash.write_u8(23);
+ expr.hash(hash);
+ }
+ Expr::Paren(expr) => {
+ hash.write_u8(24);
+ expr.hash(hash);
+ }
+ Expr::Path(expr) => {
+ hash.write_u8(25);
+ expr.hash(hash);
+ }
+ Expr::Range(expr) => {
+ hash.write_u8(26);
+ expr.hash(hash);
+ }
+ Expr::Reference(expr) => {
+ hash.write_u8(27);
+ expr.hash(hash);
+ }
+ Expr::Repeat(expr) => {
+ hash.write_u8(28);
+ expr.hash(hash);
+ }
+ Expr::Return(expr) => {
+ hash.write_u8(29);
+ expr.hash(hash);
+ }
+ Expr::Struct(expr) => {
+ hash.write_u8(30);
+ expr.hash(hash);
+ }
+ Expr::Try(expr) => {
+ hash.write_u8(31);
+ expr.hash(hash);
+ }
+ Expr::TryBlock(expr) => {
+ hash.write_u8(32);
+ expr.hash(hash);
+ }
+ Expr::Tuple(expr) => {
+ hash.write_u8(33);
+ expr.hash(hash);
+ }
+ Expr::Type(expr) => {
+ hash.write_u8(34);
+ expr.hash(hash);
+ }
+ Expr::Unary(expr) => {
+ hash.write_u8(35);
+ expr.hash(hash);
+ }
+ Expr::Unsafe(expr) => {
+ hash.write_u8(36);
+ expr.hash(hash);
+ }
+ Expr::Verbatim(expr) => {
+ hash.write_u8(37);
+ TokenStreamHelper(expr).hash(hash);
+ }
+ Expr::While(expr) => {
+ hash.write_u8(38);
+ expr.hash(hash);
+ }
+ Expr::Yield(expr) => {
+ hash.write_u8(39);
+ expr.hash(hash);
+ }
+ Expr::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+impl Expr {
+ #[cfg(all(feature = "parsing", feature = "full"))]
+ pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> {
+ match self {
+ Expr::Box(ExprBox { attrs, .. })
+ | Expr::Array(ExprArray { attrs, .. })
+ | Expr::Call(ExprCall { attrs, .. })
+ | Expr::MethodCall(ExprMethodCall { attrs, .. })
+ | Expr::Tuple(ExprTuple { attrs, .. })
+ | Expr::Binary(ExprBinary { attrs, .. })
+ | Expr::Unary(ExprUnary { attrs, .. })
+ | Expr::Lit(ExprLit { attrs, .. })
+ | Expr::Cast(ExprCast { attrs, .. })
+ | Expr::Type(ExprType { attrs, .. })
+ | Expr::Let(ExprLet { attrs, .. })
+ | Expr::If(ExprIf { attrs, .. })
+ | Expr::While(ExprWhile { attrs, .. })
+ | Expr::ForLoop(ExprForLoop { attrs, .. })
+ | Expr::Loop(ExprLoop { attrs, .. })
+ | Expr::Match(ExprMatch { attrs, .. })
+ | Expr::Closure(ExprClosure { attrs, .. })
+ | Expr::Unsafe(ExprUnsafe { attrs, .. })
+ | Expr::Block(ExprBlock { attrs, .. })
+ | Expr::Assign(ExprAssign { attrs, .. })
+ | Expr::AssignOp(ExprAssignOp { attrs, .. })
+ | Expr::Field(ExprField { attrs, .. })
+ | Expr::Index(ExprIndex { attrs, .. })
+ | Expr::Range(ExprRange { attrs, .. })
+ | Expr::Path(ExprPath { attrs, .. })
+ | Expr::Reference(ExprReference { attrs, .. })
+ | Expr::Break(ExprBreak { attrs, .. })
+ | Expr::Continue(ExprContinue { attrs, .. })
+ | Expr::Return(ExprReturn { attrs, .. })
+ | Expr::Macro(ExprMacro { attrs, .. })
+ | Expr::Struct(ExprStruct { attrs, .. })
+ | Expr::Repeat(ExprRepeat { attrs, .. })
+ | Expr::Paren(ExprParen { attrs, .. })
+ | Expr::Group(ExprGroup { attrs, .. })
+ | Expr::Try(ExprTry { attrs, .. })
+ | Expr::Async(ExprAsync { attrs, .. })
+ | Expr::Await(ExprAwait { attrs, .. })
+ | Expr::TryBlock(ExprTryBlock { attrs, .. })
+ | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new),
+ Expr::Verbatim(_) => Vec::new(),
+ Expr::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+ast_enum! {
+ /// A struct or tuple struct field accessed in a struct literal or field
+ /// expression.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[derive(Eq, PartialEq, Hash)]
+ pub enum Member #manual_extra_traits {
+ /// A named field like `self.x`.
+ Named(Ident),
+ /// An unnamed field like `self.0`.
+ Unnamed(Index),
+ }
+}
+
+#[cfg(feature = "printing")]
+impl IdentFragment for Member {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Member::Named(m) => Display::fmt(m, formatter),
+ Member::Unnamed(m) => Display::fmt(&m.index, formatter),
+ }
+ }
+
+ fn span(&self) -> Option<Span> {
+ match self {
+ Member::Named(m) => Some(m.span()),
+ Member::Unnamed(m) => Some(m.span),
+ }
+ }
+}
+
+ast_struct! {
+ /// The index of an unnamed tuple struct field.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Index #manual_extra_traits {
+ pub index: u32,
+ pub span: Span,
+ }
+}
+
+impl From<usize> for Index {
+ fn from(index: usize) -> Index {
+ assert!(index < u32::max_value() as usize);
+ Index {
+ index: index as u32,
+ span: Span::call_site(),
+ }
+ }
+}
+
+impl Eq for Index {}
+
+impl PartialEq for Index {
+ fn eq(&self, other: &Self) -> bool {
+ self.index == other.index
+ }
+}
+
+impl Hash for Index {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.index.hash(state);
+ }
+}
+
+#[cfg(feature = "printing")]
+impl IdentFragment for Index {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(&self.index, formatter)
+ }
+
+ fn span(&self) -> Option<Span> {
+ Some(self.span)
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ #[derive(Default)]
+ pub struct Reserved {
+ _private: (),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// The `::<>` explicit type parameters passed to a method call:
+ /// `parse::<u64>()`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct MethodTurbofish {
+ pub colon2_token: Token![::],
+ pub lt_token: Token![<],
+ pub args: Punctuated<GenericMethodArgument, Token![,]>,
+ pub gt_token: Token![>],
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum! {
+ /// An individual generic argument to a method, like `T`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub enum GenericMethodArgument {
+ /// A type argument.
+ Type(Type),
+ /// A const expression. Must be inside of a block.
+ ///
+ /// NOTE: Identity expressions are represented as Type arguments, as
+ /// they are indistinguishable syntactically.
+ Const(Expr),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A field-value pair in a struct literal.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct FieldValue {
+ /// Attributes tagged on the field.
+ pub attrs: Vec<Attribute>,
+
+ /// Name or index of the field.
+ pub member: Member,
+
+ /// The colon in `Struct { x: x }`. If written in shorthand like
+ /// `Struct { x }`, there is no colon.
+ pub colon_token: Option<Token![:]>,
+
+ /// Value of the field.
+ pub expr: Expr,
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A lifetime labeling a `for`, `while`, or `loop`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Label {
+ pub name: Lifetime,
+ pub colon_token: Token![:],
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// One arm of a `match` expression: `0...10 => { return true; }`.
+ ///
+ /// As in:
+ ///
+ /// ```
+ /// # fn f() -> bool {
+ /// # let n = 0;
+ /// match n {
+ /// 0...10 => {
+ /// return true;
+ /// }
+ /// // ...
+ /// # _ => {}
+ /// }
+ /// # false
+ /// # }
+ /// ```
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Arm {
+ pub attrs: Vec<Attribute>,
+ pub pat: Pat,
+ pub guard: Option<(Token![if], Box<Expr>)>,
+ pub fat_arrow_token: Token![=>],
+ pub body: Box<Expr>,
+ pub comma: Option<Token![,]>,
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum! {
+ /// Limit types of a range, inclusive or exclusive.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum RangeLimits {
+ /// Inclusive at the beginning, exclusive at the end.
+ HalfOpen(Token![..]),
+ /// Inclusive at the beginning and end.
+ Closed(Token![..=]),
+ }
+}
+
+#[cfg(any(feature = "parsing", feature = "printing"))]
+#[cfg(feature = "full")]
+pub(crate) fn requires_terminator(expr: &Expr) -> bool {
+ // see https://github.com/rust-lang/rust/blob/eb8f2586e/src/libsyntax/parse/classify.rs#L17-L37
+ match *expr {
+ Expr::Unsafe(..)
+ | Expr::Block(..)
+ | Expr::If(..)
+ | Expr::Match(..)
+ | Expr::While(..)
+ | Expr::Loop(..)
+ | Expr::ForLoop(..)
+ | Expr::Async(..)
+ | Expr::TryBlock(..) => false,
+ _ => true,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub(crate) mod parsing {
+ use super::*;
+
+ use crate::parse::discouraged::Speculative;
+ use crate::parse::{Parse, ParseStream, Result};
+ use crate::path;
+
+ // When we're parsing expressions which occur before blocks, like in an if
+ // statement's condition, we cannot parse a struct literal.
+ //
+ // Struct literals are ambiguous in certain positions
+ // https://github.com/rust-lang/rfcs/pull/92
+ #[derive(Copy, Clone)]
+ pub struct AllowStruct(bool);
+
+ #[derive(Copy, Clone, PartialEq, PartialOrd)]
+ enum Precedence {
+ Any,
+ Assign,
+ Range,
+ Or,
+ And,
+ Compare,
+ BitOr,
+ BitXor,
+ BitAnd,
+ Shift,
+ Arithmetic,
+ Term,
+ Cast,
+ }
+
+ impl Precedence {
+ fn of(op: &BinOp) -> Self {
+ match *op {
+ BinOp::Add(_) | BinOp::Sub(_) => Precedence::Arithmetic,
+ BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Term,
+ BinOp::And(_) => Precedence::And,
+ BinOp::Or(_) => Precedence::Or,
+ BinOp::BitXor(_) => Precedence::BitXor,
+ BinOp::BitAnd(_) => Precedence::BitAnd,
+ BinOp::BitOr(_) => Precedence::BitOr,
+ BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift,
+ BinOp::Eq(_)
+ | BinOp::Lt(_)
+ | BinOp::Le(_)
+ | BinOp::Ne(_)
+ | BinOp::Ge(_)
+ | BinOp::Gt(_) => Precedence::Compare,
+ BinOp::AddEq(_)
+ | BinOp::SubEq(_)
+ | BinOp::MulEq(_)
+ | BinOp::DivEq(_)
+ | BinOp::RemEq(_)
+ | BinOp::BitXorEq(_)
+ | BinOp::BitAndEq(_)
+ | BinOp::BitOrEq(_)
+ | BinOp::ShlEq(_)
+ | BinOp::ShrEq(_) => Precedence::Assign,
+ }
+ }
+ }
+
+ impl Parse for Expr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ ambiguous_expr(input, AllowStruct(true))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_no_struct(input: ParseStream) -> Result<Expr> {
+ ambiguous_expr(input, AllowStruct(false))
+ }
+
+ #[cfg(feature = "full")]
+ fn parse_expr(
+ input: ParseStream,
+ mut lhs: Expr,
+ allow_struct: AllowStruct,
+ base: Precedence,
+ ) -> Result<Expr> {
+ loop {
+ if input
+ .fork()
+ .parse::<BinOp>()
+ .ok()
+ .map_or(false, |op| Precedence::of(&op) >= base)
+ {
+ let op: BinOp = input.parse()?;
+ let precedence = Precedence::of(&op);
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next > precedence || next == precedence && precedence == Precedence::Assign {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ lhs = if precedence == Precedence::Assign {
+ Expr::AssignOp(ExprAssignOp {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ op,
+ right: Box::new(rhs),
+ })
+ } else {
+ Expr::Binary(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ op,
+ right: Box::new(rhs),
+ })
+ };
+ } else if Precedence::Assign >= base
+ && input.peek(Token![=])
+ && !input.peek(Token![==])
+ && !input.peek(Token![=>])
+ {
+ let eq_token: Token![=] = input.parse()?;
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next >= Precedence::Assign {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ lhs = Expr::Assign(ExprAssign {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ eq_token,
+ right: Box::new(rhs),
+ });
+ } else if Precedence::Range >= base && input.peek(Token![..]) {
+ let limits: RangeLimits = input.parse()?;
+ let rhs = if input.is_empty()
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || !allow_struct.0 && input.peek(token::Brace)
+ {
+ None
+ } else {
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next > Precedence::Range {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ Some(rhs)
+ };
+ lhs = Expr::Range(ExprRange {
+ attrs: Vec::new(),
+ from: Some(Box::new(lhs)),
+ limits,
+ to: rhs.map(Box::new),
+ });
+ } else if Precedence::Cast >= base && input.peek(Token![as]) {
+ let as_token: Token![as] = input.parse()?;
+ let ty = input.call(Type::without_plus)?;
+ lhs = Expr::Cast(ExprCast {
+ attrs: Vec::new(),
+ expr: Box::new(lhs),
+ as_token,
+ ty: Box::new(ty),
+ });
+ } else if Precedence::Cast >= base && input.peek(Token![:]) && !input.peek(Token![::]) {
+ let colon_token: Token![:] = input.parse()?;
+ let ty = input.call(Type::without_plus)?;
+ lhs = Expr::Type(ExprType {
+ attrs: Vec::new(),
+ expr: Box::new(lhs),
+ colon_token,
+ ty: Box::new(ty),
+ });
+ } else {
+ break;
+ }
+ }
+ Ok(lhs)
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn parse_expr(
+ input: ParseStream,
+ mut lhs: Expr,
+ allow_struct: AllowStruct,
+ base: Precedence,
+ ) -> Result<Expr> {
+ loop {
+ if input
+ .fork()
+ .parse::<BinOp>()
+ .ok()
+ .map_or(false, |op| Precedence::of(&op) >= base)
+ {
+ let op: BinOp = input.parse()?;
+ let precedence = Precedence::of(&op);
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next > precedence || next == precedence && precedence == Precedence::Assign {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ lhs = Expr::Binary(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ op,
+ right: Box::new(rhs),
+ });
+ } else if Precedence::Cast >= base && input.peek(Token![as]) {
+ let as_token: Token![as] = input.parse()?;
+ let ty = input.call(Type::without_plus)?;
+ lhs = Expr::Cast(ExprCast {
+ attrs: Vec::new(),
+ expr: Box::new(lhs),
+ as_token,
+ ty: Box::new(ty),
+ });
+ } else {
+ break;
+ }
+ }
+ Ok(lhs)
+ }
+
+ fn peek_precedence(input: ParseStream) -> Precedence {
+ if let Ok(op) = input.fork().parse() {
+ Precedence::of(&op)
+ } else if input.peek(Token![=]) && !input.peek(Token![=>]) {
+ Precedence::Assign
+ } else if input.peek(Token![..]) {
+ Precedence::Range
+ } else if input.peek(Token![as]) || input.peek(Token![:]) && !input.peek(Token![::]) {
+ Precedence::Cast
+ } else {
+ Precedence::Any
+ }
+ }
+
+ // Parse an arbitrary expression.
+ fn ambiguous_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let lhs = unary_expr(input, allow_struct)?;
+ parse_expr(input, lhs, allow_struct, Precedence::Any)
+ }
+
+ // <UnOp> <trailer>
+ // & <trailer>
+ // &mut <trailer>
+ // box <trailer>
+ #[cfg(feature = "full")]
+ fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let ahead = input.fork();
+ let attrs = ahead.call(Attribute::parse_outer)?;
+ if ahead.peek(Token![&])
+ || ahead.peek(Token![box])
+ || ahead.peek(Token![*])
+ || ahead.peek(Token![!])
+ || ahead.peek(Token![-])
+ {
+ input.advance_to(&ahead);
+ if input.peek(Token![&]) {
+ Ok(Expr::Reference(ExprReference {
+ attrs,
+ and_token: input.parse()?,
+ raw: Reserved::default(),
+ mutability: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ } else if input.peek(Token![box]) {
+ Ok(Expr::Box(ExprBox {
+ attrs,
+ box_token: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ } else {
+ Ok(Expr::Unary(ExprUnary {
+ attrs,
+ op: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ }
+ } else {
+ trailer_expr(input, allow_struct)
+ }
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let ahead = input.fork();
+ let attrs = ahead.call(Attribute::parse_outer)?;
+ if ahead.peek(Token![*]) || ahead.peek(Token![!]) || ahead.peek(Token![-]) {
+ input.advance_to(&ahead);
+ Ok(Expr::Unary(ExprUnary {
+ attrs,
+ op: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ } else {
+ trailer_expr(input, allow_struct)
+ }
+ }
+
+ // <atom> (..<args>) ...
+ // <atom> . <ident> (..<args>) ...
+ // <atom> . <ident> ...
+ // <atom> . <lit> ...
+ // <atom> [ <expr> ] ...
+ // <atom> ? ...
+ #[cfg(feature = "full")]
+ fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ if input.peek(token::Group) {
+ return input.call(expr_group).map(Expr::Group);
+ }
+
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+
+ let atom = atom_expr(input, allow_struct)?;
+ let mut e = trailer_helper(input, atom)?;
+
+ let inner_attrs = e.replace_attrs(Vec::new());
+ let attrs = private::attrs(outer_attrs, inner_attrs);
+ e.replace_attrs(attrs);
+ Ok(e)
+ }
+
+ #[cfg(feature = "full")]
+ fn trailer_helper(input: ParseStream, mut e: Expr) -> Result<Expr> {
+ loop {
+ if input.peek(token::Paren) {
+ let content;
+ e = Expr::Call(ExprCall {
+ attrs: Vec::new(),
+ func: Box::new(e),
+ paren_token: parenthesized!(content in input),
+ args: content.parse_terminated(Expr::parse)?,
+ });
+ } else if input.peek(Token![.]) && !input.peek(Token![..]) {
+ let dot_token: Token![.] = input.parse()?;
+
+ if input.peek(token::Await) {
+ e = Expr::Await(ExprAwait {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token,
+ await_token: input.parse()?,
+ });
+ continue;
+ }
+
+ let member: Member = input.parse()?;
+ let turbofish = if member.is_named() && input.peek(Token![::]) {
+ Some(MethodTurbofish {
+ colon2_token: input.parse()?,
+ lt_token: input.parse()?,
+ args: {
+ let mut args = Punctuated::new();
+ loop {
+ if input.peek(Token![>]) {
+ break;
+ }
+ let value = input.call(generic_method_argument)?;
+ args.push_value(value);
+ if input.peek(Token![>]) {
+ break;
+ }
+ let punct = input.parse()?;
+ args.push_punct(punct);
+ }
+ args
+ },
+ gt_token: input.parse()?,
+ })
+ } else {
+ None
+ };
+
+ if turbofish.is_some() || input.peek(token::Paren) {
+ if let Member::Named(method) = member {
+ let content;
+ e = Expr::MethodCall(ExprMethodCall {
+ attrs: Vec::new(),
+ receiver: Box::new(e),
+ dot_token,
+ method,
+ turbofish,
+ paren_token: parenthesized!(content in input),
+ args: content.parse_terminated(Expr::parse)?,
+ });
+ continue;
+ }
+ }
+
+ e = Expr::Field(ExprField {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token,
+ member,
+ });
+ } else if input.peek(token::Bracket) {
+ let content;
+ e = Expr::Index(ExprIndex {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ bracket_token: bracketed!(content in input),
+ index: content.parse()?,
+ });
+ } else if input.peek(Token![?]) {
+ e = Expr::Try(ExprTry {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ question_token: input.parse()?,
+ });
+ } else {
+ break;
+ }
+ }
+ Ok(e)
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let mut e = atom_expr(input, allow_struct)?;
+
+ loop {
+ if input.peek(token::Paren) {
+ let content;
+ e = Expr::Call(ExprCall {
+ attrs: Vec::new(),
+ func: Box::new(e),
+ paren_token: parenthesized!(content in input),
+ args: content.parse_terminated(Expr::parse)?,
+ });
+ } else if input.peek(Token![.]) && !input.peek(Token![..]) && !input.peek2(token::Await)
+ {
+ e = Expr::Field(ExprField {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token: input.parse()?,
+ member: input.parse()?,
+ });
+ } else if input.peek(token::Bracket) {
+ let content;
+ e = Expr::Index(ExprIndex {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ bracket_token: bracketed!(content in input),
+ index: content.parse()?,
+ });
+ } else {
+ break;
+ }
+ }
+
+ Ok(e)
+ }
+
+ // Parse all atomic expressions which don't have to worry about precedence
+ // interactions, as they are fully contained.
+ #[cfg(feature = "full")]
+ fn atom_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ if input.peek(token::Group) {
+ input.call(expr_group).map(Expr::Group)
+ } else if input.peek(Lit) {
+ input.parse().map(Expr::Lit)
+ } else if input.peek(Token![async])
+ && (input.peek2(token::Brace) || input.peek2(Token![move]) && input.peek3(token::Brace))
+ {
+ input.call(expr_async).map(Expr::Async)
+ } else if input.peek(Token![try]) && input.peek2(token::Brace) {
+ input.call(expr_try_block).map(Expr::TryBlock)
+ } else if input.peek(Token![|])
+ || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move]))
+ || input.peek(Token![static])
+ || input.peek(Token![move])
+ {
+ expr_closure(input, allow_struct).map(Expr::Closure)
+ } else if input.peek(Ident)
+ || input.peek(Token![::])
+ || input.peek(Token![<])
+ || input.peek(Token![self])
+ || input.peek(Token![Self])
+ || input.peek(Token![super])
+ || input.peek(Token![extern])
+ || input.peek(Token![crate])
+ {
+ path_or_macro_or_struct(input, allow_struct)
+ } else if input.peek(token::Paren) {
+ paren_or_tuple(input)
+ } else if input.peek(Token![break]) {
+ expr_break(input, allow_struct).map(Expr::Break)
+ } else if input.peek(Token![continue]) {
+ input.call(expr_continue).map(Expr::Continue)
+ } else if input.peek(Token![return]) {
+ expr_ret(input, allow_struct).map(Expr::Return)
+ } else if input.peek(token::Bracket) {
+ array_or_repeat(input)
+ } else if input.peek(Token![let]) {
+ input.call(expr_let).map(Expr::Let)
+ } else if input.peek(Token![if]) {
+ input.parse().map(Expr::If)
+ } else if input.peek(Token![while]) {
+ input.parse().map(Expr::While)
+ } else if input.peek(Token![for]) {
+ input.parse().map(Expr::ForLoop)
+ } else if input.peek(Token![loop]) {
+ input.parse().map(Expr::Loop)
+ } else if input.peek(Token![match]) {
+ input.parse().map(Expr::Match)
+ } else if input.peek(Token![yield]) {
+ input.call(expr_yield).map(Expr::Yield)
+ } else if input.peek(Token![unsafe]) {
+ input.call(expr_unsafe).map(Expr::Unsafe)
+ } else if input.peek(token::Brace) {
+ input.call(expr_block).map(Expr::Block)
+ } else if input.peek(Token![..]) {
+ expr_range(input, allow_struct).map(Expr::Range)
+ } else if input.peek(Lifetime) {
+ let the_label: Label = input.parse()?;
+ let mut expr = if input.peek(Token![while]) {
+ Expr::While(input.parse()?)
+ } else if input.peek(Token![for]) {
+ Expr::ForLoop(input.parse()?)
+ } else if input.peek(Token![loop]) {
+ Expr::Loop(input.parse()?)
+ } else if input.peek(token::Brace) {
+ Expr::Block(input.call(expr_block)?)
+ } else {
+ return Err(input.error("expected loop or block expression"));
+ };
+ match &mut expr {
+ Expr::While(ExprWhile { label, .. })
+ | Expr::ForLoop(ExprForLoop { label, .. })
+ | Expr::Loop(ExprLoop { label, .. })
+ | Expr::Block(ExprBlock { label, .. }) => *label = Some(the_label),
+ _ => unreachable!(),
+ }
+ Ok(expr)
+ } else {
+ Err(input.error("expected expression"))
+ }
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn atom_expr(input: ParseStream, _allow_struct: AllowStruct) -> Result<Expr> {
+ if input.peek(Lit) {
+ input.parse().map(Expr::Lit)
+ } else if input.peek(token::Paren) {
+ input.call(expr_paren).map(Expr::Paren)
+ } else if input.peek(Ident)
+ || input.peek(Token![::])
+ || input.peek(Token![<])
+ || input.peek(Token![self])
+ || input.peek(Token![Self])
+ || input.peek(Token![super])
+ || input.peek(Token![extern])
+ || input.peek(Token![crate])
+ {
+ input.parse().map(Expr::Path)
+ } else {
+ Err(input.error("unsupported expression; enable syn's features=[\"full\"]"))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn path_or_macro_or_struct(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let expr: ExprPath = input.parse()?;
+ if expr.qself.is_some() {
+ return Ok(Expr::Path(expr));
+ }
+
+ if input.peek(Token![!]) && !input.peek(Token![!=]) {
+ let mut contains_arguments = false;
+ for segment in &expr.path.segments {
+ match segment.arguments {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
+ contains_arguments = true;
+ }
+ }
+ }
+
+ if !contains_arguments {
+ let bang_token: Token![!] = input.parse()?;
+ let (delimiter, tokens) = mac::parse_delimiter(input)?;
+ return Ok(Expr::Macro(ExprMacro {
+ attrs: Vec::new(),
+ mac: Macro {
+ path: expr.path,
+ bang_token,
+ delimiter,
+ tokens,
+ },
+ }));
+ }
+ }
+
+ if allow_struct.0 && input.peek(token::Brace) {
+ let outer_attrs = Vec::new();
+ expr_struct_helper(input, outer_attrs, expr.path).map(Expr::Struct)
+ } else {
+ Ok(Expr::Path(expr))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn paren_or_tuple(input: ParseStream) -> Result<Expr> {
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ if content.is_empty() {
+ return Ok(Expr::Tuple(ExprTuple {
+ attrs: inner_attrs,
+ paren_token,
+ elems: Punctuated::new(),
+ }));
+ }
+
+ let first: Expr = content.parse()?;
+ if content.is_empty() {
+ return Ok(Expr::Paren(ExprParen {
+ attrs: inner_attrs,
+ paren_token,
+ expr: Box::new(first),
+ }));
+ }
+
+ let mut elems = Punctuated::new();
+ elems.push_value(first);
+ while !content.is_empty() {
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ if content.is_empty() {
+ break;
+ }
+ let value = content.parse()?;
+ elems.push_value(value);
+ }
+ Ok(Expr::Tuple(ExprTuple {
+ attrs: inner_attrs,
+ paren_token,
+ elems,
+ }))
+ }
+
+ #[cfg(feature = "full")]
+ fn array_or_repeat(input: ParseStream) -> Result<Expr> {
+ let content;
+ let bracket_token = bracketed!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ if content.is_empty() {
+ return Ok(Expr::Array(ExprArray {
+ attrs: inner_attrs,
+ bracket_token,
+ elems: Punctuated::new(),
+ }));
+ }
+
+ let first: Expr = content.parse()?;
+ if content.is_empty() || content.peek(Token![,]) {
+ let mut elems = Punctuated::new();
+ elems.push_value(first);
+ while !content.is_empty() {
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ if content.is_empty() {
+ break;
+ }
+ let value = content.parse()?;
+ elems.push_value(value);
+ }
+ Ok(Expr::Array(ExprArray {
+ attrs: inner_attrs,
+ bracket_token,
+ elems,
+ }))
+ } else if content.peek(Token![;]) {
+ let semi_token: Token![;] = content.parse()?;
+ let len: Expr = content.parse()?;
+ Ok(Expr::Repeat(ExprRepeat {
+ attrs: inner_attrs,
+ bracket_token,
+ expr: Box::new(first),
+ semi_token,
+ len: Box::new(len),
+ }))
+ } else {
+ Err(content.error("expected `,` or `;`"))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ pub(crate) fn expr_early(input: ParseStream) -> Result<Expr> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let mut expr = if input.peek(Token![if]) {
+ Expr::If(input.parse()?)
+ } else if input.peek(Token![while]) {
+ Expr::While(input.parse()?)
+ } else if input.peek(Token![for]) {
+ Expr::ForLoop(input.parse()?)
+ } else if input.peek(Token![loop]) {
+ Expr::Loop(input.parse()?)
+ } else if input.peek(Token![match]) {
+ Expr::Match(input.parse()?)
+ } else if input.peek(Token![try]) && input.peek2(token::Brace) {
+ Expr::TryBlock(input.call(expr_try_block)?)
+ } else if input.peek(Token![unsafe]) {
+ Expr::Unsafe(input.call(expr_unsafe)?)
+ } else if input.peek(token::Brace) {
+ Expr::Block(input.call(expr_block)?)
+ } else {
+ let allow_struct = AllowStruct(true);
+ let mut expr = unary_expr(input, allow_struct)?;
+
+ attrs.extend(expr.replace_attrs(Vec::new()));
+ expr.replace_attrs(attrs);
+
+ return parse_expr(input, expr, allow_struct, Precedence::Any);
+ };
+
+ if input.peek(Token![.]) || input.peek(Token![?]) {
+ expr = trailer_helper(input, expr)?;
+
+ attrs.extend(expr.replace_attrs(Vec::new()));
+ expr.replace_attrs(attrs);
+
+ let allow_struct = AllowStruct(true);
+ return parse_expr(input, expr, allow_struct, Precedence::Any);
+ }
+
+ attrs.extend(expr.replace_attrs(Vec::new()));
+ expr.replace_attrs(attrs);
+ Ok(expr)
+ }
+
+ impl Parse for ExprLit {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ExprLit {
+ attrs: Vec::new(),
+ lit: input.parse()?,
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_group(input: ParseStream) -> Result<ExprGroup> {
+ let group = crate::group::parse_group(input)?;
+ Ok(ExprGroup {
+ attrs: Vec::new(),
+ group_token: group.token,
+ expr: group.content.parse()?,
+ })
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn expr_paren(input: ParseStream) -> Result<ExprParen> {
+ let content;
+ Ok(ExprParen {
+ attrs: Vec::new(),
+ paren_token: parenthesized!(content in input),
+ expr: content.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn generic_method_argument(input: ParseStream) -> Result<GenericMethodArgument> {
+ // TODO parse const generics as well
+ input.parse().map(GenericMethodArgument::Type)
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_let(input: ParseStream) -> Result<ExprLet> {
+ Ok(ExprLet {
+ attrs: Vec::new(),
+ let_token: input.parse()?,
+ pat: {
+ let leading_vert: Option<Token![|]> = input.parse()?;
+ let pat: Pat = input.parse()?;
+ if leading_vert.is_some()
+ || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
+ {
+ let mut cases = Punctuated::new();
+ cases.push_value(pat);
+ while input.peek(Token![|])
+ && !input.peek(Token![||])
+ && !input.peek(Token![|=])
+ {
+ let punct = input.parse()?;
+ cases.push_punct(punct);
+ let pat: Pat = input.parse()?;
+ cases.push_value(pat);
+ }
+ Pat::Or(PatOr {
+ attrs: Vec::new(),
+ leading_vert,
+ cases,
+ })
+ } else {
+ pat
+ }
+ },
+ eq_token: input.parse()?,
+ expr: Box::new(input.call(expr_no_struct)?),
+ })
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprIf {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ExprIf {
+ attrs: Vec::new(),
+ if_token: input.parse()?,
+ cond: Box::new(input.call(expr_no_struct)?),
+ then_branch: input.parse()?,
+ else_branch: {
+ if input.peek(Token![else]) {
+ Some(input.call(else_block)?)
+ } else {
+ None
+ }
+ },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn else_block(input: ParseStream) -> Result<(Token![else], Box<Expr>)> {
+ let else_token: Token![else] = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let else_branch = if input.peek(Token![if]) {
+ input.parse().map(Expr::If)?
+ } else if input.peek(token::Brace) {
+ Expr::Block(ExprBlock {
+ attrs: Vec::new(),
+ label: None,
+ block: input.parse()?,
+ })
+ } else {
+ return Err(lookahead.error());
+ };
+
+ Ok((else_token, Box::new(else_branch)))
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprForLoop {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let label: Option<Label> = input.parse()?;
+ let for_token: Token![for] = input.parse()?;
+
+ let leading_vert: Option<Token![|]> = input.parse()?;
+ let mut pat: Pat = input.parse()?;
+ if leading_vert.is_some() || input.peek(Token![|]) {
+ let mut cases = Punctuated::new();
+ cases.push_value(pat);
+ while input.peek(Token![|]) {
+ let punct = input.parse()?;
+ cases.push_punct(punct);
+ let pat: Pat = input.parse()?;
+ cases.push_value(pat);
+ }
+ pat = Pat::Or(PatOr {
+ attrs: Vec::new(),
+ leading_vert,
+ cases,
+ });
+ }
+
+ let in_token: Token![in] = input.parse()?;
+ let expr: Expr = input.call(expr_no_struct)?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprForLoop {
+ attrs: inner_attrs,
+ label,
+ for_token,
+ pat,
+ in_token,
+ expr: Box::new(expr),
+ body: Block { brace_token, stmts },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprLoop {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let label: Option<Label> = input.parse()?;
+ let loop_token: Token![loop] = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprLoop {
+ attrs: inner_attrs,
+ label,
+ loop_token,
+ body: Block { brace_token, stmts },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprMatch {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let match_token: Token![match] = input.parse()?;
+ let expr = expr_no_struct(input)?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+
+ let mut arms = Vec::new();
+ while !content.is_empty() {
+ arms.push(content.call(Arm::parse)?);
+ }
+
+ Ok(ExprMatch {
+ attrs: inner_attrs,
+ match_token,
+ expr: Box::new(expr),
+ brace_token,
+ arms,
+ })
+ }
+ }
+
+ macro_rules! impl_by_parsing_expr {
+ (
+ $(
+ $expr_type:ty, $variant:ident, $msg:expr,
+ )*
+ ) => {
+ $(
+ #[cfg(all(feature = "full", feature = "printing"))]
+ impl Parse for $expr_type {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut expr: Expr = input.parse()?;
+ loop {
+ match expr {
+ Expr::$variant(inner) => return Ok(inner),
+ Expr::Group(next) => expr = *next.expr,
+ _ => return Err(Error::new_spanned(expr, $msg)),
+ }
+ }
+ }
+ }
+ )*
+ };
+ }
+
+ impl_by_parsing_expr! {
+ ExprBox, Box, "expected box expression",
+ ExprArray, Array, "expected slice literal expression",
+ ExprCall, Call, "expected function call expression",
+ ExprMethodCall, MethodCall, "expected method call expression",
+ ExprTuple, Tuple, "expected tuple expression",
+ ExprBinary, Binary, "expected binary operation",
+ ExprUnary, Unary, "expected unary operation",
+ ExprCast, Cast, "expected cast expression",
+ ExprType, Type, "expected type ascription expression",
+ ExprLet, Let, "expected let guard",
+ ExprClosure, Closure, "expected closure expression",
+ ExprUnsafe, Unsafe, "expected unsafe block",
+ ExprBlock, Block, "expected blocked scope",
+ ExprAssign, Assign, "expected assignment expression",
+ ExprAssignOp, AssignOp, "expected compound assignment expression",
+ ExprField, Field, "expected struct field access",
+ ExprIndex, Index, "expected indexing expression",
+ ExprRange, Range, "expected range expression",
+ ExprReference, Reference, "expected referencing operation",
+ ExprBreak, Break, "expected break expression",
+ ExprContinue, Continue, "expected continue expression",
+ ExprReturn, Return, "expected return expression",
+ ExprMacro, Macro, "expected macro invocation expression",
+ ExprStruct, Struct, "expected struct literal expression",
+ ExprRepeat, Repeat, "expected array literal constructed from one repeated element",
+ ExprParen, Paren, "expected parenthesized expression",
+ ExprTry, Try, "expected try expression",
+ ExprAsync, Async, "expected async block",
+ ExprTryBlock, TryBlock, "expected try block",
+ ExprYield, Yield, "expected yield expression",
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_try_block(input: ParseStream) -> Result<ExprTryBlock> {
+ Ok(ExprTryBlock {
+ attrs: Vec::new(),
+ try_token: input.parse()?,
+ block: input.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_yield(input: ParseStream) -> Result<ExprYield> {
+ Ok(ExprYield {
+ attrs: Vec::new(),
+ yield_token: input.parse()?,
+ expr: {
+ if !input.is_empty() && !input.peek(Token![,]) && !input.peek(Token![;]) {
+ Some(input.parse()?)
+ } else {
+ None
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_closure(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprClosure> {
+ let asyncness: Option<Token![async]> = input.parse()?;
+ let movability: Option<Token![static]> = if asyncness.is_none() {
+ input.parse()?
+ } else {
+ None
+ };
+ let capture: Option<Token![move]> = input.parse()?;
+ let or1_token: Token![|] = input.parse()?;
+
+ let mut inputs = Punctuated::new();
+ loop {
+ if input.peek(Token![|]) {
+ break;
+ }
+ let value = closure_arg(input)?;
+ inputs.push_value(value);
+ if input.peek(Token![|]) {
+ break;
+ }
+ let punct: Token![,] = input.parse()?;
+ inputs.push_punct(punct);
+ }
+
+ let or2_token: Token![|] = input.parse()?;
+
+ let (output, body) = if input.peek(Token![->]) {
+ let arrow_token: Token![->] = input.parse()?;
+ let ty: Type = input.parse()?;
+ let body: Block = input.parse()?;
+ let output = ReturnType::Type(arrow_token, Box::new(ty));
+ let block = Expr::Block(ExprBlock {
+ attrs: Vec::new(),
+ label: None,
+ block: body,
+ });
+ (output, block)
+ } else {
+ let body = ambiguous_expr(input, allow_struct)?;
+ (ReturnType::Default, body)
+ };
+
+ Ok(ExprClosure {
+ attrs: Vec::new(),
+ asyncness,
+ movability,
+ capture,
+ or1_token,
+ inputs,
+ or2_token,
+ output,
+ body: Box::new(body),
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_async(input: ParseStream) -> Result<ExprAsync> {
+ Ok(ExprAsync {
+ attrs: Vec::new(),
+ async_token: input.parse()?,
+ capture: input.parse()?,
+ block: input.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn closure_arg(input: ParseStream) -> Result<Pat> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let mut pat: Pat = input.parse()?;
+
+ if input.peek(Token![:]) {
+ Ok(Pat::Type(PatType {
+ attrs,
+ pat: Box::new(pat),
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ }))
+ } else {
+ match &mut pat {
+ Pat::Box(pat) => pat.attrs = attrs,
+ Pat::Ident(pat) => pat.attrs = attrs,
+ Pat::Lit(pat) => pat.attrs = attrs,
+ Pat::Macro(pat) => pat.attrs = attrs,
+ Pat::Or(pat) => pat.attrs = attrs,
+ Pat::Path(pat) => pat.attrs = attrs,
+ Pat::Range(pat) => pat.attrs = attrs,
+ Pat::Reference(pat) => pat.attrs = attrs,
+ Pat::Rest(pat) => pat.attrs = attrs,
+ Pat::Slice(pat) => pat.attrs = attrs,
+ Pat::Struct(pat) => pat.attrs = attrs,
+ Pat::Tuple(pat) => pat.attrs = attrs,
+ Pat::TupleStruct(pat) => pat.attrs = attrs,
+ Pat::Type(_) => unreachable!(),
+ Pat::Verbatim(_) => {}
+ Pat::Wild(pat) => pat.attrs = attrs,
+ Pat::__Nonexhaustive => unreachable!(),
+ }
+ Ok(pat)
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprWhile {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let label: Option<Label> = input.parse()?;
+ let while_token: Token![while] = input.parse()?;
+ let cond = expr_no_struct(input)?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprWhile {
+ attrs: inner_attrs,
+ label,
+ while_token,
+ cond: Box::new(cond),
+ body: Block { brace_token, stmts },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for Label {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Label {
+ name: input.parse()?,
+ colon_token: input.parse()?,
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for Option<Label> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Lifetime) {
+ input.parse().map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_continue(input: ParseStream) -> Result<ExprContinue> {
+ Ok(ExprContinue {
+ attrs: Vec::new(),
+ continue_token: input.parse()?,
+ label: input.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_break(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprBreak> {
+ Ok(ExprBreak {
+ attrs: Vec::new(),
+ break_token: input.parse()?,
+ label: input.parse()?,
+ expr: {
+ if input.is_empty()
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || !allow_struct.0 && input.peek(token::Brace)
+ {
+ None
+ } else {
+ let expr = ambiguous_expr(input, allow_struct)?;
+ Some(Box::new(expr))
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_ret(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprReturn> {
+ Ok(ExprReturn {
+ attrs: Vec::new(),
+ return_token: input.parse()?,
+ expr: {
+ if input.is_empty() || input.peek(Token![,]) || input.peek(Token![;]) {
+ None
+ } else {
+ // NOTE: return is greedy and eats blocks after it even when in a
+ // position where structs are not allowed, such as in if statement
+ // conditions. For example:
+ //
+ // if return { println!("A") } {} // Prints "A"
+ let expr = ambiguous_expr(input, allow_struct)?;
+ Some(Box::new(expr))
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for FieldValue {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let member: Member = input.parse()?;
+ let (colon_token, value) = if input.peek(Token![:]) || !member.is_named() {
+ let colon_token: Token![:] = input.parse()?;
+ let value: Expr = input.parse()?;
+ (Some(colon_token), value)
+ } else if let Member::Named(ident) = &member {
+ let value = Expr::Path(ExprPath {
+ attrs: Vec::new(),
+ qself: None,
+ path: Path::from(ident.clone()),
+ });
+ (None, value)
+ } else {
+ unreachable!()
+ };
+
+ Ok(FieldValue {
+ attrs,
+ member,
+ colon_token,
+ expr: value,
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_struct_helper(
+ input: ParseStream,
+ outer_attrs: Vec<Attribute>,
+ path: Path,
+ ) -> Result<ExprStruct> {
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let attrs = private::attrs(outer_attrs, inner_attrs);
+
+ let mut fields = Punctuated::new();
+ while !content.is_empty() {
+ if content.peek(Token![..]) {
+ return Ok(ExprStruct {
+ attrs,
+ brace_token,
+ path,
+ fields,
+ dot2_token: Some(content.parse()?),
+ rest: Some(Box::new(content.parse()?)),
+ });
+ }
+
+ fields.push(content.parse()?);
+ if !content.peek(Token![,]) {
+ break;
+ }
+ let punct: Token![,] = content.parse()?;
+ fields.push_punct(punct);
+ }
+
+ Ok(ExprStruct {
+ attrs,
+ brace_token,
+ path,
+ fields,
+ dot2_token: None,
+ rest: None,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_unsafe(input: ParseStream) -> Result<ExprUnsafe> {
+ let unsafe_token: Token![unsafe] = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprUnsafe {
+ attrs: inner_attrs,
+ unsafe_token,
+ block: Block { brace_token, stmts },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ pub fn expr_block(input: ParseStream) -> Result<ExprBlock> {
+ let label: Option<Label> = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprBlock {
+ attrs: inner_attrs,
+ label,
+ block: Block { brace_token, stmts },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_range(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprRange> {
+ Ok(ExprRange {
+ attrs: Vec::new(),
+ from: None,
+ limits: input.parse()?,
+ to: {
+ if input.is_empty()
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || !allow_struct.0 && input.peek(token::Brace)
+ {
+ None
+ } else {
+ let to = ambiguous_expr(input, allow_struct)?;
+ Some(Box::new(to))
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for RangeLimits {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![..=]) {
+ input.parse().map(RangeLimits::Closed)
+ } else if lookahead.peek(Token![...]) {
+ let dot3: Token![...] = input.parse()?;
+ Ok(RangeLimits::Closed(Token![..=](dot3.spans)))
+ } else if lookahead.peek(Token![..]) {
+ input.parse().map(RangeLimits::HalfOpen)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ impl Parse for ExprPath {
+ fn parse(input: ParseStream) -> Result<Self> {
+ #[cfg(not(feature = "full"))]
+ let attrs = Vec::new();
+ #[cfg(feature = "full")]
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ let (qself, path) = path::parsing::qpath(input, true)?;
+
+ Ok(ExprPath { attrs, qself, path })
+ }
+ }
+
+ impl Parse for Member {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Ident) {
+ input.parse().map(Member::Named)
+ } else if input.peek(LitInt) {
+ input.parse().map(Member::Unnamed)
+ } else {
+ Err(input.error("expected identifier or integer"))
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for Arm {
+ fn parse(input: ParseStream) -> Result<Arm> {
+ let requires_comma;
+ Ok(Arm {
+ attrs: input.call(Attribute::parse_outer)?,
+ pat: {
+ let leading_vert: Option<Token![|]> = input.parse()?;
+ let pat: Pat = input.parse()?;
+ if leading_vert.is_some() || input.peek(Token![|]) {
+ let mut cases = Punctuated::new();
+ cases.push_value(pat);
+ while input.peek(Token![|]) {
+ let punct = input.parse()?;
+ cases.push_punct(punct);
+ let pat: Pat = input.parse()?;
+ cases.push_value(pat);
+ }
+ Pat::Or(PatOr {
+ attrs: Vec::new(),
+ leading_vert,
+ cases,
+ })
+ } else {
+ pat
+ }
+ },
+ guard: {
+ if input.peek(Token![if]) {
+ let if_token: Token![if] = input.parse()?;
+ let guard: Expr = input.parse()?;
+ Some((if_token, Box::new(guard)))
+ } else {
+ None
+ }
+ },
+ fat_arrow_token: input.parse()?,
+ body: {
+ let body = input.call(expr_early)?;
+ requires_comma = requires_terminator(&body);
+ Box::new(body)
+ },
+ comma: {
+ if requires_comma && !input.is_empty() {
+ Some(input.parse()?)
+ } else {
+ input.parse()?
+ }
+ },
+ })
+ }
+ }
+
+ impl Parse for Index {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lit: LitInt = input.parse()?;
+ if lit.suffix().is_empty() {
+ Ok(Index {
+ index: lit
+ .base10_digits()
+ .parse()
+ .map_err(|err| Error::new(lit.span(), err))?,
+ span: lit.span(),
+ })
+ } else {
+ Err(Error::new(lit.span(), "expected unsuffixed integer"))
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Member {
+ fn is_named(&self) -> bool {
+ match *self {
+ Member::Named(_) => true,
+ Member::Unnamed(_) => false,
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+pub(crate) mod printing {
+ use super::*;
+
+ use proc_macro2::{Literal, TokenStream};
+ use quote::{ToTokens, TokenStreamExt};
+
+ #[cfg(feature = "full")]
+ use crate::attr::FilterAttrs;
+ #[cfg(feature = "full")]
+ use crate::print::TokensOrDefault;
+
+ // If the given expression is a bare `ExprStruct`, wraps it in parenthesis
+ // before appending it to `TokenStream`.
+ #[cfg(feature = "full")]
+ fn wrap_bare_struct(tokens: &mut TokenStream, e: &Expr) {
+ if let Expr::Struct(_) = *e {
+ token::Paren::default().surround(tokens, |tokens| {
+ e.to_tokens(tokens);
+ });
+ } else {
+ e.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ pub(crate) fn outer_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) {
+ tokens.append_all(attrs.outer());
+ }
+
+ #[cfg(feature = "full")]
+ fn inner_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) {
+ tokens.append_all(attrs.inner());
+ }
+
+ #[cfg(not(feature = "full"))]
+ pub(crate) fn outer_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {}
+
+ #[cfg(not(feature = "full"))]
+ fn inner_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {}
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBox {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.box_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprArray {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.elems.to_tokens(tokens);
+ })
+ }
+ }
+
+ impl ToTokens for ExprCall {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.func.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMethodCall {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.receiver.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.method.to_tokens(tokens);
+ self.turbofish.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for MethodTurbofish {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.colon2_token.to_tokens(tokens);
+ self.lt_token.to_tokens(tokens);
+ self.args.to_tokens(tokens);
+ self.gt_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for GenericMethodArgument {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ GenericMethodArgument::Type(t) => t.to_tokens(tokens),
+ GenericMethodArgument::Const(c) => c.to_tokens(tokens),
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.elems.to_tokens(tokens);
+ // If we only have one argument, we need a trailing comma to
+ // distinguish ExprTuple from ExprParen.
+ if self.elems.len() == 1 && !self.elems.trailing_punct() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ })
+ }
+ }
+
+ impl ToTokens for ExprBinary {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.op.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprUnary {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.op.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprLit {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.lit.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprCast {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.as_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn maybe_wrap_else(tokens: &mut TokenStream, else_: &Option<(Token![else], Box<Expr>)>) {
+ if let Some((else_token, else_)) = else_ {
+ else_token.to_tokens(tokens);
+
+ // If we are not one of the valid expressions to exist in an else
+ // clause, wrap ourselves in a block.
+ match **else_ {
+ Expr::If(_) | Expr::Block(_) => {
+ else_.to_tokens(tokens);
+ }
+ _ => {
+ token::Brace::default().surround(tokens, |tokens| {
+ else_.to_tokens(tokens);
+ });
+ }
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprLet {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.let_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprIf {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.if_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
+ self.then_branch.to_tokens(tokens);
+ maybe_wrap_else(tokens, &self.else_branch);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprWhile {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.while_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprForLoop {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.for_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ self.in_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprLoop {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.loop_token.to_tokens(tokens);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMatch {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.match_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ for (i, arm) in self.arms.iter().enumerate() {
+ arm.to_tokens(tokens);
+ // Ensure that we have a comma after a non-block arm, except
+ // for the last one.
+ let is_last = i == self.arms.len() - 1;
+ if !is_last && requires_terminator(&arm.body) && arm.comma.is_none() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ }
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAsync {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.async_token.to_tokens(tokens);
+ self.capture.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAwait {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.base.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.await_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTryBlock {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.try_token.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprYield {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.yield_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprClosure {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.asyncness.to_tokens(tokens);
+ self.movability.to_tokens(tokens);
+ self.capture.to_tokens(tokens);
+ self.or1_token.to_tokens(tokens);
+ self.inputs.to_tokens(tokens);
+ self.or2_token.to_tokens(tokens);
+ self.output.to_tokens(tokens);
+ self.body.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprUnsafe {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.unsafe_token.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBlock {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAssign {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAssignOp {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.op.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprField {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.base.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.member.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Member {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Member::Named(ident) => ident.to_tokens(tokens),
+ Member::Unnamed(index) => index.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for Index {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let mut lit = Literal::i64_unsuffixed(i64::from(self.index));
+ lit.set_span(self.span);
+ tokens.append(lit);
+ }
+ }
+
+ impl ToTokens for ExprIndex {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ self.index.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprRange {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.from.to_tokens(tokens);
+ match &self.limits {
+ RangeLimits::HalfOpen(t) => t.to_tokens(tokens),
+ RangeLimits::Closed(t) => t.to_tokens(tokens),
+ }
+ self.to.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprPath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ private::print_path(tokens, &self.qself, &self.path);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprReference {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.and_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBreak {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.break_token.to_tokens(tokens);
+ self.label.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprContinue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.continue_token.to_tokens(tokens);
+ self.label.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprReturn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.return_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.mac.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.path.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.fields.to_tokens(tokens);
+ if self.rest.is_some() {
+ TokensOrDefault(&self.dot2_token).to_tokens(tokens);
+ self.rest.to_tokens(tokens);
+ }
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprRepeat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ self.len.to_tokens(tokens);
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprGroup {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.group_token.surround(tokens, |tokens| {
+ self.expr.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for ExprParen {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTry {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.question_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Label {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.name.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for FieldValue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.member.to_tokens(tokens);
+ if let Some(colon_token) = &self.colon_token {
+ colon_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Arm {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.pat.to_tokens(tokens);
+ if let Some((if_token, guard)) = &self.guard {
+ if_token.to_tokens(tokens);
+ guard.to_tokens(tokens);
+ }
+ self.fat_arrow_token.to_tokens(tokens);
+ self.body.to_tokens(tokens);
+ self.comma.to_tokens(tokens);
+ }
+ }
+}