]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/util/parser.rs
8dc9ce39915adf31924a78daeb02f7fd284d1a29
[rust.git] / src / libsyntax / util / parser.rs
1 use crate::parse::token::{self, Token, BinOpToken};
2 use crate::symbol::kw;
3 use crate::ast::{self, BinOpKind};
4
5 /// Associative operator with precedence.
6 ///
7 /// This is the enum which specifies operator precedence and fixity to the parser.
8 #[derive(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 {
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             _ if t.is_keyword(kw::As) => Some(As),
101             _ => None
102         }
103     }
104
105     /// Creates a new AssocOp from ast::BinOpKind.
106     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     /// Gets the precedence of this operator
131     pub fn precedence(&self) -> usize {
132         use AssocOp::*;
133         match *self {
134             As | Colon => 14,
135             Multiply | Divide | Modulus => 13,
136             Add | Subtract => 12,
137             ShiftLeft | ShiftRight => 11,
138             BitAnd => 10,
139             BitXor => 9,
140             BitOr => 8,
141             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
142             LAnd => 6,
143             LOr => 5,
144             DotDot | DotDotEq => 4,
145             Assign | AssignOp(_) => 2,
146         }
147     }
148
149     /// Gets the fixity of this operator
150     pub fn fixity(&self) -> Fixity {
151         use AssocOp::*;
152         // NOTE: it is a bug to have an operators that has same precedence but different fixities!
153         match *self {
154             Assign | AssignOp(_) => Fixity::Right,
155             As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
156             BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
157             LAnd | LOr | Colon => Fixity::Left,
158             DotDot | DotDotEq => Fixity::None
159         }
160     }
161
162     pub fn is_comparison(&self) -> bool {
163         use AssocOp::*;
164         match *self {
165             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
166             Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
167             Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
168             DotDot | DotDotEq | Colon => false
169         }
170     }
171
172     pub fn is_assign_like(&self) -> bool {
173         use AssocOp::*;
174         match *self {
175             Assign | AssignOp(_) => true,
176             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
177             Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
178             LOr | DotDot | DotDotEq | Colon => false
179         }
180     }
181
182     pub fn to_ast_binop(&self) -> Option<BinOpKind> {
183         use AssocOp::*;
184         match *self {
185             Less => Some(BinOpKind::Lt),
186             Greater => Some(BinOpKind::Gt),
187             LessEqual => Some(BinOpKind::Le),
188             GreaterEqual => Some(BinOpKind::Ge),
189             Equal => Some(BinOpKind::Eq),
190             NotEqual => Some(BinOpKind::Ne),
191             Multiply => Some(BinOpKind::Mul),
192             Divide => Some(BinOpKind::Div),
193             Modulus => Some(BinOpKind::Rem),
194             Add => Some(BinOpKind::Add),
195             Subtract => Some(BinOpKind::Sub),
196             ShiftLeft => Some(BinOpKind::Shl),
197             ShiftRight => Some(BinOpKind::Shr),
198             BitAnd => Some(BinOpKind::BitAnd),
199             BitXor => Some(BinOpKind::BitXor),
200             BitOr => Some(BinOpKind::BitOr),
201             LAnd => Some(BinOpKind::And),
202             LOr => Some(BinOpKind::Or),
203             Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
204         }
205     }
206
207     /// This operator could be used to follow a block unambiguously.
208     ///
209     /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
210     /// parentheses while having a high degree of confidence on the correctness of the suggestion.
211     pub fn can_continue_expr_unambiguously(&self) -> bool {
212         use AssocOp::*;
213         match self {
214             BitXor | // `{ 42 } ^ 3`
215             Assign | // `{ 42 } = { 42 }`
216             Divide | // `{ 42 } / 42`
217             Modulus | // `{ 42 } % 2`
218             ShiftRight | // `{ 42 } >> 2`
219             LessEqual | // `{ 42 } <= 3`
220             Greater | // `{ 42 } > 3`
221             GreaterEqual | // `{ 42 } >= 3`
222             AssignOp(_) | // `{ 42 } +=`
223             LAnd | // `{ 42 } &&foo`
224             As | // `{ 42 } as usize`
225             // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
226             // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
227             Colon => true, // `{ 42 }: usize`
228             _ => false,
229         }
230     }
231 }
232
233 pub const PREC_RESET: i8 = -100;
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
251     Range,
252
253     Binary(BinOpKind),
254
255     Cast,
256     Type,
257
258     Assign,
259     AssignOp,
260
261     Box,
262     AddrOf,
263     Unary,
264
265     Call,
266     MethodCall,
267     Field,
268     Index,
269     Try,
270     InlineAsm,
271     Mac,
272
273     Array,
274     Repeat,
275     Tup,
276     Lit,
277     Path,
278     Paren,
279     If,
280     IfLet,
281     While,
282     WhileLet,
283     ForLoop,
284     Loop,
285     Match,
286     Block,
287     TryBlock,
288     Struct,
289     Async,
290     Await,
291     Err,
292 }
293
294 impl ExprPrecedence {
295     pub fn order(self) -> i8 {
296         match self {
297             ExprPrecedence::Closure => PREC_CLOSURE,
298
299             ExprPrecedence::Break |
300             ExprPrecedence::Continue |
301             ExprPrecedence::Ret |
302             ExprPrecedence::Yield => PREC_JUMP,
303
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
307             // parse.
308             ExprPrecedence::Range => PREC_RANGE,
309
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,
314
315             ExprPrecedence::Assign |
316             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
317
318             // Unary, prefix
319             ExprPrecedence::Box |
320             ExprPrecedence::AddrOf |
321             ExprPrecedence::Unary => PREC_PREFIX,
322
323             // Unary, postfix
324             ExprPrecedence::Await |
325             ExprPrecedence::Call |
326             ExprPrecedence::MethodCall |
327             ExprPrecedence::Field |
328             ExprPrecedence::Index |
329             ExprPrecedence::Try |
330             ExprPrecedence::InlineAsm |
331             ExprPrecedence::Mac => PREC_POSTFIX,
332
333             // Never need parens
334             ExprPrecedence::Array |
335             ExprPrecedence::Repeat |
336             ExprPrecedence::Tup |
337             ExprPrecedence::Lit |
338             ExprPrecedence::Path |
339             ExprPrecedence::Paren |
340             ExprPrecedence::If |
341             ExprPrecedence::IfLet |
342             ExprPrecedence::While |
343             ExprPrecedence::WhileLet |
344             ExprPrecedence::ForLoop |
345             ExprPrecedence::Loop |
346             ExprPrecedence::Match |
347             ExprPrecedence::Block |
348             ExprPrecedence::TryBlock |
349             ExprPrecedence::Async |
350             ExprPrecedence::Struct |
351             ExprPrecedence::Err => PREC_PAREN,
352         }
353     }
354 }
355
356
357 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
358 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
359 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
360 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
361     match value.node {
362         ast::ExprKind::Struct(..) => true,
363
364         ast::ExprKind::Assign(ref lhs, ref rhs) |
365         ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
366         ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
367             // X { y: 1 } + X { y: 2 }
368             contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
369         }
370         ast::ExprKind::Await(_, ref x) |
371         ast::ExprKind::Unary(_, ref x) |
372         ast::ExprKind::Cast(ref x, _) |
373         ast::ExprKind::Type(ref x, _) |
374         ast::ExprKind::Field(ref x, _) |
375         ast::ExprKind::Index(ref x, _) => {
376             // &X { y: 1 }, X { y: 1 }.y
377             contains_exterior_struct_lit(&x)
378         }
379
380         ast::ExprKind::MethodCall(.., ref exprs) => {
381             // X { y: 1 }.bar(...)
382             contains_exterior_struct_lit(&exprs[0])
383         }
384
385         _ => false,
386     }
387 }