syn/
precedence.rs

1#[cfg(all(feature = "printing", feature = "full"))]
2use crate::attr::{AttrStyle, Attribute};
3#[cfg(feature = "printing")]
4use crate::expr::Expr;
5#[cfg(all(feature = "printing", feature = "full"))]
6use crate::expr::{
7    ExprArray, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprCall, ExprConst, ExprContinue,
8    ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, ExprLit, ExprLoop, ExprMacro,
9    ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprReturn, ExprStruct, ExprTry,
10    ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile, ExprYield,
11};
12use crate::op::BinOp;
13#[cfg(all(feature = "printing", feature = "full"))]
14use crate::ty::ReturnType;
15use std::cmp::Ordering;
16
17// Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence
18pub(crate) enum Precedence {
19    // return, break, closures
20    Jump,
21    // = += -= *= /= %= &= |= ^= <<= >>=
22    Assign,
23    // .. ..=
24    Range,
25    // ||
26    Or,
27    // &&
28    And,
29    // let
30    #[cfg(feature = "printing")]
31    Let,
32    // == != < > <= >=
33    Compare,
34    // |
35    BitOr,
36    // ^
37    BitXor,
38    // &
39    BitAnd,
40    // << >>
41    Shift,
42    // + -
43    Sum,
44    // * / %
45    Product,
46    // as
47    Cast,
48    // unary - * ! & &mut
49    #[cfg(feature = "printing")]
50    Prefix,
51    // paths, loops, function calls, array indexing, field expressions, method calls
52    #[cfg(feature = "printing")]
53    Unambiguous,
54}
55
56impl Precedence {
57    pub(crate) const MIN: Self = Precedence::Jump;
58
59    pub(crate) fn of_binop(op: &BinOp) -> Self {
60        match op {
61            BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum,
62            BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Product,
63            BinOp::And(_) => Precedence::And,
64            BinOp::Or(_) => Precedence::Or,
65            BinOp::BitXor(_) => Precedence::BitXor,
66            BinOp::BitAnd(_) => Precedence::BitAnd,
67            BinOp::BitOr(_) => Precedence::BitOr,
68            BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift,
69
70            BinOp::Eq(_)
71            | BinOp::Lt(_)
72            | BinOp::Le(_)
73            | BinOp::Ne(_)
74            | BinOp::Ge(_)
75            | BinOp::Gt(_) => Precedence::Compare,
76
77            BinOp::AddAssign(_)
78            | BinOp::SubAssign(_)
79            | BinOp::MulAssign(_)
80            | BinOp::DivAssign(_)
81            | BinOp::RemAssign(_)
82            | BinOp::BitXorAssign(_)
83            | BinOp::BitAndAssign(_)
84            | BinOp::BitOrAssign(_)
85            | BinOp::ShlAssign(_)
86            | BinOp::ShrAssign(_) => Precedence::Assign,
87        }
88    }
89
90    #[cfg(feature = "printing")]
91    pub(crate) fn of(e: &Expr) -> Self {
92        #[cfg(feature = "full")]
93        fn prefix_attrs(attrs: &[Attribute]) -> Precedence {
94            for attr in attrs {
95                if let AttrStyle::Outer = attr.style {
96                    return Precedence::Prefix;
97                }
98            }
99            Precedence::Unambiguous
100        }
101
102        match e {
103            #[cfg(feature = "full")]
104            Expr::Closure(e) => match e.output {
105                ReturnType::Default => Precedence::Jump,
106                ReturnType::Type(..) => prefix_attrs(&e.attrs),
107            },
108
109            #[cfg(feature = "full")]
110            Expr::Break(ExprBreak { expr, .. })
111            | Expr::Return(ExprReturn { expr, .. })
112            | Expr::Yield(ExprYield { expr, .. }) => match expr {
113                Some(_) => Precedence::Jump,
114                None => Precedence::Unambiguous,
115            },
116
117            Expr::Assign(_) => Precedence::Assign,
118            Expr::Range(_) => Precedence::Range,
119            Expr::Binary(e) => Precedence::of_binop(&e.op),
120            Expr::Let(_) => Precedence::Let,
121            Expr::Cast(_) => Precedence::Cast,
122            Expr::RawAddr(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix,
123
124            #[cfg(feature = "full")]
125            Expr::Array(ExprArray { attrs, .. })
126            | Expr::Async(ExprAsync { attrs, .. })
127            | Expr::Await(ExprAwait { attrs, .. })
128            | Expr::Block(ExprBlock { attrs, .. })
129            | Expr::Call(ExprCall { attrs, .. })
130            | Expr::Const(ExprConst { attrs, .. })
131            | Expr::Continue(ExprContinue { attrs, .. })
132            | Expr::Field(ExprField { attrs, .. })
133            | Expr::ForLoop(ExprForLoop { attrs, .. })
134            | Expr::Group(ExprGroup { attrs, .. })
135            | Expr::If(ExprIf { attrs, .. })
136            | Expr::Index(ExprIndex { attrs, .. })
137            | Expr::Infer(ExprInfer { attrs, .. })
138            | Expr::Lit(ExprLit { attrs, .. })
139            | Expr::Loop(ExprLoop { attrs, .. })
140            | Expr::Macro(ExprMacro { attrs, .. })
141            | Expr::Match(ExprMatch { attrs, .. })
142            | Expr::MethodCall(ExprMethodCall { attrs, .. })
143            | Expr::Paren(ExprParen { attrs, .. })
144            | Expr::Path(ExprPath { attrs, .. })
145            | Expr::Repeat(ExprRepeat { attrs, .. })
146            | Expr::Struct(ExprStruct { attrs, .. })
147            | Expr::Try(ExprTry { attrs, .. })
148            | Expr::TryBlock(ExprTryBlock { attrs, .. })
149            | Expr::Tuple(ExprTuple { attrs, .. })
150            | Expr::Unsafe(ExprUnsafe { attrs, .. })
151            | Expr::While(ExprWhile { attrs, .. }) => prefix_attrs(attrs),
152
153            #[cfg(not(feature = "full"))]
154            Expr::Array(_)
155            | Expr::Async(_)
156            | Expr::Await(_)
157            | Expr::Block(_)
158            | Expr::Call(_)
159            | Expr::Const(_)
160            | Expr::Continue(_)
161            | Expr::Field(_)
162            | Expr::ForLoop(_)
163            | Expr::Group(_)
164            | Expr::If(_)
165            | Expr::Index(_)
166            | Expr::Infer(_)
167            | Expr::Lit(_)
168            | Expr::Loop(_)
169            | Expr::Macro(_)
170            | Expr::Match(_)
171            | Expr::MethodCall(_)
172            | Expr::Paren(_)
173            | Expr::Path(_)
174            | Expr::Repeat(_)
175            | Expr::Struct(_)
176            | Expr::Try(_)
177            | Expr::TryBlock(_)
178            | Expr::Tuple(_)
179            | Expr::Unsafe(_)
180            | Expr::While(_) => Precedence::Unambiguous,
181
182            Expr::Verbatim(_) => Precedence::Unambiguous,
183
184            #[cfg(not(feature = "full"))]
185            Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => unreachable!(),
186        }
187    }
188}
189
190impl Copy for Precedence {}
191
192impl Clone for Precedence {
193    fn clone(&self) -> Self {
194        *self
195    }
196}
197
198impl PartialEq for Precedence {
199    fn eq(&self, other: &Self) -> bool {
200        *self as u8 == *other as u8
201    }
202}
203
204impl PartialOrd for Precedence {
205    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
206        let this = *self as u8;
207        let other = *other as u8;
208        Some(this.cmp(&other))
209    }
210}