]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/util/parser.rs
Rollup merge of #107325 - petrochenkov:hiddoc2, r=GuillaumeGomez
[rust.git] / compiler / rustc_ast / src / util / parser.rs
1 use crate::ast::{self, BinOpKind};
2 use crate::token::{self, BinOpToken, Token};
3 use rustc_span::symbol::kw;
4
5 /// Associative operator with precedence.
6 ///
7 /// This is the enum which specifies operator precedence and fixity to the parser.
8 #[derive(Copy, Clone, PartialEq, Debug)]
9 pub enum AssocOp {
10     /// `+`
11     Add,
12     /// `-`
13     Subtract,
14     /// `*`
15     Multiply,
16     /// `/`
17     Divide,
18     /// `%`
19     Modulus,
20     /// `&&`
21     LAnd,
22     /// `||`
23     LOr,
24     /// `^`
25     BitXor,
26     /// `&`
27     BitAnd,
28     /// `|`
29     BitOr,
30     /// `<<`
31     ShiftLeft,
32     /// `>>`
33     ShiftRight,
34     /// `==`
35     Equal,
36     /// `<`
37     Less,
38     /// `<=`
39     LessEqual,
40     /// `!=`
41     NotEqual,
42     /// `>`
43     Greater,
44     /// `>=`
45     GreaterEqual,
46     /// `=`
47     Assign,
48     /// `?=` where ? is one of the BinOpToken
49     AssignOp(BinOpToken),
50     /// `as`
51     As,
52     /// `..` range
53     DotDot,
54     /// `..=` range
55     DotDotEq,
56     /// `:`
57     Colon,
58 }
59
60 #[derive(PartialEq, Debug)]
61 pub enum Fixity {
62     /// The operator is left-associative
63     Left,
64     /// The operator is right-associative
65     Right,
66     /// The operator is not associative
67     None,
68 }
69
70 impl AssocOp {
71     /// Creates a new AssocOP from a token
72     pub fn from_token(t: &Token) -> Option<AssocOp> {
73         use AssocOp::*;
74         match t.kind {
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),
103             _ => None,
104         }
105     }
106
107     /// Creates a new AssocOp from ast::BinOpKind.
108     pub fn from_ast_binop(op: BinOpKind) -> Self {
109         use AssocOp::*;
110         match op {
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,
129         }
130     }
131
132     /// Gets the precedence of this operator
133     pub fn precedence(&self) -> usize {
134         use AssocOp::*;
135         match *self {
136             As | Colon => 14,
137             Multiply | Divide | Modulus => 13,
138             Add | Subtract => 12,
139             ShiftLeft | ShiftRight => 11,
140             BitAnd => 10,
141             BitXor => 9,
142             BitOr => 8,
143             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
144             LAnd => 6,
145             LOr => 5,
146             DotDot | DotDotEq => 4,
147             Assign | AssignOp(_) => 2,
148         }
149     }
150
151     /// Gets the fixity of this operator
152     pub fn fixity(&self) -> Fixity {
153         use AssocOp::*;
154         // NOTE: it is a bug to have an operators that has same precedence but different fixities!
155         match *self {
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,
161         }
162     }
163
164     pub fn is_comparison(&self) -> bool {
165         use AssocOp::*;
166         match *self {
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
170             | Colon => false,
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 | Colon => 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 | Colon => None,
206         }
207     }
208
209     /// This operator could be used to follow a block unambiguously.
210     ///
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 {
214         use AssocOp::*;
215         matches!(
216             self,
217             BitXor | // `{ 42 } ^ 3`
218             Assign | // `{ 42 } = { 42 }`
219             Divide | // `{ 42 } / 42`
220             Modulus | // `{ 42 } % 2`
221             ShiftRight | // `{ 42 } >> 2`
222             LessEqual | // `{ 42 } <= 3`
223             Greater | // `{ 42 } > 3`
224             GreaterEqual | // `{ 42 } >= 3`
225             AssignOp(_) | // `{ 42 } +=`
226             As | // `{ 42 } as usize`
227             // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
228             // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
229             Colon, // `{ 42 }: usize`
230         )
231     }
232 }
233
234 pub const PREC_CLOSURE: i8 = -40;
235 pub const PREC_JUMP: i8 = -30;
236 pub const PREC_RANGE: i8 = -10;
237 // The range 2..=14 is reserved for AssocOp binary operator precedences.
238 pub const PREC_PREFIX: i8 = 50;
239 pub const PREC_POSTFIX: i8 = 60;
240 pub const PREC_PAREN: i8 = 99;
241 pub const PREC_FORCE_PAREN: i8 = 100;
242
243 #[derive(Debug, Clone, Copy)]
244 pub enum ExprPrecedence {
245     Closure,
246     Break,
247     Continue,
248     Ret,
249     Yield,
250     Yeet,
251
252     Range,
253
254     Binary(BinOpKind),
255
256     Cast,
257     Type,
258
259     Assign,
260     AssignOp,
261
262     Box,
263     AddrOf,
264     Let,
265     Unary,
266
267     Call,
268     MethodCall,
269     Field,
270     Index,
271     Try,
272     InlineAsm,
273     Mac,
274     FormatArgs,
275
276     Array,
277     Repeat,
278     Tup,
279     Lit,
280     Path,
281     Paren,
282     If,
283     While,
284     ForLoop,
285     Loop,
286     Match,
287     ConstBlock,
288     Block,
289     TryBlock,
290     Struct,
291     Async,
292     Await,
293     Err,
294 }
295
296 impl ExprPrecedence {
297     pub fn order(self) -> i8 {
298         match self {
299             ExprPrecedence::Closure => PREC_CLOSURE,
300
301             ExprPrecedence::Break
302             | ExprPrecedence::Continue
303             | ExprPrecedence::Ret
304             | ExprPrecedence::Yield
305             | ExprPrecedence::Yeet => PREC_JUMP,
306
307             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
308             // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
309             // ensures that `pprust` will add parentheses in the right places to get the desired
310             // parse.
311             ExprPrecedence::Range => PREC_RANGE,
312
313             // Binop-like expr kinds, handled by `AssocOp`.
314             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
315             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
316             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
317
318             ExprPrecedence::Assign |
319             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
320
321             // Unary, prefix
322             ExprPrecedence::Box
323             | ExprPrecedence::AddrOf
324             // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
325             // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
326             // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
327             // but we need to print `(let _ = a) < b` as-is with parens.
328             | ExprPrecedence::Let
329             | ExprPrecedence::Unary => PREC_PREFIX,
330
331             // Unary, postfix
332             ExprPrecedence::Await
333             | ExprPrecedence::Call
334             | ExprPrecedence::MethodCall
335             | ExprPrecedence::Field
336             | ExprPrecedence::Index
337             | ExprPrecedence::Try
338             | ExprPrecedence::InlineAsm
339             | ExprPrecedence::Mac
340             | ExprPrecedence::FormatArgs => PREC_POSTFIX,
341
342             // Never need parens
343             ExprPrecedence::Array
344             | ExprPrecedence::Repeat
345             | ExprPrecedence::Tup
346             | ExprPrecedence::Lit
347             | ExprPrecedence::Path
348             | ExprPrecedence::Paren
349             | ExprPrecedence::If
350             | ExprPrecedence::While
351             | ExprPrecedence::ForLoop
352             | ExprPrecedence::Loop
353             | ExprPrecedence::Match
354             | ExprPrecedence::ConstBlock
355             | ExprPrecedence::Block
356             | ExprPrecedence::TryBlock
357             | ExprPrecedence::Async
358             | ExprPrecedence::Struct
359             | ExprPrecedence::Err => PREC_PAREN,
360         }
361     }
362 }
363
364 /// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
365 pub fn prec_let_scrutinee_needs_par() -> usize {
366     AssocOp::LAnd.precedence()
367 }
368
369 /// Suppose we have `let _ = e` and the `order` of `e`.
370 /// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
371 ///
372 /// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
373 /// Can we print this as `let _ = a OP b`?
374 pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
375     order <= prec_let_scrutinee_needs_par() as i8
376 }
377
378 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
379 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
380 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
381 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
382     match &value.kind {
383         ast::ExprKind::Struct(..) => true,
384
385         ast::ExprKind::Assign(lhs, rhs, _)
386         | ast::ExprKind::AssignOp(_, lhs, rhs)
387         | ast::ExprKind::Binary(_, lhs, rhs) => {
388             // X { y: 1 } + X { y: 2 }
389             contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
390         }
391         ast::ExprKind::Await(x)
392         | ast::ExprKind::Unary(_, x)
393         | ast::ExprKind::Cast(x, _)
394         | ast::ExprKind::Type(x, _)
395         | ast::ExprKind::Field(x, _)
396         | ast::ExprKind::Index(x, _) => {
397             // &X { y: 1 }, X { y: 1 }.y
398             contains_exterior_struct_lit(x)
399         }
400
401         ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {
402             // X { y: 1 }.bar(...)
403             contains_exterior_struct_lit(receiver)
404         }
405
406         _ => false,
407     }
408 }