// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(all(feature = "printing", feature = "full"))]use crate::attr::{AttrStyle, Attribute};#[cfg(feature = "printing")]use crate::expr::Expr;#[cfg(all(feature = "printing", feature = "full"))]use crate::expr::{ ExprArray, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprCall, ExprConst, ExprContinue, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile, ExprYield,};use crate::op::BinOp;#[cfg(all(feature = "printing", feature = "full"))]use crate::ty::ReturnType;use std::cmp::Ordering; // Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedencepub(crate) enum Precedence { // return, break, closures Jump, // = += -= *= /= %= &= |= ^= <<= >>= Assign, // .. ..= Range, // || Or, // && And, // let #[cfg(feature = "printing")] Let, // == != < > <= >= Compare, // | BitOr, // ^ BitXor, // & BitAnd, // << >> Shift, // + - Sum, // * / % Product, // as Cast, // unary - * ! & &mut #[cfg(feature = "printing")] Prefix, // paths, loops, function calls, array indexing, field expressions, method calls #[cfg(feature = "printing")] Unambiguous,} impl Precedence { pub(crate) const MIN: Self = Precedence::Jump; pub(crate) fn of_binop(op: &BinOp) -> Self { match op { BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum, BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Product, 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::AddAssign(_) | BinOp::SubAssign(_) | BinOp::MulAssign(_) | BinOp::DivAssign(_) | BinOp::RemAssign(_) | BinOp::BitXorAssign(_) | BinOp::BitAndAssign(_) | BinOp::BitOrAssign(_) | BinOp::ShlAssign(_) | BinOp::ShrAssign(_) => Precedence::Assign, } } #[cfg(feature = "printing")] pub(crate) fn of(e: &Expr) -> Self { #[cfg(feature = "full")] fn prefix_attrs(attrs: &[Attribute]) -> Precedence { for attr in attrs { if let AttrStyle::Outer = attr.style { return Precedence::Prefix; } } Precedence::Unambiguous } match e { #[cfg(feature = "full")] Expr::Closure(e) => match e.output { ReturnType::Default => Precedence::Jump, ReturnType::Type(..) => prefix_attrs(&e.attrs), }, #[cfg(feature = "full")] Expr::Break(ExprBreak { expr, .. }) | Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr { Some(_) => Precedence::Jump, None => Precedence::Unambiguous, }, Expr::Assign(_) => Precedence::Assign, Expr::Range(_) => Precedence::Range, Expr::Binary(e) => Precedence::of_binop(&e.op), Expr::Let(_) => Precedence::Let, Expr::Cast(_) => Precedence::Cast, Expr::RawAddr(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix, #[cfg(feature = "full")] Expr::Array(ExprArray { attrs, .. }) | Expr::Async(ExprAsync { attrs, .. }) | Expr::Await(ExprAwait { attrs, .. }) | Expr::Block(ExprBlock { attrs, .. }) | Expr::Call(ExprCall { attrs, .. }) | Expr::Const(ExprConst { attrs, .. }) | Expr::Continue(ExprContinue { attrs, .. }) | Expr::Field(ExprField { attrs, .. }) | Expr::ForLoop(ExprForLoop { attrs, .. }) | Expr::Group(ExprGroup { attrs, .. }) | Expr::If(ExprIf { attrs, .. }) | Expr::Index(ExprIndex { attrs, .. }) | Expr::Infer(ExprInfer { attrs, .. }) | Expr::Lit(ExprLit { attrs, .. }) | Expr::Loop(ExprLoop { attrs, .. }) | Expr::Macro(ExprMacro { attrs, .. }) | Expr::Match(ExprMatch { attrs, .. }) | Expr::MethodCall(ExprMethodCall { attrs, .. }) | Expr::Paren(ExprParen { attrs, .. }) | Expr::Path(ExprPath { attrs, .. }) | Expr::Repeat(ExprRepeat { attrs, .. }) | Expr::Struct(ExprStruct { attrs, .. }) | Expr::Try(ExprTry { attrs, .. }) | Expr::TryBlock(ExprTryBlock { attrs, .. }) | Expr::Tuple(ExprTuple { attrs, .. }) | Expr::Unsafe(ExprUnsafe { attrs, .. }) | Expr::While(ExprWhile { attrs, .. }) => prefix_attrs(attrs), #[cfg(not(feature = "full"))] Expr::Array(_) | Expr::Async(_) | Expr::Await(_) | Expr::Block(_) | Expr::Call(_) | Expr::Const(_) | Expr::Continue(_) | Expr::Field(_) | Expr::ForLoop(_) | Expr::Group(_) | Expr::If(_) | Expr::Index(_) | Expr::Infer(_) | Expr::Lit(_) | Expr::Loop(_) | Expr::Macro(_) | Expr::Match(_) | Expr::MethodCall(_) | Expr::Paren(_) | Expr::Path(_) | Expr::Repeat(_) | Expr::Struct(_) | Expr::Try(_) | Expr::TryBlock(_) | Expr::Tuple(_) | Expr::Unsafe(_) | Expr::While(_) => Precedence::Unambiguous, Expr::Verbatim(_) => Precedence::Unambiguous, #[cfg(not(feature = "full"))] Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => unreachable!(), } }} impl Copy for Precedence {} impl Clone for Precedence { fn clone(&self) -> Self { *self }} impl PartialEq for Precedence { fn eq(&self, other: &Self) -> bool { *self as u8 == *other as u8 }} impl PartialOrd for Precedence { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { let this = *self as u8; let other = *other as u8; Some(this.cmp(&other)) }}
// SPDX-License-Identifier: Apache-2.0 OR MIT
#[cfg(all(feature = "printing", feature = "full"))]
use crate::attr::{AttrStyle, Attribute};
#[cfg(feature = "printing")]
use crate::expr::Expr;
#[cfg(all(feature = "printing", feature = "full"))]
use crate::expr::{
ExprArray, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprCall, ExprConst, ExprContinue,
ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, ExprLit, ExprLoop, ExprMacro,
ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprReturn, ExprStruct, ExprTry,
ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile, ExprYield,
};
use crate::op::BinOp;
#[cfg(all(feature = "printing", feature = "full"))]
use crate::ty::ReturnType;
use std::cmp::Ordering;
// Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence
pub(crate) enum Precedence {
// return, break, closures
Jump,
// = += -= *= /= %= &= |= ^= <<= >>=
Assign,
// .. ..=
Range,
// ||
Or,
// &&
And,
// let
#[cfg(feature = "printing")]
Let,
// == != < > <= >=
Compare,
// |
BitOr,
// ^
BitXor,
// &
BitAnd,
// << >>
Shift,
// + -
Sum,
// * / %
Product,
// as
Cast,
// unary - * ! & &mut
#[cfg(feature = "printing")]
Prefix,
// paths, loops, function calls, array indexing, field expressions, method calls
#[cfg(feature = "printing")]
Unambiguous,
}
impl Precedence {
pub(crate) const MIN: Self = Precedence::Jump;
pub(crate) fn of_binop(op: &BinOp) -> Self {
match op {
BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum,
BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Product,
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::AddAssign(_)
| BinOp::SubAssign(_)
| BinOp::MulAssign(_)
| BinOp::DivAssign(_)
| BinOp::RemAssign(_)
| BinOp::BitXorAssign(_)
| BinOp::BitAndAssign(_)
| BinOp::BitOrAssign(_)
| BinOp::ShlAssign(_)
| BinOp::ShrAssign(_) => Precedence::Assign,
}
}
#[cfg(feature = "printing")]
pub(crate) fn of(e: &Expr) -> Self {
#[cfg(feature = "full")]
fn prefix_attrs(attrs: &[Attribute]) -> Precedence {
for attr in attrs {
if let AttrStyle::Outer = attr.style {
return Precedence::Prefix;
}
}
Precedence::Unambiguous
}
match e {
#[cfg(feature = "full")]
Expr::Closure(e) => match e.output {
ReturnType::Default => Precedence::Jump,
ReturnType::Type(..) => prefix_attrs(&e.attrs),
},
#[cfg(feature = "full")]
Expr::Break(ExprBreak { expr, .. })
| Expr::Return(ExprReturn { expr, .. })
| Expr::Yield(ExprYield { expr, .. }) => match expr {
Some(_) => Precedence::Jump,
None => Precedence::Unambiguous,
},
Expr::Assign(_) => Precedence::Assign,
Expr::Range(_) => Precedence::Range,
Expr::Binary(e) => Precedence::of_binop(&e.op),
Expr::Let(_) => Precedence::Let,
Expr::Cast(_) => Precedence::Cast,
Expr::RawAddr(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix,
#[cfg(feature = "full")]
Expr::Array(ExprArray { attrs, .. })
| Expr::Async(ExprAsync { attrs, .. })
| Expr::Await(ExprAwait { attrs, .. })
| Expr::Block(ExprBlock { attrs, .. })
| Expr::Call(ExprCall { attrs, .. })
| Expr::Const(ExprConst { attrs, .. })
| Expr::Continue(ExprContinue { attrs, .. })
| Expr::Field(ExprField { attrs, .. })
| Expr::ForLoop(ExprForLoop { attrs, .. })
| Expr::Group(ExprGroup { attrs, .. })
| Expr::If(ExprIf { attrs, .. })
| Expr::Index(ExprIndex { attrs, .. })
| Expr::Infer(ExprInfer { attrs, .. })
| Expr::Lit(ExprLit { attrs, .. })
| Expr::Loop(ExprLoop { attrs, .. })
| Expr::Macro(ExprMacro { attrs, .. })
| Expr::Match(ExprMatch { attrs, .. })
| Expr::MethodCall(ExprMethodCall { attrs, .. })
| Expr::Paren(ExprParen { attrs, .. })
| Expr::Path(ExprPath { attrs, .. })
| Expr::Repeat(ExprRepeat { attrs, .. })
| Expr::Struct(ExprStruct { attrs, .. })
| Expr::Try(ExprTry { attrs, .. })
| Expr::TryBlock(ExprTryBlock { attrs, .. })
| Expr::Tuple(ExprTuple { attrs, .. })
| Expr::Unsafe(ExprUnsafe { attrs, .. })
| Expr::While(ExprWhile { attrs, .. }) => prefix_attrs(attrs),
#[cfg(not(feature = "full"))]
Expr::Array(_)
| Expr::Async(_)
| Expr::Await(_)
| Expr::Block(_)
| Expr::Call(_)
| Expr::Const(_)
| Expr::Continue(_)
| Expr::Field(_)
| Expr::ForLoop(_)
| Expr::Group(_)
| Expr::If(_)
| Expr::Index(_)
| Expr::Infer(_)
| Expr::Lit(_)
| Expr::Loop(_)
| Expr::Macro(_)
| Expr::Match(_)
| Expr::MethodCall(_)
| Expr::Paren(_)
| Expr::Path(_)
| Expr::Repeat(_)
| Expr::Struct(_)
| Expr::Try(_)
| Expr::TryBlock(_)
| Expr::Tuple(_)
| Expr::Unsafe(_)
| Expr::While(_) => Precedence::Unambiguous,
Expr::Verbatim(_) => Precedence::Unambiguous,
#[cfg(not(feature = "full"))]
Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => unreachable!(),
}
}
}
impl Copy for Precedence {}
impl Clone for Precedence {
fn clone(&self) -> Self {
*self
}
}
impl PartialEq for Precedence {
fn eq(&self, other: &Self) -> bool {
*self as u8 == *other as u8
}
}
impl PartialOrd for Precedence {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let this = *self as u8;
let other = *other as u8;
Some(this.cmp(&other))
}
}