]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/util/parser.rs
New upstream version 1.33.0+dfsg1
[rustc.git] / src / libsyntax / util / parser.rs
CommitLineData
476ff2be
SL
1use parse::token::{Token, BinOpToken};
2use symbol::keywords;
2c00a5a8
XL
3use ast::{self, BinOpKind};
4
92a42be0
SL
5/// Associative operator with precedence.
6///
7/// This is the enum which specifies operator precedence and fixity to the parser.
8faf50e0 8#[derive(PartialEq, Debug)]
92a42be0
SL
9pub 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 /// `<-`
83c7162d 49 ObsoleteInPlace,
92a42be0
SL
50 /// `?=` where ? is one of the BinOpToken
51 AssignOp(BinOpToken),
52 /// `as`
53 As,
54 /// `..` range
9cc50fc6 55 DotDot,
ea8adc8c
XL
56 /// `..=` range
57 DotDotEq,
9cc50fc6
SL
58 /// `:`
59 Colon,
92a42be0
SL
60}
61
8faf50e0 62#[derive(PartialEq, Debug)]
92a42be0
SL
63pub 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
72impl AssocOp {
73 /// Create a new AssocOP from a token
74 pub fn from_token(t: &Token) -> Option<AssocOp> {
75 use self::AssocOp::*;
76 match *t {
77 Token::BinOpEq(k) => Some(AssignOp(k)),
83c7162d 78 Token::LArrow => Some(ObsoleteInPlace),
92a42be0
SL
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),
ea8adc8c 99 Token::DotDotEq => Some(DotDotEq),
abe05a73
XL
100 // DotDotDot is no longer supported, but we need some way to display the error
101 Token::DotDotDot => Some(DotDotEq),
9cc50fc6 102 Token::Colon => Some(Colon),
92a42be0
SL
103 _ if t.is_keyword(keywords::As) => Some(As),
104 _ => None
105 }
106 }
107
7453a54e
SL
108 /// Create a new AssocOp from ast::BinOpKind.
109 pub fn from_ast_binop(op: BinOpKind) -> Self {
92a42be0
SL
110 use self::AssocOp::*;
111 match op {
7453a54e
SL
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
92a42be0
SL
130 }
131 }
132
133 /// Gets the precedence of this operator
134 pub fn precedence(&self) -> usize {
135 use self::AssocOp::*;
136 match *self {
9cc50fc6 137 As | Colon => 14,
92a42be0
SL
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,
ea8adc8c 147 DotDot | DotDotEq => 4,
83c7162d 148 ObsoleteInPlace => 3,
92a42be0
SL
149 Assign | AssignOp(_) => 2,
150 }
151 }
152
153 /// Gets the fixity of this operator
154 pub fn fixity(&self) -> Fixity {
155 use self::AssocOp::*;
156 // NOTE: it is a bug to have an operators that has same precedence but different fixities!
157 match *self {
83c7162d 158 ObsoleteInPlace | Assign | AssignOp(_) => Fixity::Right,
92a42be0
SL
159 As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
160 BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
9cc50fc6 161 LAnd | LOr | Colon => Fixity::Left,
ea8adc8c 162 DotDot | DotDotEq => Fixity::None
92a42be0
SL
163 }
164 }
165
166 pub fn is_comparison(&self) -> bool {
167 use self::AssocOp::*;
168 match *self {
169 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
83c7162d
XL
170 ObsoleteInPlace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
171 Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
ea8adc8c 172 DotDot | DotDotEq | Colon => false
92a42be0
SL
173 }
174 }
175
176 pub fn is_assign_like(&self) -> bool {
177 use self::AssocOp::*;
178 match *self {
83c7162d 179 Assign | AssignOp(_) | ObsoleteInPlace => true,
92a42be0
SL
180 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
181 Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
ea8adc8c 182 LOr | DotDot | DotDotEq | Colon => false
92a42be0
SL
183 }
184 }
185
7453a54e 186 pub fn to_ast_binop(&self) -> Option<BinOpKind> {
92a42be0
SL
187 use self::AssocOp::*;
188 match *self {
7453a54e
SL
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),
83c7162d 207 ObsoleteInPlace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
92a42be0
SL
208 }
209 }
92a42be0 210}
ea8adc8c
XL
211
212pub const PREC_RESET: i8 = -100;
213pub const PREC_CLOSURE: i8 = -40;
214pub const PREC_JUMP: i8 = -30;
215pub const PREC_RANGE: i8 = -10;
216// The range 2 ... 14 is reserved for AssocOp binary operator precedences.
217pub const PREC_PREFIX: i8 = 50;
218pub const PREC_POSTFIX: i8 = 60;
219pub const PREC_PAREN: i8 = 99;
220pub const PREC_FORCE_PAREN: i8 = 100;
221
8faf50e0 222#[derive(Debug, Clone, Copy)]
2c00a5a8
XL
223pub enum ExprPrecedence {
224 Closure,
225 Break,
226 Continue,
227 Ret,
228 Yield,
229
230 Range,
231
232 Binary(BinOpKind),
233
83c7162d 234 ObsoleteInPlace,
2c00a5a8
XL
235 Cast,
236 Type,
237
238 Assign,
239 AssignOp,
240
241 Box,
242 AddrOf,
243 Unary,
244
245 Call,
246 MethodCall,
247 Field,
2c00a5a8
XL
248 Index,
249 Try,
250 InlineAsm,
251 Mac,
252
253 Array,
254 Repeat,
255 Tup,
256 Lit,
257 Path,
258 Paren,
259 If,
260 IfLet,
261 While,
262 WhileLet,
263 ForLoop,
264 Loop,
265 Match,
266 Block,
b7449926 267 TryBlock,
2c00a5a8 268 Struct,
8faf50e0 269 Async,
0731742a 270 Err,
2c00a5a8 271}
ea8adc8c 272
2c00a5a8
XL
273impl ExprPrecedence {
274 pub fn order(self) -> i8 {
275 match self {
276 ExprPrecedence::Closure => PREC_CLOSURE,
ea8adc8c 277
2c00a5a8
XL
278 ExprPrecedence::Break |
279 ExprPrecedence::Continue |
280 ExprPrecedence::Ret |
281 ExprPrecedence::Yield => PREC_JUMP,
ea8adc8c 282
2c00a5a8
XL
283 // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
284 // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
285 // ensures that `pprust` will add parentheses in the right places to get the desired
286 // parse.
287 ExprPrecedence::Range => PREC_RANGE,
ea8adc8c 288
2c00a5a8
XL
289 // Binop-like expr kinds, handled by `AssocOp`.
290 ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
83c7162d 291 ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
2c00a5a8
XL
292 ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
293 ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
ea8adc8c 294
2c00a5a8
XL
295 ExprPrecedence::Assign |
296 ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
ea8adc8c 297
2c00a5a8
XL
298 // Unary, prefix
299 ExprPrecedence::Box |
300 ExprPrecedence::AddrOf |
301 ExprPrecedence::Unary => PREC_PREFIX,
302
303 // Unary, postfix
304 ExprPrecedence::Call |
305 ExprPrecedence::MethodCall |
306 ExprPrecedence::Field |
2c00a5a8
XL
307 ExprPrecedence::Index |
308 ExprPrecedence::Try |
309 ExprPrecedence::InlineAsm |
310 ExprPrecedence::Mac => PREC_POSTFIX,
311
312 // Never need parens
313 ExprPrecedence::Array |
314 ExprPrecedence::Repeat |
315 ExprPrecedence::Tup |
316 ExprPrecedence::Lit |
317 ExprPrecedence::Path |
318 ExprPrecedence::Paren |
319 ExprPrecedence::If |
320 ExprPrecedence::IfLet |
321 ExprPrecedence::While |
322 ExprPrecedence::WhileLet |
323 ExprPrecedence::ForLoop |
324 ExprPrecedence::Loop |
325 ExprPrecedence::Match |
326 ExprPrecedence::Block |
b7449926 327 ExprPrecedence::TryBlock |
8faf50e0 328 ExprPrecedence::Async |
0731742a
XL
329 ExprPrecedence::Struct |
330 ExprPrecedence::Err => PREC_PAREN,
2c00a5a8 331 }
ea8adc8c
XL
332 }
333}
334
2c00a5a8 335
0731742a
XL
336/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
337/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
ea8adc8c
XL
338/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
339pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
340 match value.node {
341 ast::ExprKind::Struct(..) => true,
342
343 ast::ExprKind::Assign(ref lhs, ref rhs) |
344 ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
345 ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
346 // X { y: 1 } + X { y: 2 }
347 contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
348 }
349 ast::ExprKind::Unary(_, ref x) |
350 ast::ExprKind::Cast(ref x, _) |
351 ast::ExprKind::Type(ref x, _) |
352 ast::ExprKind::Field(ref x, _) |
ea8adc8c
XL
353 ast::ExprKind::Index(ref x, _) => {
354 // &X { y: 1 }, X { y: 1 }.y
355 contains_exterior_struct_lit(&x)
356 }
357
358 ast::ExprKind::MethodCall(.., ref exprs) => {
359 // X { y: 1 }.bar(...)
360 contains_exterior_struct_lit(&exprs[0])
361 }
362
363 _ => false,
364 }
365}