use syn::{ AttrStyle, Attribute, BinOp, Expr, ExprArray, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprCall, ExprConst, ExprContinue, ExprField, ExprForLoop, ExprIf, ExprIndex, ExprInfer, ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile, ExprYield, ReturnType, }; // Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence #[derive(Copy, Clone, PartialEq, PartialOrd)] pub enum Precedence { // return, break, closures Jump, // = += -= *= /= %= &= |= ^= <<= >>= Assign, // .. ..= Range, // || Or, // && And, // let Let, // == != < > <= >= Compare, // | BitOr, // ^ BitXor, // & BitAnd, // << >> Shift, // + - Sum, // * / % Product, // as Cast, // unary - * ! & &mut Prefix, // paths, loops, function calls, array indexing, field expressions, method calls Unambiguous, } impl Precedence { pub(crate) const MIN: Self = Precedence::Jump; pub(crate) fn of_binop(op: &BinOp) -> Self { match op { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] 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, _ => Precedence::MIN, } } pub(crate) fn of(e: &Expr) -> Self { fn prefix_attrs(attrs: &[Attribute]) -> Precedence { for attr in attrs { if let AttrStyle::Outer = attr.style { return Precedence::Prefix; } } Precedence::Unambiguous } match e { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] Expr::Closure(e) => match e.output { ReturnType::Default => Precedence::Jump, ReturnType::Type(..) => prefix_attrs(&e.attrs), }, 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, 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::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), Expr::Group(e) => Precedence::of(&e.expr), Expr::Verbatim(_) => Precedence::Unambiguous, _ => Precedence::Unambiguous, } } }