Enum syn::Expr

source ·
#[non_exhaustive]
pub enum Expr {
Show 40 variants Array(ExprArray), Assign(ExprAssign), AssignOp(ExprAssignOp), Async(ExprAsync), Await(ExprAwait), Binary(ExprBinary), Block(ExprBlock), Box(ExprBox), Break(ExprBreak), Call(ExprCall), Cast(ExprCast), Closure(ExprClosure), Continue(ExprContinue), Field(ExprField), ForLoop(ExprForLoop), Group(ExprGroup), If(ExprIf), Index(ExprIndex), Let(ExprLet), Lit(ExprLit), Loop(ExprLoop), Macro(ExprMacro), Match(ExprMatch), MethodCall(ExprMethodCall), Paren(ExprParen), Path(ExprPath), Range(ExprRange), Reference(ExprReference), Repeat(ExprRepeat), Return(ExprReturn), Struct(ExprStruct), Try(ExprTry), TryBlock(ExprTryBlock), Tuple(ExprTuple), Type(ExprType), Unary(ExprUnary), Unsafe(ExprUnsafe), Verbatim(TokenStream), While(ExprWhile), Yield(ExprYield),
}
Available on crate features full or derive only.
Expand description

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.

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.

// 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.

// 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.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Array(ExprArray)

A slice literal expression: [a, b, c, d].

§

Assign(ExprAssign)

An assignment expression: a = compute().

§

AssignOp(ExprAssignOp)

A compound assignment expression: counter += 1.

§

Async(ExprAsync)

An async block: async { ... }.

§

Await(ExprAwait)

An await expression: fut.await.

§

Binary(ExprBinary)

A binary operation: a + b, a * b.

§

Block(ExprBlock)

A blocked scope: { ... }.

§

Box(ExprBox)

A box expression: box f.

§

Break(ExprBreak)

A break, with an optional label to break and an optional expression.

§

Call(ExprCall)

A function call expression: invoke(a, b).

§

Cast(ExprCast)

A cast expression: foo as f64.

§

Closure(ExprClosure)

A closure expression: |a, b| a + b.

§

Continue(ExprContinue)

A continue, with an optional label.

§

Field(ExprField)

Access of a named struct field (obj.k) or unnamed tuple struct field (obj.0).

§

ForLoop(ExprForLoop)

A for loop: for pat in expr { ... }.

§

Group(ExprGroup)

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.

§

If(ExprIf)

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.

§

Index(ExprIndex)

A square bracketed indexing expression: vector[2].

§

Let(ExprLet)

A let guard: let Some(x) = opt.

§

Lit(ExprLit)

A literal in place of an expression: 1, "foo".

§

Loop(ExprLoop)

Conditionless loop: loop { ... }.

§

Macro(ExprMacro)

A macro invocation expression: format!("{}", q).

§

Match(ExprMatch)

A match expression: match n { Some(n) => {}, None => {} }.

§

MethodCall(ExprMethodCall)

A method call expression: x.foo::<T>(a, b).

§

Paren(ExprParen)

A parenthesized expression: (a + b).

§

Path(ExprPath)

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.

§

Range(ExprRange)

A range expression: 1..2, 1.., ..2, 1..=2, ..=2.

§

Reference(ExprReference)

A referencing operation: &a or &mut a.

§

Repeat(ExprRepeat)

An array literal constructed from one repeated element: [0u8; N].

§

Return(ExprReturn)

A return, with an optional value to be returned.

§

Struct(ExprStruct)

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 }.

§

Try(ExprTry)

A try-expression: expr?.

§

TryBlock(ExprTryBlock)

A try block: try { ... }.

§

Tuple(ExprTuple)

A tuple expression: (a, b, c, d).

§

Type(ExprType)

A type ascription expression: foo: f64.

§

Unary(ExprUnary)

A unary operation: !x, *x.

§

Unsafe(ExprUnsafe)

An unsafe block: unsafe { ... }.

§

Verbatim(TokenStream)

Tokens in expression position not interpreted by Syn.

§

While(ExprWhile)

A while loop: while expr { ... }.

§

Yield(ExprYield)

A yield expression: yield expr.

Implementations§

Available on crate features full and parsing only.

An alternative to the primary Expr::parse parser (from the Parse trait) for ambiguous syntactic positions in which a trailing brace should not be taken as part of the expression.

Rust grammar has an ambiguity where braces sometimes turn a path expression into a struct initialization and sometimes do not. In the following code, the expression S {} is one expression. Presumably there is an empty struct struct S {} defined somewhere which it is instantiating.

let _ = *S {};

// parsed by rustc as: `*(S {})`

We would want to parse the above using Expr::parse after the = token.

But in the following, S {} is not a struct init expression.

if *S {} {}

// parsed by rustc as:
//
//    if (*S) {
//        /* empty block */
//    }
//    {
//        /* another empty block */
//    }

For that reason we would want to parse if-conditions using Expr::parse_without_eager_brace after the if token. Same for similar syntactic positions such as the condition expr after a while token or the expr at the top of a match.

The Rust grammar’s choices around which way this ambiguity is resolved at various syntactic positions is fairly arbitrary. Really either parse behavior could work in most positions, and language designers just decide each case based on which is more likely to be what the programmer had in mind most of the time.

if return S {} {}

// parsed by rustc as:
//
//    if (return (S {})) {
//    }
//
// but could equally well have been this other arbitrary choice:
//
//    if (return S) {
//    }
//    {}

Note the grammar ambiguity on trailing braces is distinct from precedence and is not captured by assigning a precedence level to the braced struct init expr in relation to other operators. This can be illustrated by return 0..S {} vs match 0..S {}. The former parses as return (0..(S {})) implying tighter precedence for struct init than .., while the latter parses as match (0..S) {} implying tighter precedence for .. than struct init, a contradiction.

Examples found in repository?
src/expr.rs (line 2263)
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
        fn parse(input: ParseStream) -> Result<Self> {
            let mut attrs = input.call(Attribute::parse_outer)?;
            let match_token: Token![match] = input.parse()?;
            let expr = Expr::parse_without_eager_brace(input)?;

            let content;
            let brace_token = braced!(content in input);
            attr::parsing::parse_inner(&content, &mut attrs)?;

            let mut arms = Vec::new();
            while !content.is_empty() {
                arms.push(content.call(Arm::parse)?);
            }

            Ok(ExprMatch {
                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"))]
                #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
                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! {
        ExprAssign, Assign, "expected assignment expression",
        ExprAssignOp, AssignOp, "expected compound assignment expression",
        ExprAwait, Await, "expected await expression",
        ExprBinary, Binary, "expected binary operation",
        ExprCall, Call, "expected function call expression",
        ExprCast, Cast, "expected cast expression",
        ExprField, Field, "expected struct field access",
        ExprIndex, Index, "expected indexing expression",
        ExprMethodCall, MethodCall, "expected method call expression",
        ExprRange, Range, "expected range expression",
        ExprTry, Try, "expected try expression",
        ExprTuple, Tuple, "expected tuple expression",
        ExprType, Type, "expected type ascription expression",
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprBox {
        fn parse(input: ParseStream) -> Result<Self> {
            let attrs = Vec::new();
            let allow_struct = AllowStruct(true);
            expr_box(input, attrs, allow_struct)
        }
    }

    #[cfg(feature = "full")]
    fn expr_box(
        input: ParseStream,
        attrs: Vec<Attribute>,
        allow_struct: AllowStruct,
    ) -> Result<ExprBox> {
        Ok(ExprBox {
            attrs,
            box_token: input.parse()?,
            expr: Box::new(unary_expr(input, allow_struct)?),
        })
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprUnary {
        fn parse(input: ParseStream) -> Result<Self> {
            let attrs = Vec::new();
            let allow_struct = AllowStruct(true);
            expr_unary(input, attrs, allow_struct)
        }
    }

    #[cfg(feature = "full")]
    fn expr_unary(
        input: ParseStream,
        attrs: Vec<Attribute>,
        allow_struct: AllowStruct,
    ) -> Result<ExprUnary> {
        Ok(ExprUnary {
            attrs,
            op: input.parse()?,
            expr: Box::new(unary_expr(input, allow_struct)?),
        })
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprClosure {
        fn parse(input: ParseStream) -> Result<Self> {
            let allow_struct = AllowStruct(true);
            expr_closure(input, allow_struct)
        }
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprReference {
        fn parse(input: ParseStream) -> Result<Self> {
            let allow_struct = AllowStruct(true);
            Ok(ExprReference {
                attrs: Vec::new(),
                and_token: input.parse()?,
                raw: Reserved::default(),
                mutability: input.parse()?,
                expr: Box::new(unary_expr(input, allow_struct)?),
            })
        }
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprBreak {
        fn parse(input: ParseStream) -> Result<Self> {
            let allow_struct = AllowStruct(true);
            expr_break(input, allow_struct)
        }
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprReturn {
        fn parse(input: ParseStream) -> Result<Self> {
            let allow_struct = AllowStruct(true);
            expr_ret(input, allow_struct)
        }
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprTryBlock {
        fn parse(input: ParseStream) -> Result<Self> {
            Ok(ExprTryBlock {
                attrs: Vec::new(),
                try_token: input.parse()?,
                block: input.parse()?,
            })
        }
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprYield {
        fn parse(input: ParseStream) -> Result<Self> {
            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 movability: Option<Token![static]> = input.parse()?;
        let asyncness: Option<Token![async]> = input.parse()?;
        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(),
            movability,
            asyncness,
            capture,
            or1_token,
            inputs,
            or2_token,
            output,
            body: Box::new(body),
        })
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprAsync {
        fn parse(input: ParseStream) -> Result<Self> {
            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,

                #[cfg(syn_no_non_exhaustive)]
                _ => unreachable!(),
            }
            Ok(pat)
        }
    }

    #[cfg(feature = "full")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
    impl Parse for ExprWhile {
        fn parse(input: ParseStream) -> Result<Self> {
            let mut attrs = input.call(Attribute::parse_outer)?;
            let label: Option<Label> = input.parse()?;
            let while_token: Token![while] = input.parse()?;
            let cond = Expr::parse_without_eager_brace(input)?;

            let content;
            let brace_token = braced!(content in input);
            attr::parsing::parse_inner(&content, &mut attrs)?;
            let stmts = content.call(Block::parse_within)?;

            Ok(ExprWhile {
                attrs,
                label,
                while_token,
                cond: Box::new(cond),
                body: Block { brace_token, stmts },
            })
        }

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used by ==. Read more
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason. Read more
Write self to the given TokenStream. Read more
Convert self directly into a TokenStream object. Read more
Convert self directly into a TokenStream object. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Available on crate features parsing and printing only.
Returns a Span covering the complete contents of this syntax tree node, or Span::call_site() if this node is empty. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.