]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/util/parser.rs
d76dede8155a0ddbe23b2eeb922bb3e58f0ccee4
[rust.git] / src / libsyntax / util / parser.rs
1 use crate::parse::token::{Token, BinOpToken};
2 use crate::symbol::keywords;
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(keywords::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     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
234 pub const PREC_RESET: i8 = -100;
235 pub const PREC_CLOSURE: i8 = -40;
236 pub const PREC_JUMP: i8 = -30;
237 pub const PREC_RANGE: i8 = -10;
238 // The range 2 ... 14 is reserved for AssocOp binary operator precedences.
239 pub const PREC_PREFIX: i8 = 50;
240 pub const PREC_POSTFIX: i8 = 60;
241 pub const PREC_PAREN: i8 = 99;
242 pub const PREC_FORCE_PAREN: i8 = 100;
243
244 #[derive(Debug, Clone, Copy)]
245 pub enum ExprPrecedence {
246     Closure,
247     Break,
248     Continue,
249     Ret,
250     Yield,
251
252     Range,
253
254     Binary(BinOpKind),
255
256     ObsoleteInPlace,
257     Cast,
258     Type,
259
260     Assign,
261     AssignOp,
262
263     Box,
264     AddrOf,
265     Unary,
266
267     Call,
268     MethodCall,
269     Field,
270     Index,
271     Try,
272     InlineAsm,
273     Mac,
274
275     Array,
276     Repeat,
277     Tup,
278     Lit,
279     Path,
280     Paren,
281     If,
282     IfLet,
283     While,
284     WhileLet,
285     ForLoop,
286     Loop,
287     Match,
288     Block,
289     TryBlock,
290     Struct,
291     Async,
292     Err,
293 }
294
295 impl ExprPrecedence {
296     pub fn order(self) -> i8 {
297         match self {
298             ExprPrecedence::Closure => PREC_CLOSURE,
299
300             ExprPrecedence::Break |
301             ExprPrecedence::Continue |
302             ExprPrecedence::Ret |
303             ExprPrecedence::Yield => PREC_JUMP,
304
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,
310
311             // Binop-like expr kinds, handled by `AssocOp`.
312             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
313             ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
314             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
315             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
316
317             ExprPrecedence::Assign |
318             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
319
320             // Unary, prefix
321             ExprPrecedence::Box |
322             ExprPrecedence::AddrOf |
323             ExprPrecedence::Unary => PREC_PREFIX,
324
325             // Unary, postfix
326             ExprPrecedence::Call |
327             ExprPrecedence::MethodCall |
328             ExprPrecedence::Field |
329             ExprPrecedence::Index |
330             ExprPrecedence::Try |
331             ExprPrecedence::InlineAsm |
332             ExprPrecedence::Mac => PREC_POSTFIX,
333
334             // Never need parens
335             ExprPrecedence::Array |
336             ExprPrecedence::Repeat |
337             ExprPrecedence::Tup |
338             ExprPrecedence::Lit |
339             ExprPrecedence::Path |
340             ExprPrecedence::Paren |
341             ExprPrecedence::If |
342             ExprPrecedence::IfLet |
343             ExprPrecedence::While |
344             ExprPrecedence::WhileLet |
345             ExprPrecedence::ForLoop |
346             ExprPrecedence::Loop |
347             ExprPrecedence::Match |
348             ExprPrecedence::Block |
349             ExprPrecedence::TryBlock |
350             ExprPrecedence::Async |
351             ExprPrecedence::Struct |
352             ExprPrecedence::Err => PREC_PAREN,
353         }
354     }
355 }
356
357
358 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
359 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
360 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
361 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
362     match value.node {
363         ast::ExprKind::Struct(..) => true,
364
365         ast::ExprKind::Assign(ref lhs, ref rhs) |
366         ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
367         ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
368             // X { y: 1 } + X { y: 2 }
369             contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
370         }
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 }