1use rustc_span::kw;
2
3use crate::ast::{self, BinOpKind};
4use crate::token::{self, BinOpToken, Token};
5
6#[derive(Copy, Clone, PartialEq, Debug)]
10pub enum AssocOp {
11 Add,
13 Subtract,
15 Multiply,
17 Divide,
19 Modulus,
21 LAnd,
23 LOr,
25 BitXor,
27 BitAnd,
29 BitOr,
31 ShiftLeft,
33 ShiftRight,
35 Equal,
37 Less,
39 LessEqual,
41 NotEqual,
43 Greater,
45 GreaterEqual,
47 Assign,
49 AssignOp(BinOpToken),
51 As,
53 DotDot,
55 DotDotEq,
57}
58
59#[derive(PartialEq, Debug)]
60pub enum Fixity {
61 Left,
63 Right,
65 None,
67}
68
69impl AssocOp {
70 pub fn from_token(t: &Token) -> Option<AssocOp> {
72 use AssocOp::*;
73 match t.kind {
74 token::BinOpEq(k) => Some(AssignOp(k)),
75 token::Eq => Some(Assign),
76 token::BinOp(BinOpToken::Star) => Some(Multiply),
77 token::BinOp(BinOpToken::Slash) => Some(Divide),
78 token::BinOp(BinOpToken::Percent) => Some(Modulus),
79 token::BinOp(BinOpToken::Plus) => Some(Add),
80 token::BinOp(BinOpToken::Minus) => Some(Subtract),
81 token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
82 token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
83 token::BinOp(BinOpToken::And) => Some(BitAnd),
84 token::BinOp(BinOpToken::Caret) => Some(BitXor),
85 token::BinOp(BinOpToken::Or) => Some(BitOr),
86 token::Lt => Some(Less),
87 token::Le => Some(LessEqual),
88 token::Ge => Some(GreaterEqual),
89 token::Gt => Some(Greater),
90 token::EqEq => Some(Equal),
91 token::Ne => Some(NotEqual),
92 token::AndAnd => Some(LAnd),
93 token::OrOr => Some(LOr),
94 token::DotDot => Some(DotDot),
95 token::DotDotEq => Some(DotDotEq),
96 token::DotDotDot => Some(DotDotEq),
98 token::LArrow => Some(Less),
100 _ if t.is_keyword(kw::As) => Some(As),
101 _ => None,
102 }
103 }
104
105 pub fn from_ast_binop(op: BinOpKind) -> Self {
107 use AssocOp::*;
108 match op {
109 BinOpKind::Lt => Less,
110 BinOpKind::Gt => Greater,
111 BinOpKind::Le => LessEqual,
112 BinOpKind::Ge => GreaterEqual,
113 BinOpKind::Eq => Equal,
114 BinOpKind::Ne => NotEqual,
115 BinOpKind::Mul => Multiply,
116 BinOpKind::Div => Divide,
117 BinOpKind::Rem => Modulus,
118 BinOpKind::Add => Add,
119 BinOpKind::Sub => Subtract,
120 BinOpKind::Shl => ShiftLeft,
121 BinOpKind::Shr => ShiftRight,
122 BinOpKind::BitAnd => BitAnd,
123 BinOpKind::BitXor => BitXor,
124 BinOpKind::BitOr => BitOr,
125 BinOpKind::And => LAnd,
126 BinOpKind::Or => LOr,
127 }
128 }
129
130 pub fn precedence(&self) -> ExprPrecedence {
132 use AssocOp::*;
133 match *self {
134 As => ExprPrecedence::Cast,
135 Multiply | Divide | Modulus => ExprPrecedence::Product,
136 Add | Subtract => ExprPrecedence::Sum,
137 ShiftLeft | ShiftRight => ExprPrecedence::Shift,
138 BitAnd => ExprPrecedence::BitAnd,
139 BitXor => ExprPrecedence::BitXor,
140 BitOr => ExprPrecedence::BitOr,
141 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => ExprPrecedence::Compare,
142 LAnd => ExprPrecedence::LAnd,
143 LOr => ExprPrecedence::LOr,
144 DotDot | DotDotEq => ExprPrecedence::Range,
145 Assign | AssignOp(_) => ExprPrecedence::Assign,
146 }
147 }
148
149 pub fn fixity(&self) -> Fixity {
151 use AssocOp::*;
152 match *self {
154 Assign | AssignOp(_) => Fixity::Right,
155 As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
156 | BitXor | BitOr | LAnd | LOr => Fixity::Left,
157 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | DotDot | DotDotEq => {
158 Fixity::None
159 }
160 }
161 }
162
163 pub fn is_comparison(&self) -> bool {
164 use AssocOp::*;
165 match *self {
166 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
167 Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
168 | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq => {
169 false
170 }
171 }
172 }
173
174 pub fn is_assign_like(&self) -> bool {
175 use AssocOp::*;
176 match *self {
177 Assign | AssignOp(_) => true,
178 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply
179 | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor
180 | BitOr | LAnd | LOr | DotDot | DotDotEq => false,
181 }
182 }
183
184 pub fn to_ast_binop(&self) -> Option<BinOpKind> {
185 use AssocOp::*;
186 match *self {
187 Less => Some(BinOpKind::Lt),
188 Greater => Some(BinOpKind::Gt),
189 LessEqual => Some(BinOpKind::Le),
190 GreaterEqual => Some(BinOpKind::Ge),
191 Equal => Some(BinOpKind::Eq),
192 NotEqual => Some(BinOpKind::Ne),
193 Multiply => Some(BinOpKind::Mul),
194 Divide => Some(BinOpKind::Div),
195 Modulus => Some(BinOpKind::Rem),
196 Add => Some(BinOpKind::Add),
197 Subtract => Some(BinOpKind::Sub),
198 ShiftLeft => Some(BinOpKind::Shl),
199 ShiftRight => Some(BinOpKind::Shr),
200 BitAnd => Some(BinOpKind::BitAnd),
201 BitXor => Some(BinOpKind::BitXor),
202 BitOr => Some(BinOpKind::BitOr),
203 LAnd => Some(BinOpKind::And),
204 LOr => Some(BinOpKind::Or),
205 Assign | AssignOp(_) | As | DotDot | DotDotEq => None,
206 }
207 }
208
209 pub fn can_continue_expr_unambiguously(&self) -> bool {
214 use AssocOp::*;
215 matches!(
216 self,
217 BitXor | Assign | Divide | Modulus | ShiftRight | LessEqual | Greater | GreaterEqual | AssignOp(_) | As )
230 }
231}
232
233#[derive(Clone, Copy, PartialEq, PartialOrd)]
234pub enum ExprPrecedence {
235 Jump,
237 Assign,
239 Range,
241 LOr,
243 LAnd,
245 Compare,
247 BitOr,
249 BitXor,
251 BitAnd,
253 Shift,
255 Sum,
257 Product,
259 Cast,
261 Prefix,
263 Unambiguous,
265}
266
267pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
269 ExprPrecedence::LAnd
270}
271
272pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
278 order <= prec_let_scrutinee_needs_par()
279}
280
281pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
285 match &value.kind {
286 ast::ExprKind::Struct(..) => true,
287
288 ast::ExprKind::Assign(lhs, rhs, _)
289 | ast::ExprKind::AssignOp(_, lhs, rhs)
290 | ast::ExprKind::Binary(_, lhs, rhs) => {
291 contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
293 }
294 ast::ExprKind::Await(x, _)
295 | ast::ExprKind::Unary(_, x)
296 | ast::ExprKind::Cast(x, _)
297 | ast::ExprKind::Type(x, _)
298 | ast::ExprKind::Field(x, _)
299 | ast::ExprKind::Index(x, _, _)
300 | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {
301 contains_exterior_struct_lit(x)
303 }
304
305 ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {
306 contains_exterior_struct_lit(receiver)
308 }
309
310 _ => false,
311 }
312}