]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/util/parser.rs
Auto merge of #56862 - arielb1:fundamentally-clean, r=nikomatsakis
[rust.git] / src / libsyntax / util / parser.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 use parse::token::{Token, BinOpToken};
11 use symbol::keywords;
12 use ast::{self, BinOpKind};
13
14 /// Associative operator with precedence.
15 ///
16 /// This is the enum which specifies operator precedence and fixity to the parser.
17 #[derive(PartialEq, Debug)]
18 pub enum AssocOp {
19     /// `+`
20     Add,
21     /// `-`
22     Subtract,
23     /// `*`
24     Multiply,
25     /// `/`
26     Divide,
27     /// `%`
28     Modulus,
29     /// `&&`
30     LAnd,
31     /// `||`
32     LOr,
33     /// `^`
34     BitXor,
35     /// `&`
36     BitAnd,
37     /// `|`
38     BitOr,
39     /// `<<`
40     ShiftLeft,
41     /// `>>`
42     ShiftRight,
43     /// `==`
44     Equal,
45     /// `<`
46     Less,
47     /// `<=`
48     LessEqual,
49     /// `!=`
50     NotEqual,
51     /// `>`
52     Greater,
53     /// `>=`
54     GreaterEqual,
55     /// `=`
56     Assign,
57     /// `<-`
58     ObsoleteInPlace,
59     /// `?=` where ? is one of the BinOpToken
60     AssignOp(BinOpToken),
61     /// `as`
62     As,
63     /// `..` range
64     DotDot,
65     /// `..=` range
66     DotDotEq,
67     /// `:`
68     Colon,
69 }
70
71 #[derive(PartialEq, Debug)]
72 pub enum Fixity {
73     /// The operator is left-associative
74     Left,
75     /// The operator is right-associative
76     Right,
77     /// The operator is not associative
78     None
79 }
80
81 impl AssocOp {
82     /// Create a new AssocOP from a token
83     pub fn from_token(t: &Token) -> Option<AssocOp> {
84         use self::AssocOp::*;
85         match *t {
86             Token::BinOpEq(k) => Some(AssignOp(k)),
87             Token::LArrow => Some(ObsoleteInPlace),
88             Token::Eq => Some(Assign),
89             Token::BinOp(BinOpToken::Star) => Some(Multiply),
90             Token::BinOp(BinOpToken::Slash) => Some(Divide),
91             Token::BinOp(BinOpToken::Percent) => Some(Modulus),
92             Token::BinOp(BinOpToken::Plus) => Some(Add),
93             Token::BinOp(BinOpToken::Minus) => Some(Subtract),
94             Token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
95             Token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
96             Token::BinOp(BinOpToken::And) => Some(BitAnd),
97             Token::BinOp(BinOpToken::Caret) => Some(BitXor),
98             Token::BinOp(BinOpToken::Or) => Some(BitOr),
99             Token::Lt => Some(Less),
100             Token::Le => Some(LessEqual),
101             Token::Ge => Some(GreaterEqual),
102             Token::Gt => Some(Greater),
103             Token::EqEq => Some(Equal),
104             Token::Ne => Some(NotEqual),
105             Token::AndAnd => Some(LAnd),
106             Token::OrOr => Some(LOr),
107             Token::DotDot => Some(DotDot),
108             Token::DotDotEq => Some(DotDotEq),
109             // DotDotDot is no longer supported, but we need some way to display the error
110             Token::DotDotDot => Some(DotDotEq),
111             Token::Colon => Some(Colon),
112             _ if t.is_keyword(keywords::As) => Some(As),
113             _ => None
114         }
115     }
116
117     /// Create a new AssocOp from ast::BinOpKind.
118     pub fn from_ast_binop(op: BinOpKind) -> Self {
119         use self::AssocOp::*;
120         match op {
121             BinOpKind::Lt => Less,
122             BinOpKind::Gt => Greater,
123             BinOpKind::Le => LessEqual,
124             BinOpKind::Ge => GreaterEqual,
125             BinOpKind::Eq => Equal,
126             BinOpKind::Ne => NotEqual,
127             BinOpKind::Mul => Multiply,
128             BinOpKind::Div => Divide,
129             BinOpKind::Rem => Modulus,
130             BinOpKind::Add => Add,
131             BinOpKind::Sub => Subtract,
132             BinOpKind::Shl => ShiftLeft,
133             BinOpKind::Shr => ShiftRight,
134             BinOpKind::BitAnd => BitAnd,
135             BinOpKind::BitXor => BitXor,
136             BinOpKind::BitOr => BitOr,
137             BinOpKind::And => LAnd,
138             BinOpKind::Or => LOr
139         }
140     }
141
142     /// Gets the precedence of this operator
143     pub fn precedence(&self) -> usize {
144         use self::AssocOp::*;
145         match *self {
146             As | Colon => 14,
147             Multiply | Divide | Modulus => 13,
148             Add | Subtract => 12,
149             ShiftLeft | ShiftRight => 11,
150             BitAnd => 10,
151             BitXor => 9,
152             BitOr => 8,
153             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
154             LAnd => 6,
155             LOr => 5,
156             DotDot | DotDotEq => 4,
157             ObsoleteInPlace => 3,
158             Assign | AssignOp(_) => 2,
159         }
160     }
161
162     /// Gets the fixity of this operator
163     pub fn fixity(&self) -> Fixity {
164         use self::AssocOp::*;
165         // NOTE: it is a bug to have an operators that has same precedence but different fixities!
166         match *self {
167             ObsoleteInPlace | Assign | AssignOp(_) => Fixity::Right,
168             As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
169             BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
170             LAnd | LOr | Colon => Fixity::Left,
171             DotDot | DotDotEq => Fixity::None
172         }
173     }
174
175     pub fn is_comparison(&self) -> bool {
176         use self::AssocOp::*;
177         match *self {
178             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
179             ObsoleteInPlace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
180             Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
181             DotDot | DotDotEq | Colon => false
182         }
183     }
184
185     pub fn is_assign_like(&self) -> bool {
186         use self::AssocOp::*;
187         match *self {
188             Assign | AssignOp(_) | ObsoleteInPlace => true,
189             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
190             Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
191             LOr | DotDot | DotDotEq | Colon => false
192         }
193     }
194
195     pub fn to_ast_binop(&self) -> Option<BinOpKind> {
196         use self::AssocOp::*;
197         match *self {
198             Less => Some(BinOpKind::Lt),
199             Greater => Some(BinOpKind::Gt),
200             LessEqual => Some(BinOpKind::Le),
201             GreaterEqual => Some(BinOpKind::Ge),
202             Equal => Some(BinOpKind::Eq),
203             NotEqual => Some(BinOpKind::Ne),
204             Multiply => Some(BinOpKind::Mul),
205             Divide => Some(BinOpKind::Div),
206             Modulus => Some(BinOpKind::Rem),
207             Add => Some(BinOpKind::Add),
208             Subtract => Some(BinOpKind::Sub),
209             ShiftLeft => Some(BinOpKind::Shl),
210             ShiftRight => Some(BinOpKind::Shr),
211             BitAnd => Some(BinOpKind::BitAnd),
212             BitXor => Some(BinOpKind::BitXor),
213             BitOr => Some(BinOpKind::BitOr),
214             LAnd => Some(BinOpKind::And),
215             LOr => Some(BinOpKind::Or),
216             ObsoleteInPlace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
217         }
218     }
219 }
220
221 pub const PREC_RESET: i8 = -100;
222 pub const PREC_CLOSURE: i8 = -40;
223 pub const PREC_JUMP: i8 = -30;
224 pub const PREC_RANGE: i8 = -10;
225 // The range 2 ... 14 is reserved for AssocOp binary operator precedences.
226 pub const PREC_PREFIX: i8 = 50;
227 pub const PREC_POSTFIX: i8 = 60;
228 pub const PREC_PAREN: i8 = 99;
229 pub const PREC_FORCE_PAREN: i8 = 100;
230
231 #[derive(Debug, Clone, Copy)]
232 pub enum ExprPrecedence {
233     Closure,
234     Break,
235     Continue,
236     Ret,
237     Yield,
238
239     Range,
240
241     Binary(BinOpKind),
242
243     ObsoleteInPlace,
244     Cast,
245     Type,
246
247     Assign,
248     AssignOp,
249
250     Box,
251     AddrOf,
252     Unary,
253
254     Call,
255     MethodCall,
256     Field,
257     Index,
258     Try,
259     InlineAsm,
260     Mac,
261
262     Array,
263     Repeat,
264     Tup,
265     Lit,
266     Path,
267     Paren,
268     If,
269     IfLet,
270     While,
271     WhileLet,
272     ForLoop,
273     Loop,
274     Match,
275     Block,
276     TryBlock,
277     Struct,
278     Async,
279 }
280
281 impl ExprPrecedence {
282     pub fn order(self) -> i8 {
283         match self {
284             ExprPrecedence::Closure => PREC_CLOSURE,
285
286             ExprPrecedence::Break |
287             ExprPrecedence::Continue |
288             ExprPrecedence::Ret |
289             ExprPrecedence::Yield => PREC_JUMP,
290
291             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
292             // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
293             // ensures that `pprust` will add parentheses in the right places to get the desired
294             // parse.
295             ExprPrecedence::Range => PREC_RANGE,
296
297             // Binop-like expr kinds, handled by `AssocOp`.
298             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
299             ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
300             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
301             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
302
303             ExprPrecedence::Assign |
304             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
305
306             // Unary, prefix
307             ExprPrecedence::Box |
308             ExprPrecedence::AddrOf |
309             ExprPrecedence::Unary => PREC_PREFIX,
310
311             // Unary, postfix
312             ExprPrecedence::Call |
313             ExprPrecedence::MethodCall |
314             ExprPrecedence::Field |
315             ExprPrecedence::Index |
316             ExprPrecedence::Try |
317             ExprPrecedence::InlineAsm |
318             ExprPrecedence::Mac => PREC_POSTFIX,
319
320             // Never need parens
321             ExprPrecedence::Array |
322             ExprPrecedence::Repeat |
323             ExprPrecedence::Tup |
324             ExprPrecedence::Lit |
325             ExprPrecedence::Path |
326             ExprPrecedence::Paren |
327             ExprPrecedence::If |
328             ExprPrecedence::IfLet |
329             ExprPrecedence::While |
330             ExprPrecedence::WhileLet |
331             ExprPrecedence::ForLoop |
332             ExprPrecedence::Loop |
333             ExprPrecedence::Match |
334             ExprPrecedence::Block |
335             ExprPrecedence::TryBlock |
336             ExprPrecedence::Async |
337             ExprPrecedence::Struct => PREC_PAREN,
338         }
339     }
340 }
341
342
343 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
344 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
345 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
346 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
347     match value.node {
348         ast::ExprKind::Struct(..) => true,
349
350         ast::ExprKind::Assign(ref lhs, ref rhs) |
351         ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
352         ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
353             // X { y: 1 } + X { y: 2 }
354             contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
355         }
356         ast::ExprKind::Unary(_, ref x) |
357         ast::ExprKind::Cast(ref x, _) |
358         ast::ExprKind::Type(ref x, _) |
359         ast::ExprKind::Field(ref x, _) |
360         ast::ExprKind::Index(ref x, _) => {
361             // &X { y: 1 }, X { y: 1 }.y
362             contains_exterior_struct_lit(&x)
363         }
364
365         ast::ExprKind::MethodCall(.., ref exprs) => {
366             // X { y: 1 }.bar(...)
367             contains_exterior_struct_lit(&exprs[0])
368         }
369
370         _ => false,
371     }
372 }