]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/util/parser.rs
6789fea28cad6daf1798c2da3e1c31d5e9282931
[rust.git] / src / libsyntax / util / parser.rs
1 use crate::parse::token::{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     /// `<-`
49     ObsoleteInPlace,
50     /// `?=` where ? is one of the BinOpToken
51     AssignOp(BinOpToken),
52     /// `as`
53     As,
54     /// `..` range
55     DotDot,
56     /// `..=` range
57     DotDotEq,
58     /// `:`
59     Colon,
60 }
61
62 #[derive(PartialEq, Debug)]
63 pub enum Fixity {
64     /// The operator is left-associative
65     Left,
66     /// The operator is right-associative
67     Right,
68     /// The operator is not associative
69     None
70 }
71
72 impl AssocOp {
73     /// Creates a new AssocOP from a token
74     pub fn from_token(t: &Token) -> Option<AssocOp> {
75         use AssocOp::*;
76         match *t {
77             Token::BinOpEq(k) => Some(AssignOp(k)),
78             Token::LArrow => Some(ObsoleteInPlace),
79             Token::Eq => Some(Assign),
80             Token::BinOp(BinOpToken::Star) => Some(Multiply),
81             Token::BinOp(BinOpToken::Slash) => Some(Divide),
82             Token::BinOp(BinOpToken::Percent) => Some(Modulus),
83             Token::BinOp(BinOpToken::Plus) => Some(Add),
84             Token::BinOp(BinOpToken::Minus) => Some(Subtract),
85             Token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
86             Token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
87             Token::BinOp(BinOpToken::And) => Some(BitAnd),
88             Token::BinOp(BinOpToken::Caret) => Some(BitXor),
89             Token::BinOp(BinOpToken::Or) => Some(BitOr),
90             Token::Lt => Some(Less),
91             Token::Le => Some(LessEqual),
92             Token::Ge => Some(GreaterEqual),
93             Token::Gt => Some(Greater),
94             Token::EqEq => Some(Equal),
95             Token::Ne => Some(NotEqual),
96             Token::AndAnd => Some(LAnd),
97             Token::OrOr => Some(LOr),
98             Token::DotDot => Some(DotDot),
99             Token::DotDotEq => Some(DotDotEq),
100             // DotDotDot is no longer supported, but we need some way to display the error
101             Token::DotDotDot => Some(DotDotEq),
102             Token::Colon => Some(Colon),
103             _ if t.is_keyword(kw::As) => Some(As),
104             _ => None
105         }
106     }
107
108     /// Creates a new AssocOp from ast::BinOpKind.
109     pub fn from_ast_binop(op: BinOpKind) -> Self {
110         use AssocOp::*;
111         match op {
112             BinOpKind::Lt => Less,
113             BinOpKind::Gt => Greater,
114             BinOpKind::Le => LessEqual,
115             BinOpKind::Ge => GreaterEqual,
116             BinOpKind::Eq => Equal,
117             BinOpKind::Ne => NotEqual,
118             BinOpKind::Mul => Multiply,
119             BinOpKind::Div => Divide,
120             BinOpKind::Rem => Modulus,
121             BinOpKind::Add => Add,
122             BinOpKind::Sub => Subtract,
123             BinOpKind::Shl => ShiftLeft,
124             BinOpKind::Shr => ShiftRight,
125             BinOpKind::BitAnd => BitAnd,
126             BinOpKind::BitXor => BitXor,
127             BinOpKind::BitOr => BitOr,
128             BinOpKind::And => LAnd,
129             BinOpKind::Or => LOr
130         }
131     }
132
133     /// Gets the precedence of this operator
134     pub fn precedence(&self) -> usize {
135         use AssocOp::*;
136         match *self {
137             As | Colon => 14,
138             Multiply | Divide | Modulus => 13,
139             Add | Subtract => 12,
140             ShiftLeft | ShiftRight => 11,
141             BitAnd => 10,
142             BitXor => 9,
143             BitOr => 8,
144             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
145             LAnd => 6,
146             LOr => 5,
147             DotDot | DotDotEq => 4,
148             ObsoleteInPlace => 3,
149             Assign | AssignOp(_) => 2,
150         }
151     }
152
153     /// Gets the fixity of this operator
154     pub fn fixity(&self) -> Fixity {
155         use AssocOp::*;
156         // NOTE: it is a bug to have an operators that has same precedence but different fixities!
157         match *self {
158             ObsoleteInPlace | Assign | AssignOp(_) => Fixity::Right,
159             As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
160             BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
161             LAnd | LOr | Colon => Fixity::Left,
162             DotDot | DotDotEq => Fixity::None
163         }
164     }
165
166     pub fn is_comparison(&self) -> bool {
167         use AssocOp::*;
168         match *self {
169             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
170             ObsoleteInPlace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
171             Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
172             DotDot | DotDotEq | Colon => false
173         }
174     }
175
176     pub fn is_assign_like(&self) -> bool {
177         use AssocOp::*;
178         match *self {
179             Assign | AssignOp(_) | ObsoleteInPlace => true,
180             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
181             Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
182             LOr | DotDot | DotDotEq | Colon => false
183         }
184     }
185
186     pub fn to_ast_binop(&self) -> Option<BinOpKind> {
187         use AssocOp::*;
188         match *self {
189             Less => Some(BinOpKind::Lt),
190             Greater => Some(BinOpKind::Gt),
191             LessEqual => Some(BinOpKind::Le),
192             GreaterEqual => Some(BinOpKind::Ge),
193             Equal => Some(BinOpKind::Eq),
194             NotEqual => Some(BinOpKind::Ne),
195             Multiply => Some(BinOpKind::Mul),
196             Divide => Some(BinOpKind::Div),
197             Modulus => Some(BinOpKind::Rem),
198             Add => Some(BinOpKind::Add),
199             Subtract => Some(BinOpKind::Sub),
200             ShiftLeft => Some(BinOpKind::Shl),
201             ShiftRight => Some(BinOpKind::Shr),
202             BitAnd => Some(BinOpKind::BitAnd),
203             BitXor => Some(BinOpKind::BitXor),
204             BitOr => Some(BinOpKind::BitOr),
205             LAnd => Some(BinOpKind::And),
206             LOr => Some(BinOpKind::Or),
207             ObsoleteInPlace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
208         }
209     }
210
211     /// This operator could be used to follow a block unambiguously.
212     ///
213     /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
214     /// parentheses while having a high degree of confidence on the correctness of the suggestion.
215     pub fn can_continue_expr_unambiguously(&self) -> bool {
216         use AssocOp::*;
217         match self {
218             BitXor | // `{ 42 } ^ 3`
219             Assign | // `{ 42 } = { 42 }`
220             Divide | // `{ 42 } / 42`
221             Modulus | // `{ 42 } % 2`
222             ShiftRight | // `{ 42 } >> 2`
223             LessEqual | // `{ 42 } <= 3`
224             Greater | // `{ 42 } > 3`
225             GreaterEqual | // `{ 42 } >= 3`
226             AssignOp(_) | // `{ 42 } +=`
227             LAnd | // `{ 42 } &&foo`
228             As | // `{ 42 } as usize`
229             // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
230             // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
231             Colon => true, // `{ 42 }: usize`
232             _ => false,
233         }
234     }
235 }
236
237 pub const PREC_RESET: i8 = -100;
238 pub const PREC_CLOSURE: i8 = -40;
239 pub const PREC_JUMP: i8 = -30;
240 pub const PREC_RANGE: i8 = -10;
241 // The range 2 ... 14 is reserved for AssocOp binary operator precedences.
242 pub const PREC_PREFIX: i8 = 50;
243 pub const PREC_POSTFIX: i8 = 60;
244 pub const PREC_PAREN: i8 = 99;
245 pub const PREC_FORCE_PAREN: i8 = 100;
246
247 #[derive(Debug, Clone, Copy)]
248 pub enum ExprPrecedence {
249     Closure,
250     Break,
251     Continue,
252     Ret,
253     Yield,
254
255     Range,
256
257     Binary(BinOpKind),
258
259     ObsoleteInPlace,
260     Cast,
261     Type,
262
263     Assign,
264     AssignOp,
265
266     Box,
267     AddrOf,
268     Unary,
269
270     Call,
271     MethodCall,
272     Field,
273     Index,
274     Try,
275     InlineAsm,
276     Mac,
277
278     Array,
279     Repeat,
280     Tup,
281     Lit,
282     Path,
283     Paren,
284     If,
285     IfLet,
286     While,
287     WhileLet,
288     ForLoop,
289     Loop,
290     Match,
291     Block,
292     TryBlock,
293     Struct,
294     Async,
295     Await,
296     Err,
297 }
298
299 impl ExprPrecedence {
300     pub fn order(self) -> i8 {
301         match self {
302             ExprPrecedence::Closure => PREC_CLOSURE,
303
304             ExprPrecedence::Break |
305             ExprPrecedence::Continue |
306             ExprPrecedence::Ret |
307             ExprPrecedence::Yield => PREC_JUMP,
308
309             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
310             // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
311             // ensures that `pprust` will add parentheses in the right places to get the desired
312             // parse.
313             ExprPrecedence::Range => PREC_RANGE,
314
315             // Binop-like expr kinds, handled by `AssocOp`.
316             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
317             ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
318             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
319             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
320
321             ExprPrecedence::Assign |
322             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
323
324             // Unary, prefix
325             ExprPrecedence::Box |
326             ExprPrecedence::AddrOf |
327             ExprPrecedence::Unary => PREC_PREFIX,
328
329             // Unary, postfix
330             ExprPrecedence::Await |
331             ExprPrecedence::Call |
332             ExprPrecedence::MethodCall |
333             ExprPrecedence::Field |
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 |
347             ExprPrecedence::IfLet |
348             ExprPrecedence::While |
349             ExprPrecedence::WhileLet |
350             ExprPrecedence::ForLoop |
351             ExprPrecedence::Loop |
352             ExprPrecedence::Match |
353             ExprPrecedence::Block |
354             ExprPrecedence::TryBlock |
355             ExprPrecedence::Async |
356             ExprPrecedence::Struct |
357             ExprPrecedence::Err => PREC_PAREN,
358         }
359     }
360 }
361
362
363 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
364 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
365 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
366 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
367     match value.node {
368         ast::ExprKind::Struct(..) => true,
369
370         ast::ExprKind::Assign(ref lhs, ref rhs) |
371         ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
372         ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
373             // X { y: 1 } + X { y: 2 }
374             contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
375         }
376         ast::ExprKind::Await(_, ref x) |
377         ast::ExprKind::Unary(_, ref x) |
378         ast::ExprKind::Cast(ref x, _) |
379         ast::ExprKind::Type(ref x, _) |
380         ast::ExprKind::Field(ref x, _) |
381         ast::ExprKind::Index(ref x, _) => {
382             // &X { y: 1 }, X { y: 1 }.y
383             contains_exterior_struct_lit(&x)
384         }
385
386         ast::ExprKind::MethodCall(.., ref exprs) => {
387             // X { y: 1 }.bar(...)
388             contains_exterior_struct_lit(&exprs[0])
389         }
390
391         _ => false,
392     }
393 }