use super::*; use crate::punctuated::Punctuated; 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(feature = "parsing")] use std::mem; ast_enum_of_structs! { /// A Rust expression. /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature, but most of the variants are not available unless "full" is enabled.* /// /// # 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`. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] #[non_exhaustive] pub enum Expr { /// A slice literal expression: `[a, b, c, d]`. Array(ExprArray), /// An assignment expression: `a = compute()`. Assign(ExprAssign), /// 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 `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 const block: `const { ... }`. Const(ExprConst), /// 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), /// The inferred value of a const generic argument, denoted `_`. Infer(ExprInfer), /// 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::(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 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), // For testing exhaustiveness in downstream code, use the following idiom: // // match expr { // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // // Expr::Array(expr) => {...} // Expr::Assign(expr) => {...} // ... // Expr::Yield(expr) => {...} // // _ => { /* some sane fallback */ } // } // // This way we fail your tests but don't break your library when adding // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. } } ast_struct! { /// A slice literal expression: `[a, b, c, d]`. #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct ExprArray #full { pub attrs: Vec, pub bracket_token: token::Bracket, pub elems: Punctuated, } } ast_struct! { /// An assignment expression: `a = compute()`. #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct ExprAssign #full { pub attrs: Vec, pub left: Box, pub eq_token: Token![=], pub right: Box, } } ast_struct! { /// An async block: `async { ... }`. #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct ExprAsync #full { pub attrs: Vec, pub async_token: Token![async], pub capture: Option, pub block: Block, } } ast_struct! { /// An await expression: `fut.await`. #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct ExprAwait #full { pub attrs: Vec, pub base: Box, pub dot_token: Token![.], pub await_token: Token![await], } } ast_struct! { /// A binary operation: `a + b`, `a += b`. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct ExprBinary { pub attrs: Vec, pub left: Box, pub op: BinOp, pub right: Box, } } ast_struct! { /// A blocked scope: `{ ... }`. #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct ExprBlock #full { pub attrs: Vec, pub label: Option