]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/util/parser.rs
Remove licenses
[rust.git] / src / libsyntax / util / parser.rs
1 use parse::token::{Token, BinOpToken};
2 use symbol::keywords;
3 use 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     /// 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)),
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     /// Create a new AssocOp from ast::BinOpKind.
109     pub fn from_ast_binop(op: BinOpKind) -> Self {
110         use self::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 self::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 self::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 self::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 self::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 self::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
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
222 #[derive(Debug, Clone, Copy)]
223 pub enum ExprPrecedence {
224     Closure,
225     Break,
226     Continue,
227     Ret,
228     Yield,
229
230     Range,
231
232     Binary(BinOpKind),
233
234     ObsoleteInPlace,
235     Cast,
236     Type,
237
238     Assign,
239     AssignOp,
240
241     Box,
242     AddrOf,
243     Unary,
244
245     Call,
246     MethodCall,
247     Field,
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,
267     TryBlock,
268     Struct,
269     Async,
270 }
271
272 impl ExprPrecedence {
273     pub fn order(self) -> i8 {
274         match self {
275             ExprPrecedence::Closure => PREC_CLOSURE,
276
277             ExprPrecedence::Break |
278             ExprPrecedence::Continue |
279             ExprPrecedence::Ret |
280             ExprPrecedence::Yield => PREC_JUMP,
281
282             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
283             // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
284             // ensures that `pprust` will add parentheses in the right places to get the desired
285             // parse.
286             ExprPrecedence::Range => PREC_RANGE,
287
288             // Binop-like expr kinds, handled by `AssocOp`.
289             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
290             ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
291             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
292             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
293
294             ExprPrecedence::Assign |
295             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
296
297             // Unary, prefix
298             ExprPrecedence::Box |
299             ExprPrecedence::AddrOf |
300             ExprPrecedence::Unary => PREC_PREFIX,
301
302             // Unary, postfix
303             ExprPrecedence::Call |
304             ExprPrecedence::MethodCall |
305             ExprPrecedence::Field |
306             ExprPrecedence::Index |
307             ExprPrecedence::Try |
308             ExprPrecedence::InlineAsm |
309             ExprPrecedence::Mac => PREC_POSTFIX,
310
311             // Never need parens
312             ExprPrecedence::Array |
313             ExprPrecedence::Repeat |
314             ExprPrecedence::Tup |
315             ExprPrecedence::Lit |
316             ExprPrecedence::Path |
317             ExprPrecedence::Paren |
318             ExprPrecedence::If |
319             ExprPrecedence::IfLet |
320             ExprPrecedence::While |
321             ExprPrecedence::WhileLet |
322             ExprPrecedence::ForLoop |
323             ExprPrecedence::Loop |
324             ExprPrecedence::Match |
325             ExprPrecedence::Block |
326             ExprPrecedence::TryBlock |
327             ExprPrecedence::Async |
328             ExprPrecedence::Struct => PREC_PAREN,
329         }
330     }
331 }
332
333
334 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
335 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
336 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
337 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
338     match value.node {
339         ast::ExprKind::Struct(..) => true,
340
341         ast::ExprKind::Assign(ref lhs, ref rhs) |
342         ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
343         ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
344             // X { y: 1 } + X { y: 2 }
345             contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
346         }
347         ast::ExprKind::Unary(_, ref x) |
348         ast::ExprKind::Cast(ref x, _) |
349         ast::ExprKind::Type(ref x, _) |
350         ast::ExprKind::Field(ref x, _) |
351         ast::ExprKind::Index(ref x, _) => {
352             // &X { y: 1 }, X { y: 1 }.y
353             contains_exterior_struct_lit(&x)
354         }
355
356         ast::ExprKind::MethodCall(.., ref exprs) => {
357             // X { y: 1 }.bar(...)
358             contains_exterior_struct_lit(&exprs[0])
359         }
360
361         _ => false,
362     }
363 }