]>
Commit | Line | Data |
---|---|---|
476ff2be SL |
1 | use parse::token::{Token, BinOpToken}; |
2 | use symbol::keywords; | |
2c00a5a8 XL |
3 | use 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 |
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 | /// `<-` | |
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 |
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 | /// 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 | |
212 | pub const PREC_RESET: i8 = -100; | |
213 | pub const PREC_CLOSURE: i8 = -40; | |
214 | pub const PREC_JUMP: i8 = -30; | |
215 | pub const PREC_RANGE: i8 = -10; | |
216 | // The range 2 ... 14 is reserved for AssocOp binary operator precedences. | |
217 | pub const PREC_PREFIX: i8 = 50; | |
218 | pub const PREC_POSTFIX: i8 = 60; | |
219 | pub const PREC_PAREN: i8 = 99; | |
220 | pub const PREC_FORCE_PAREN: i8 = 100; | |
221 | ||
8faf50e0 | 222 | #[derive(Debug, Clone, Copy)] |
2c00a5a8 XL |
223 | pub 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 |
273 | impl 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. |
339 | pub 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 | } |