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
17pub(crate) enum Precedence {
19 Jump,
21 Assign,
23 Range,
25 Or,
27 And,
29 #[cfg(feature = "printing")]
31 Let,
32 Compare,
34 BitOr,
36 BitXor,
38 BitAnd,
40 Shift,
42 Sum,
44 Product,
46 Cast,
48 #[cfg(feature = "printing")]
50 Prefix,
51 #[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}