]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/util/parser.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / libsyntax / util / parser.rs
CommitLineData
60c5eb7d 1use crate::token::{self, Token, BinOpToken};
dc9dc135 2use crate::symbol::kw;
9fa01778 3use crate::ast::{self, BinOpKind};
2c00a5a8 4
92a42be0
SL
5/// Associative operator with precedence.
6///
7/// This is the enum which specifies operator precedence and fixity to the parser.
8faf50e0 8#[derive(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
67 None
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),
92a42be0
SL
103 _ => None
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,
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,
92a42be0
SL
157 As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
158 BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
9cc50fc6 159 LAnd | LOr | Colon => Fixity::Left,
ea8adc8c 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,
dc9dc135 168 Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
83c7162d 169 Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
ea8adc8c 170 DotDot | DotDotEq | 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,
92a42be0
SL
178 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
179 Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
ea8adc8c 180 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),
dc9dc135 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::*;
215 match self {
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 LAnd | // `{ 42 } &&foo`
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 => true, // `{ 42 }: usize`
230 _ => false,
231 }
232 }
92a42be0 233}
ea8adc8c
XL
234
235pub const PREC_RESET: i8 = -100;
236pub const PREC_CLOSURE: i8 = -40;
237pub const PREC_JUMP: i8 = -30;
238pub const PREC_RANGE: i8 = -10;
dc9dc135 239// The range 2..=14 is reserved for AssocOp binary operator precedences.
ea8adc8c
XL
240pub const PREC_PREFIX: i8 = 50;
241pub const PREC_POSTFIX: i8 = 60;
242pub const PREC_PAREN: i8 = 99;
243pub const PREC_FORCE_PAREN: i8 = 100;
244
8faf50e0 245#[derive(Debug, Clone, Copy)]
2c00a5a8
XL
246pub enum ExprPrecedence {
247 Closure,
248 Break,
249 Continue,
250 Ret,
251 Yield,
252
253 Range,
254
255 Binary(BinOpKind),
256
2c00a5a8
XL
257 Cast,
258 Type,
259
260 Assign,
261 AssignOp,
262
263 Box,
264 AddrOf,
dc9dc135 265 Let,
2c00a5a8
XL
266 Unary,
267
268 Call,
269 MethodCall,
270 Field,
2c00a5a8
XL
271 Index,
272 Try,
273 InlineAsm,
274 Mac,
275
276 Array,
277 Repeat,
278 Tup,
279 Lit,
280 Path,
281 Paren,
282 If,
2c00a5a8 283 While,
2c00a5a8
XL
284 ForLoop,
285 Loop,
286 Match,
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
2c00a5a8
XL
300 ExprPrecedence::Break |
301 ExprPrecedence::Continue |
302 ExprPrecedence::Ret |
303 ExprPrecedence::Yield => PREC_JUMP,
ea8adc8c 304
2c00a5a8
XL
305 // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
306 // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
307 // ensures that `pprust` will add parentheses in the right places to get the desired
308 // parse.
309 ExprPrecedence::Range => PREC_RANGE,
ea8adc8c 310
2c00a5a8
XL
311 // Binop-like expr kinds, handled by `AssocOp`.
312 ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
2c00a5a8
XL
313 ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
314 ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
ea8adc8c 315
2c00a5a8
XL
316 ExprPrecedence::Assign |
317 ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
ea8adc8c 318
2c00a5a8
XL
319 // Unary, prefix
320 ExprPrecedence::Box |
321 ExprPrecedence::AddrOf |
dc9dc135
XL
322 // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
323 // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
324 // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
325 // but we need to print `(let _ = a) < b` as-is with parens.
326 ExprPrecedence::Let |
2c00a5a8
XL
327 ExprPrecedence::Unary => PREC_PREFIX,
328
329 // Unary, postfix
48663c56 330 ExprPrecedence::Await |
2c00a5a8
XL
331 ExprPrecedence::Call |
332 ExprPrecedence::MethodCall |
333 ExprPrecedence::Field |
2c00a5a8
XL
334 ExprPrecedence::Index |
335 ExprPrecedence::Try |
336 ExprPrecedence::InlineAsm |
337 ExprPrecedence::Mac => PREC_POSTFIX,
338
339 // Never need parens
340 ExprPrecedence::Array |
341 ExprPrecedence::Repeat |
342 ExprPrecedence::Tup |
343 ExprPrecedence::Lit |
344 ExprPrecedence::Path |
345 ExprPrecedence::Paren |
346 ExprPrecedence::If |
2c00a5a8 347 ExprPrecedence::While |
2c00a5a8
XL
348 ExprPrecedence::ForLoop |
349 ExprPrecedence::Loop |
350 ExprPrecedence::Match |
351 ExprPrecedence::Block |
b7449926 352 ExprPrecedence::TryBlock |
8faf50e0 353 ExprPrecedence::Async |
0731742a
XL
354 ExprPrecedence::Struct |
355 ExprPrecedence::Err => PREC_PAREN,
2c00a5a8 356 }
ea8adc8c
XL
357 }
358}
359
dc9dc135 360/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
60c5eb7d 361pub fn prec_let_scrutinee_needs_par() -> usize {
dc9dc135
XL
362 AssocOp::LAnd.precedence()
363}
364
365/// Suppose we have `let _ = e` and the `order` of `e`.
366/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
367///
368/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
369/// Can we print this as `let _ = a OP b`?
370crate fn needs_par_as_let_scrutinee(order: i8) -> bool {
371 order <= prec_let_scrutinee_needs_par() as i8
372}
2c00a5a8 373
0731742a
XL
374/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
375/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
ea8adc8c
XL
376/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
377pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
e74abb32 378 match value.kind {
ea8adc8c
XL
379 ast::ExprKind::Struct(..) => true,
380
381 ast::ExprKind::Assign(ref lhs, ref rhs) |
382 ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
383 ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
384 // X { y: 1 } + X { y: 2 }
385 contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
386 }
416331ca 387 ast::ExprKind::Await(ref x) |
ea8adc8c
XL
388 ast::ExprKind::Unary(_, ref x) |
389 ast::ExprKind::Cast(ref x, _) |
390 ast::ExprKind::Type(ref x, _) |
391 ast::ExprKind::Field(ref x, _) |
ea8adc8c
XL
392 ast::ExprKind::Index(ref x, _) => {
393 // &X { y: 1 }, X { y: 1 }.y
394 contains_exterior_struct_lit(&x)
395 }
396
397 ast::ExprKind::MethodCall(.., ref exprs) => {
398 // X { y: 1 }.bar(...)
399 contains_exterior_struct_lit(&exprs[0])
400 }
401
402 _ => false,
403 }
404}