]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/util/parser.rs
New upstream version 1.27.1+dfsg1
[rustc.git] / src / libsyntax / util / parser.rs
CommitLineData
92a42be0
SL
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.
476ff2be
SL
10use parse::token::{Token, BinOpToken};
11use symbol::keywords;
2c00a5a8
XL
12use ast::{self, BinOpKind};
13
14use std::cmp::Ordering;
92a42be0
SL
15
16/// Associative operator with precedence.
17///
18/// This is the enum which specifies operator precedence and fixity to the parser.
19#[derive(Debug, PartialEq, Eq)]
20pub enum AssocOp {
21 /// `+`
22 Add,
23 /// `-`
24 Subtract,
25 /// `*`
26 Multiply,
27 /// `/`
28 Divide,
29 /// `%`
30 Modulus,
31 /// `&&`
32 LAnd,
33 /// `||`
34 LOr,
35 /// `^`
36 BitXor,
37 /// `&`
38 BitAnd,
39 /// `|`
40 BitOr,
41 /// `<<`
42 ShiftLeft,
43 /// `>>`
44 ShiftRight,
45 /// `==`
46 Equal,
47 /// `<`
48 Less,
49 /// `<=`
50 LessEqual,
51 /// `!=`
52 NotEqual,
53 /// `>`
54 Greater,
55 /// `>=`
56 GreaterEqual,
57 /// `=`
58 Assign,
59 /// `<-`
83c7162d 60 ObsoleteInPlace,
92a42be0
SL
61 /// `?=` where ? is one of the BinOpToken
62 AssignOp(BinOpToken),
63 /// `as`
64 As,
65 /// `..` range
9cc50fc6 66 DotDot,
ea8adc8c
XL
67 /// `..=` range
68 DotDotEq,
9cc50fc6
SL
69 /// `:`
70 Colon,
92a42be0
SL
71}
72
73#[derive(Debug, PartialEq, Eq)]
74pub enum Fixity {
75 /// The operator is left-associative
76 Left,
77 /// The operator is right-associative
78 Right,
79 /// The operator is not associative
80 None
81}
82
83impl AssocOp {
84 /// Create a new AssocOP from a token
85 pub fn from_token(t: &Token) -> Option<AssocOp> {
86 use self::AssocOp::*;
87 match *t {
88 Token::BinOpEq(k) => Some(AssignOp(k)),
83c7162d 89 Token::LArrow => Some(ObsoleteInPlace),
92a42be0
SL
90 Token::Eq => Some(Assign),
91 Token::BinOp(BinOpToken::Star) => Some(Multiply),
92 Token::BinOp(BinOpToken::Slash) => Some(Divide),
93 Token::BinOp(BinOpToken::Percent) => Some(Modulus),
94 Token::BinOp(BinOpToken::Plus) => Some(Add),
95 Token::BinOp(BinOpToken::Minus) => Some(Subtract),
96 Token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
97 Token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
98 Token::BinOp(BinOpToken::And) => Some(BitAnd),
99 Token::BinOp(BinOpToken::Caret) => Some(BitXor),
100 Token::BinOp(BinOpToken::Or) => Some(BitOr),
101 Token::Lt => Some(Less),
102 Token::Le => Some(LessEqual),
103 Token::Ge => Some(GreaterEqual),
104 Token::Gt => Some(Greater),
105 Token::EqEq => Some(Equal),
106 Token::Ne => Some(NotEqual),
107 Token::AndAnd => Some(LAnd),
108 Token::OrOr => Some(LOr),
109 Token::DotDot => Some(DotDot),
ea8adc8c 110 Token::DotDotEq => Some(DotDotEq),
abe05a73
XL
111 // DotDotDot is no longer supported, but we need some way to display the error
112 Token::DotDotDot => Some(DotDotEq),
9cc50fc6 113 Token::Colon => Some(Colon),
92a42be0
SL
114 _ if t.is_keyword(keywords::As) => Some(As),
115 _ => None
116 }
117 }
118
7453a54e
SL
119 /// Create a new AssocOp from ast::BinOpKind.
120 pub fn from_ast_binop(op: BinOpKind) -> Self {
92a42be0
SL
121 use self::AssocOp::*;
122 match op {
7453a54e
SL
123 BinOpKind::Lt => Less,
124 BinOpKind::Gt => Greater,
125 BinOpKind::Le => LessEqual,
126 BinOpKind::Ge => GreaterEqual,
127 BinOpKind::Eq => Equal,
128 BinOpKind::Ne => NotEqual,
129 BinOpKind::Mul => Multiply,
130 BinOpKind::Div => Divide,
131 BinOpKind::Rem => Modulus,
132 BinOpKind::Add => Add,
133 BinOpKind::Sub => Subtract,
134 BinOpKind::Shl => ShiftLeft,
135 BinOpKind::Shr => ShiftRight,
136 BinOpKind::BitAnd => BitAnd,
137 BinOpKind::BitXor => BitXor,
138 BinOpKind::BitOr => BitOr,
139 BinOpKind::And => LAnd,
140 BinOpKind::Or => LOr
92a42be0
SL
141 }
142 }
143
144 /// Gets the precedence of this operator
145 pub fn precedence(&self) -> usize {
146 use self::AssocOp::*;
147 match *self {
9cc50fc6 148 As | Colon => 14,
92a42be0
SL
149 Multiply | Divide | Modulus => 13,
150 Add | Subtract => 12,
151 ShiftLeft | ShiftRight => 11,
152 BitAnd => 10,
153 BitXor => 9,
154 BitOr => 8,
155 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
156 LAnd => 6,
157 LOr => 5,
ea8adc8c 158 DotDot | DotDotEq => 4,
83c7162d 159 ObsoleteInPlace => 3,
92a42be0
SL
160 Assign | AssignOp(_) => 2,
161 }
162 }
163
164 /// Gets the fixity of this operator
165 pub fn fixity(&self) -> Fixity {
166 use self::AssocOp::*;
167 // NOTE: it is a bug to have an operators that has same precedence but different fixities!
168 match *self {
83c7162d 169 ObsoleteInPlace | Assign | AssignOp(_) => Fixity::Right,
92a42be0
SL
170 As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
171 BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
9cc50fc6 172 LAnd | LOr | Colon => Fixity::Left,
ea8adc8c 173 DotDot | DotDotEq => Fixity::None
92a42be0
SL
174 }
175 }
176
177 pub fn is_comparison(&self) -> bool {
178 use self::AssocOp::*;
179 match *self {
180 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
83c7162d
XL
181 ObsoleteInPlace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
182 Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
ea8adc8c 183 DotDot | DotDotEq | Colon => false
92a42be0
SL
184 }
185 }
186
187 pub fn is_assign_like(&self) -> bool {
188 use self::AssocOp::*;
189 match *self {
83c7162d 190 Assign | AssignOp(_) | ObsoleteInPlace => true,
92a42be0
SL
191 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
192 Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
ea8adc8c 193 LOr | DotDot | DotDotEq | Colon => false
92a42be0
SL
194 }
195 }
196
7453a54e 197 pub fn to_ast_binop(&self) -> Option<BinOpKind> {
92a42be0
SL
198 use self::AssocOp::*;
199 match *self {
7453a54e
SL
200 Less => Some(BinOpKind::Lt),
201 Greater => Some(BinOpKind::Gt),
202 LessEqual => Some(BinOpKind::Le),
203 GreaterEqual => Some(BinOpKind::Ge),
204 Equal => Some(BinOpKind::Eq),
205 NotEqual => Some(BinOpKind::Ne),
206 Multiply => Some(BinOpKind::Mul),
207 Divide => Some(BinOpKind::Div),
208 Modulus => Some(BinOpKind::Rem),
209 Add => Some(BinOpKind::Add),
210 Subtract => Some(BinOpKind::Sub),
211 ShiftLeft => Some(BinOpKind::Shl),
212 ShiftRight => Some(BinOpKind::Shr),
213 BitAnd => Some(BinOpKind::BitAnd),
214 BitXor => Some(BinOpKind::BitXor),
215 BitOr => Some(BinOpKind::BitOr),
216 LAnd => Some(BinOpKind::And),
217 LOr => Some(BinOpKind::Or),
83c7162d 218 ObsoleteInPlace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
92a42be0
SL
219 }
220 }
92a42be0 221}
ea8adc8c
XL
222
223pub const PREC_RESET: i8 = -100;
224pub const PREC_CLOSURE: i8 = -40;
225pub const PREC_JUMP: i8 = -30;
226pub const PREC_RANGE: i8 = -10;
227// The range 2 ... 14 is reserved for AssocOp binary operator precedences.
228pub const PREC_PREFIX: i8 = 50;
229pub const PREC_POSTFIX: i8 = 60;
230pub const PREC_PAREN: i8 = 99;
231pub const PREC_FORCE_PAREN: i8 = 100;
232
2c00a5a8
XL
233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub enum ExprPrecedence {
235 Closure,
236 Break,
237 Continue,
238 Ret,
239 Yield,
240
241 Range,
242
243 Binary(BinOpKind),
244
83c7162d 245 ObsoleteInPlace,
2c00a5a8
XL
246 Cast,
247 Type,
248
249 Assign,
250 AssignOp,
251
252 Box,
253 AddrOf,
254 Unary,
255
256 Call,
257 MethodCall,
258 Field,
2c00a5a8
XL
259 Index,
260 Try,
261 InlineAsm,
262 Mac,
263
264 Array,
265 Repeat,
266 Tup,
267 Lit,
268 Path,
269 Paren,
270 If,
271 IfLet,
272 While,
273 WhileLet,
274 ForLoop,
275 Loop,
276 Match,
277 Block,
278 Catch,
279 Struct,
280}
ea8adc8c 281
2c00a5a8
XL
282impl PartialOrd for ExprPrecedence {
283 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
284 Some(self.order().cmp(&other.order()))
285 }
286}
ea8adc8c 287
2c00a5a8
XL
288impl Ord for ExprPrecedence {
289 fn cmp(&self, other: &Self) -> Ordering {
290 self.order().cmp(&other.order())
291 }
292}
ea8adc8c 293
2c00a5a8
XL
294impl ExprPrecedence {
295 pub fn order(self) -> i8 {
296 match self {
297 ExprPrecedence::Closure => PREC_CLOSURE,
ea8adc8c 298
2c00a5a8
XL
299 ExprPrecedence::Break |
300 ExprPrecedence::Continue |
301 ExprPrecedence::Ret |
302 ExprPrecedence::Yield => PREC_JUMP,
ea8adc8c 303
2c00a5a8
XL
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,
ea8adc8c 309
2c00a5a8
XL
310 // Binop-like expr kinds, handled by `AssocOp`.
311 ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
83c7162d 312 ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.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 |
322 ExprPrecedence::Unary => PREC_PREFIX,
323
324 // Unary, postfix
325 ExprPrecedence::Call |
326 ExprPrecedence::MethodCall |
327 ExprPrecedence::Field |
2c00a5a8
XL
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::Catch |
349 ExprPrecedence::Struct => PREC_PAREN,
350 }
ea8adc8c
XL
351 }
352}
353
2c00a5a8 354
ea8adc8c
XL
355/// Expressions that syntactically contain an "exterior" struct literal i.e. not surrounded by any
356/// parens or other delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
357/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
358pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
359 match value.node {
360 ast::ExprKind::Struct(..) => true,
361
362 ast::ExprKind::Assign(ref lhs, ref rhs) |
363 ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
364 ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
365 // X { y: 1 } + X { y: 2 }
366 contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
367 }
368 ast::ExprKind::Unary(_, ref x) |
369 ast::ExprKind::Cast(ref x, _) |
370 ast::ExprKind::Type(ref x, _) |
371 ast::ExprKind::Field(ref x, _) |
ea8adc8c
XL
372 ast::ExprKind::Index(ref x, _) => {
373 // &X { y: 1 }, X { y: 1 }.y
374 contains_exterior_struct_lit(&x)
375 }
376
377 ast::ExprKind::MethodCall(.., ref exprs) => {
378 // X { y: 1 }.bar(...)
379 contains_exterior_struct_lit(&exprs[0])
380 }
381
382 _ => false,
383 }
384}