]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/util/parser.rs
Add riscv64gc-unknown-none-elf target
[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     /// Create 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     /// Create 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
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     Err,
271 }
272
273 impl ExprPrecedence {
274     pub fn order(self) -> i8 {
275         match self {
276             ExprPrecedence::Closure => PREC_CLOSURE,
277
278             ExprPrecedence::Break |
279             ExprPrecedence::Continue |
280             ExprPrecedence::Ret |
281             ExprPrecedence::Yield => PREC_JUMP,
282
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,
288
289             // Binop-like expr kinds, handled by `AssocOp`.
290             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
291             ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
292             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
293             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
294
295             ExprPrecedence::Assign |
296             ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
297
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 |
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 |
327             ExprPrecedence::TryBlock |
328             ExprPrecedence::Async |
329             ExprPrecedence::Struct |
330             ExprPrecedence::Err => PREC_PAREN,
331         }
332     }
333 }
334
335
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
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, _) |
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 }