]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_ast/src/util/parser.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_ast / src / util / parser.rs
CommitLineData
9fa01778 1use crate::ast::{self, BinOpKind};
dfeec247
XL
2use crate::token::{self, BinOpToken, Token};
3use rustc_span::symbol::kw;
2c00a5a8 4
92a42be0
SL
5/// Associative operator with precedence.
6///
7/// This is the enum which specifies operator precedence and fixity to the parser.
f035d41b 8#[derive(Copy, Clone, PartialEq, Debug)]
92a42be0
SL
9pub 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,
92a42be0
SL
48 /// `?=` where ? is one of the BinOpToken
49 AssignOp(BinOpToken),
50 /// `as`
51 As,
52 /// `..` range
9cc50fc6 53 DotDot,
ea8adc8c
XL
54 /// `..=` range
55 DotDotEq,
9cc50fc6
SL
56 /// `:`
57 Colon,
92a42be0
SL
58}
59
8faf50e0 60#[derive(PartialEq, Debug)]
92a42be0
SL
61pub enum Fixity {
62 /// The operator is left-associative
63 Left,
64 /// The operator is right-associative
65 Right,
66 /// The operator is not associative
dfeec247 67 None,
92a42be0
SL
68}
69
70impl AssocOp {
9fa01778 71 /// Creates a new AssocOP from a token
60c5eb7d 72 pub fn from_token(t: &Token) -> Option<AssocOp> {
9fa01778 73 use AssocOp::*;
dc9dc135
XL
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),
abe05a73 97 // DotDotDot is no longer supported, but we need some way to display the error
dc9dc135
XL
98 token::DotDotDot => Some(DotDotEq),
99 token::Colon => Some(Colon),
e1599b0c
XL
100 // `<-` should probably be `< -`
101 token::LArrow => Some(Less),
dc9dc135 102 _ if t.is_keyword(kw::As) => Some(As),
dfeec247 103 _ => None,
92a42be0
SL
104 }
105 }
106
9fa01778 107 /// Creates a new AssocOp from ast::BinOpKind.
7453a54e 108 pub fn from_ast_binop(op: BinOpKind) -> Self {
9fa01778 109 use AssocOp::*;
92a42be0 110 match op {
7453a54e
SL
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,
dfeec247 128 BinOpKind::Or => LOr,
92a42be0
SL
129 }
130 }
131
132 /// Gets the precedence of this operator
133 pub fn precedence(&self) -> usize {
9fa01778 134 use AssocOp::*;
92a42be0 135 match *self {
9cc50fc6 136 As | Colon => 14,
92a42be0
SL
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,
ea8adc8c 146 DotDot | DotDotEq => 4,
92a42be0
SL
147 Assign | AssignOp(_) => 2,
148 }
149 }
150
151 /// Gets the fixity of this operator
152 pub fn fixity(&self) -> Fixity {
9fa01778 153 use AssocOp::*;
92a42be0
SL
154 // NOTE: it is a bug to have an operators that has same precedence but different fixities!
155 match *self {
dc9dc135 156 Assign | AssignOp(_) => Fixity::Right,
dfeec247
XL
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,
92a42be0
SL
161 }
162 }
163
164 pub fn is_comparison(&self) -> bool {
9fa01778 165 use AssocOp::*;
92a42be0
SL
166 match *self {
167 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
dfeec247
XL
168 Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
169 | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq
170 | Colon => false,
92a42be0
SL
171 }
172 }
173
174 pub fn is_assign_like(&self) -> bool {
9fa01778 175 use AssocOp::*;
92a42be0 176 match *self {
dc9dc135 177 Assign | AssignOp(_) => true,
dfeec247
XL
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,
92a42be0
SL
181 }
182 }
183
7453a54e 184 pub fn to_ast_binop(&self) -> Option<BinOpKind> {
9fa01778 185 use AssocOp::*;
92a42be0 186 match *self {
7453a54e
SL
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),
dfeec247 205 Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None,
92a42be0
SL
206 }
207 }
48663c56
XL
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::*;
3c0e092e
XL
215 matches!(
216 self,
48663c56
XL
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 } +=`
48663c56
XL
226 As | // `{ 42 } as usize`
227 // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
228 // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
3c0e092e
XL
229 Colon, // `{ 42 }: usize`
230 )
48663c56 231 }
92a42be0 232}
ea8adc8c 233
ea8adc8c
XL
234pub const PREC_CLOSURE: i8 = -40;
235pub const PREC_JUMP: i8 = -30;
236pub const PREC_RANGE: i8 = -10;
dc9dc135 237// The range 2..=14 is reserved for AssocOp binary operator precedences.
ea8adc8c
XL
238pub const PREC_PREFIX: i8 = 50;
239pub const PREC_POSTFIX: i8 = 60;
240pub const PREC_PAREN: i8 = 99;
241pub const PREC_FORCE_PAREN: i8 = 100;
242
8faf50e0 243#[derive(Debug, Clone, Copy)]
2c00a5a8
XL
244pub enum ExprPrecedence {
245 Closure,
246 Break,
247 Continue,
248 Ret,
249 Yield,
04454e1e 250 Yeet,
2c00a5a8
XL
251
252 Range,
253
254 Binary(BinOpKind),
255
2c00a5a8
XL
256 Cast,
257 Type,
258
259 Assign,
260 AssignOp,
261
262 Box,
263 AddrOf,
dc9dc135 264 Let,
2c00a5a8
XL
265 Unary,
266
267 Call,
268 MethodCall,
269 Field,
2c00a5a8
XL
270 Index,
271 Try,
272 InlineAsm,
273 Mac,
274
275 Array,
276 Repeat,
277 Tup,
278 Lit,
279 Path,
280 Paren,
281 If,
2c00a5a8 282 While,
2c00a5a8
XL
283 ForLoop,
284 Loop,
285 Match,
29967ef6 286 ConstBlock,
2c00a5a8 287 Block,
b7449926 288 TryBlock,
2c00a5a8 289 Struct,
8faf50e0 290 Async,
48663c56 291 Await,
0731742a 292 Err,
2c00a5a8 293}
ea8adc8c 294
2c00a5a8
XL
295impl ExprPrecedence {
296 pub fn order(self) -> i8 {
297 match self {
298 ExprPrecedence::Closure => PREC_CLOSURE,
ea8adc8c 299
f2b60f7d
FG
300 ExprPrecedence::Break
301 | ExprPrecedence::Continue
302 | ExprPrecedence::Ret
303 | ExprPrecedence::Yield
304 | ExprPrecedence::Yeet => PREC_JUMP,
ea8adc8c 305
2c00a5a8 306 // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
9c376795 307 // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
2c00a5a8
XL
308 // ensures that `pprust` will add parentheses in the right places to get the desired
309 // parse.
310 ExprPrecedence::Range => PREC_RANGE,
ea8adc8c 311
2c00a5a8
XL
312 // Binop-like expr kinds, handled by `AssocOp`.
313 ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
2c00a5a8
XL
314 ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
315 ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
ea8adc8c 316
2c00a5a8
XL
317 ExprPrecedence::Assign |
318 ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
ea8adc8c 319
2c00a5a8 320 // Unary, prefix
f2b60f7d
FG
321 ExprPrecedence::Box
322 | ExprPrecedence::AddrOf
dc9dc135
XL
323 // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
324 // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
325 // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
326 // but we need to print `(let _ = a) < b` as-is with parens.
f2b60f7d
FG
327 | ExprPrecedence::Let
328 | ExprPrecedence::Unary => PREC_PREFIX,
2c00a5a8
XL
329
330 // Unary, postfix
f2b60f7d
FG
331 ExprPrecedence::Await
332 | ExprPrecedence::Call
333 | ExprPrecedence::MethodCall
334 | ExprPrecedence::Field
335 | ExprPrecedence::Index
336 | ExprPrecedence::Try
337 | ExprPrecedence::InlineAsm
338 | ExprPrecedence::Mac => PREC_POSTFIX,
2c00a5a8
XL
339
340 // Never need parens
f2b60f7d
FG
341 ExprPrecedence::Array
342 | ExprPrecedence::Repeat
343 | ExprPrecedence::Tup
344 | ExprPrecedence::Lit
345 | ExprPrecedence::Path
346 | ExprPrecedence::Paren
347 | ExprPrecedence::If
348 | ExprPrecedence::While
349 | ExprPrecedence::ForLoop
350 | ExprPrecedence::Loop
351 | ExprPrecedence::Match
352 | ExprPrecedence::ConstBlock
353 | ExprPrecedence::Block
354 | ExprPrecedence::TryBlock
355 | ExprPrecedence::Async
356 | ExprPrecedence::Struct
357 | ExprPrecedence::Err => PREC_PAREN,
2c00a5a8 358 }
ea8adc8c
XL
359 }
360}
361
3c0e092e 362/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
60c5eb7d 363pub fn prec_let_scrutinee_needs_par() -> usize {
dc9dc135
XL
364 AssocOp::LAnd.precedence()
365}
366
367/// Suppose we have `let _ = e` and the `order` of `e`.
3c0e092e 368/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
dc9dc135
XL
369///
370/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
371/// Can we print this as `let _ = a OP b`?
74b04a01 372pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
dc9dc135
XL
373 order <= prec_let_scrutinee_needs_par() as i8
374}
2c00a5a8 375
0731742a
XL
376/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
377/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
ea8adc8c
XL
378/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
379pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
487cf647 380 match &value.kind {
ea8adc8c
XL
381 ast::ExprKind::Struct(..) => true,
382
487cf647
FG
383 ast::ExprKind::Assign(lhs, rhs, _)
384 | ast::ExprKind::AssignOp(_, lhs, rhs)
385 | ast::ExprKind::Binary(_, lhs, rhs) => {
ea8adc8c 386 // X { y: 1 } + X { y: 2 }
487cf647 387 contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
ea8adc8c 388 }
487cf647
FG
389 ast::ExprKind::Await(x)
390 | ast::ExprKind::Unary(_, x)
391 | ast::ExprKind::Cast(x, _)
392 | ast::ExprKind::Type(x, _)
393 | ast::ExprKind::Field(x, _)
394 | ast::ExprKind::Index(x, _) => {
ea8adc8c 395 // &X { y: 1 }, X { y: 1 }.y
487cf647 396 contains_exterior_struct_lit(x)
ea8adc8c
XL
397 }
398
487cf647 399 ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {
ea8adc8c 400 // X { y: 1 }.bar(...)
487cf647 401 contains_exterior_struct_lit(receiver)
ea8adc8c
XL
402 }
403
404 _ => false,
405 }
406}