Skip to content

Commit

Permalink
Merge pull request #1778 from dtolnay/exprpeek
Browse files Browse the repository at this point in the history
Expose can_begin_expr as Expr::peek
  • Loading branch information
dtolnay authored Nov 2, 2024
2 parents 12f068c + a890e9d commit ceaf4d6
Showing 1 changed file with 37 additions and 26 deletions.
63 changes: 37 additions & 26 deletions src/expr.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use crate::attr::Attribute;
#[cfg(all(feature = "parsing", feature = "full"))]
use crate::error::Result;
#[cfg(feature = "parsing")]
use crate::ext::IdentExt as _;
#[cfg(feature = "full")]
use crate::generics::BoundLifetimes;
use crate::ident::Ident;
#[cfg(feature = "full")]
#[cfg(any(feature = "parsing", feature = "full"))]
use crate::lifetime::Lifetime;
use crate::lit::Lit;
use crate::mac::Macro;
use crate::op::{BinOp, UnOp};
#[cfg(all(feature = "parsing", feature = "full"))]
#[cfg(feature = "parsing")]
use crate::parse::ParseStream;
#[cfg(feature = "full")]
use crate::pat::Pat;
Expand Down Expand Up @@ -889,6 +891,36 @@ impl Expr {
parsing::parse_with_earlier_boundary_rule(input)
}

/// Returns whether the next token in the parse stream is one that might
/// possibly form the beginning of an expr.
///
/// This classification is a load-bearing part of the grammar of some Rust
/// expressions, notably `return` and `break`. For example `return < …` will
/// never parse `<` as a binary operator regardless of what comes after,
/// because `<` is a legal starting token for an expression and so it's
/// required to be continued as a return value, such as `return <Struct as
/// Trait>::CONST`. Meanwhile `return > …` treats the `>` as a binary
/// operator because it cannot be a starting token for any Rust expression.
#[cfg(feature = "parsing")]
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
pub fn peek(input: ParseStream) -> bool {
input.peek(Ident::peek_any) // value name or keyword
|| input.peek(token::Paren) // tuple
|| input.peek(token::Bracket) // array
|| input.peek(token::Brace) // block
|| input.peek(Lit) // literal
|| input.peek(Token![!]) && !input.peek(Token![!=]) // operator not
|| input.peek(Token![-]) && !input.peek(Token![-=]) && !input.peek(Token![->]) // unary minus
|| input.peek(Token![*]) && !input.peek(Token![*=]) // dereference
|| input.peek(Token![|]) && !input.peek(Token![|=]) // closure
|| input.peek(Token![&]) && !input.peek(Token![&=]) // reference
|| input.peek(Token![..]) // range
|| input.peek(Token![<]) && !input.peek(Token![<=]) && !input.peek(Token![<<=]) // associated path
|| input.peek(Token![::]) // absolute path
|| input.peek(Lifetime) // labeled loop
|| input.peek(Token![#]) // expression attributes
}

#[cfg(all(feature = "parsing", feature = "full"))]
pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> {
match self {
Expand Down Expand Up @@ -1147,8 +1179,6 @@ pub(crate) mod parsing {
FieldValue, Index, Member,
};
#[cfg(feature = "full")]
use crate::ext::IdentExt as _;
#[cfg(feature = "full")]
use crate::generics::BoundLifetimes;
use crate::ident::Ident;
#[cfg(feature = "full")]
Expand Down Expand Up @@ -1266,25 +1296,6 @@ pub(crate) mod parsing {
}
}

#[cfg(feature = "full")]
fn can_begin_expr(input: ParseStream) -> bool {
input.peek(Ident::peek_any) // value name or keyword
|| input.peek(token::Paren) // tuple
|| input.peek(token::Bracket) // array
|| input.peek(token::Brace) // block
|| input.peek(Lit) // literal
|| input.peek(Token![!]) && !input.peek(Token![!=]) // operator not
|| input.peek(Token![-]) && !input.peek(Token![-=]) && !input.peek(Token![->]) // unary minus
|| input.peek(Token![*]) && !input.peek(Token![*=]) // dereference
|| input.peek(Token![|]) && !input.peek(Token![|=]) // closure
|| input.peek(Token![&]) && !input.peek(Token![&=]) // reference
|| input.peek(Token![..]) // range notation
|| input.peek(Token![<]) && !input.peek(Token![<=]) && !input.peek(Token![<<=]) // associated path
|| input.peek(Token![::]) // global path
|| input.peek(Lifetime) // labeled loop
|| input.peek(Token![#]) // expression attributes
}

#[cfg(feature = "full")]
fn parse_expr(
input: ParseStream,
Expand Down Expand Up @@ -2439,7 +2450,7 @@ pub(crate) mod parsing {
attrs: Vec::new(),
return_token: input.parse()?,
expr: {
if can_begin_expr(input) {
if Expr::peek(input) {
Some(input.parse()?)
} else {
None
Expand Down Expand Up @@ -2477,7 +2488,7 @@ pub(crate) mod parsing {
attrs: Vec::new(),
yield_token: input.parse()?,
expr: {
if can_begin_expr(input) {
if Expr::peek(input) {
Some(input.parse()?)
} else {
None
Expand Down Expand Up @@ -2690,7 +2701,7 @@ pub(crate) mod parsing {
}

input.advance_to(&ahead);
let expr = if can_begin_expr(input) && (allow_struct.0 || !input.peek(token::Brace)) {
let expr = if Expr::peek(input) && (allow_struct.0 || !input.peek(token::Brace)) {
Some(input.parse()?)
} else {
None
Expand Down

0 comments on commit ceaf4d6

Please sign in to comment.