1 use crate::ast::{self, BinOpKind};
2 use crate::token::{self, BinOpToken, Token};
3 use rustc_span::symbol::kw;
5 /// Associative operator with precedence.
7 /// This is the enum which specifies operator precedence and fixity to the parser.
8 #[derive(Copy, Clone, PartialEq, Debug)]
48 /// `?=` where ? is one of the BinOpToken
60 #[derive(PartialEq, Debug)]
62 /// The operator is left-associative
64 /// The operator is right-associative
66 /// The operator is not associative
71 /// Creates a new AssocOP from a token
72 pub fn from_token(t: &Token) -> Option<AssocOp> {
75 token::BinOpEq(k) => Some(AssignOp(k)),
76 token::Eq => Some(Assign),
77 token::BinOp(BinOpToken::Star) => Some(Multiply),
78 token::BinOp(BinOpToken::Slash) => Some(Divide),
79 token::BinOp(BinOpToken::Percent) => Some(Modulus),
80 token::BinOp(BinOpToken::Plus) => Some(Add),
81 token::BinOp(BinOpToken::Minus) => Some(Subtract),
82 token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
83 token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
84 token::BinOp(BinOpToken::And) => Some(BitAnd),
85 token::BinOp(BinOpToken::Caret) => Some(BitXor),
86 token::BinOp(BinOpToken::Or) => Some(BitOr),
87 token::Lt => Some(Less),
88 token::Le => Some(LessEqual),
89 token::Ge => Some(GreaterEqual),
90 token::Gt => Some(Greater),
91 token::EqEq => Some(Equal),
92 token::Ne => Some(NotEqual),
93 token::AndAnd => Some(LAnd),
94 token::OrOr => Some(LOr),
95 token::DotDot => Some(DotDot),
96 token::DotDotEq => Some(DotDotEq),
97 // DotDotDot is no longer supported, but we need some way to display the error
98 token::DotDotDot => Some(DotDotEq),
99 token::Colon => Some(Colon),
100 // `<-` should probably be `< -`
101 token::LArrow => Some(Less),
102 _ if t.is_keyword(kw::As) => Some(As),
107 /// Creates a new AssocOp from ast::BinOpKind.
108 pub fn from_ast_binop(op: BinOpKind) -> Self {
111 BinOpKind::Lt => Less,
112 BinOpKind::Gt => Greater,
113 BinOpKind::Le => LessEqual,
114 BinOpKind::Ge => GreaterEqual,
115 BinOpKind::Eq => Equal,
116 BinOpKind::Ne => NotEqual,
117 BinOpKind::Mul => Multiply,
118 BinOpKind::Div => Divide,
119 BinOpKind::Rem => Modulus,
120 BinOpKind::Add => Add,
121 BinOpKind::Sub => Subtract,
122 BinOpKind::Shl => ShiftLeft,
123 BinOpKind::Shr => ShiftRight,
124 BinOpKind::BitAnd => BitAnd,
125 BinOpKind::BitXor => BitXor,
126 BinOpKind::BitOr => BitOr,
127 BinOpKind::And => LAnd,
128 BinOpKind::Or => LOr,
132 /// Gets the precedence of this operator
133 pub fn precedence(&self) -> usize {
137 Multiply | Divide | Modulus => 13,
138 Add | Subtract => 12,
139 ShiftLeft | ShiftRight => 11,
143 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
146 DotDot | DotDotEq => 4,
147 Assign | AssignOp(_) => 2,
151 /// Gets the fixity of this operator
152 pub fn fixity(&self) -> Fixity {
154 // NOTE: it is a bug to have an operators that has same precedence but different fixities!
156 Assign | AssignOp(_) => Fixity::Right,
157 As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
158 | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual
159 | LAnd | LOr | Colon => Fixity::Left,
160 DotDot | DotDotEq => Fixity::None,
164 pub fn is_comparison(&self) -> bool {
167 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
168 Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
169 | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq
174 pub fn is_assign_like(&self) -> bool {
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 | Colon => false,
184 pub fn to_ast_binop(&self) -> Option<BinOpKind> {
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 | Colon => None,
209 /// This operator could be used to follow a block unambiguously.
211 /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
212 /// parentheses while having a high degree of confidence on the correctness of the suggestion.
213 pub fn can_continue_expr_unambiguously(&self) -> bool {
216 BitXor | // `{ 42 } ^ 3`
217 Assign | // `{ 42 } = { 42 }`
218 Divide | // `{ 42 } / 42`
219 Modulus | // `{ 42 } % 2`
220 ShiftRight | // `{ 42 } >> 2`
221 LessEqual | // `{ 42 } <= 3`
222 Greater | // `{ 42 } > 3`
223 GreaterEqual | // `{ 42 } >= 3`
224 AssignOp(_) | // `{ 42 } +=`
225 As | // `{ 42 } as usize`
226 // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
227 // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
228 Colon => true, // `{ 42 }: usize`
234 pub const PREC_RESET: i8 = -100;
235 pub const PREC_CLOSURE: i8 = -40;
236 pub const PREC_JUMP: i8 = -30;
237 pub const PREC_RANGE: i8 = -10;
238 // The range 2..=14 is reserved for AssocOp binary operator precedences.
239 pub const PREC_PREFIX: i8 = 50;
240 pub const PREC_POSTFIX: i8 = 60;
241 pub const PREC_PAREN: i8 = 99;
242 pub const PREC_FORCE_PAREN: i8 = 100;
244 #[derive(Debug, Clone, Copy)]
245 pub enum ExprPrecedence {
294 impl ExprPrecedence {
295 pub fn order(self) -> i8 {
297 ExprPrecedence::Closure => PREC_CLOSURE,
299 ExprPrecedence::Break |
300 ExprPrecedence::Continue |
301 ExprPrecedence::Ret |
302 ExprPrecedence::Yield => PREC_JUMP,
304 // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
305 // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
306 // ensures that `pprust` will add parentheses in the right places to get the desired
308 ExprPrecedence::Range => PREC_RANGE,
310 // Binop-like expr kinds, handled by `AssocOp`.
311 ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
312 ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
313 ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
315 ExprPrecedence::Assign |
316 ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
319 ExprPrecedence::Box |
320 ExprPrecedence::AddrOf |
321 // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
322 // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
323 // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
324 // but we need to print `(let _ = a) < b` as-is with parens.
325 ExprPrecedence::Let |
326 ExprPrecedence::Unary => PREC_PREFIX,
329 ExprPrecedence::Await |
330 ExprPrecedence::Call |
331 ExprPrecedence::MethodCall |
332 ExprPrecedence::Field |
333 ExprPrecedence::Index |
334 ExprPrecedence::Try |
335 ExprPrecedence::InlineAsm |
336 ExprPrecedence::Mac => PREC_POSTFIX,
339 ExprPrecedence::Array |
340 ExprPrecedence::Repeat |
341 ExprPrecedence::Tup |
342 ExprPrecedence::Lit |
343 ExprPrecedence::Path |
344 ExprPrecedence::Paren |
346 ExprPrecedence::While |
347 ExprPrecedence::ForLoop |
348 ExprPrecedence::Loop |
349 ExprPrecedence::Match |
350 ExprPrecedence::Block |
351 ExprPrecedence::TryBlock |
352 ExprPrecedence::Async |
353 ExprPrecedence::Struct |
354 ExprPrecedence::Err => PREC_PAREN,
359 /// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
360 pub fn prec_let_scrutinee_needs_par() -> usize {
361 AssocOp::LAnd.precedence()
364 /// Suppose we have `let _ = e` and the `order` of `e`.
365 /// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
367 /// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
368 /// Can we print this as `let _ = a OP b`?
369 pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
370 order <= prec_let_scrutinee_needs_par() as i8
373 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
374 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
375 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
376 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
378 ast::ExprKind::Struct(..) => true,
380 ast::ExprKind::Assign(ref lhs, ref rhs, _)
381 | ast::ExprKind::AssignOp(_, ref lhs, ref rhs)
382 | ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
383 // X { y: 1 } + X { y: 2 }
384 contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
386 ast::ExprKind::Await(ref x)
387 | ast::ExprKind::Unary(_, ref x)
388 | ast::ExprKind::Cast(ref x, _)
389 | ast::ExprKind::Type(ref x, _)
390 | ast::ExprKind::Field(ref x, _)
391 | ast::ExprKind::Index(ref x, _) => {
392 // &X { y: 1 }, X { y: 1 }.y
393 contains_exterior_struct_lit(&x)
396 ast::ExprKind::MethodCall(.., ref exprs, _) => {
397 // X { y: 1 }.bar(...)
398 contains_exterior_struct_lit(&exprs[0])