Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose can_begin_expr as Expr::peek #1778

Merged
merged 1 commit into from
Nov 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading