1 use crate::parse::token::{Token, BinOpToken};
2 use crate::symbol::keywords;
3 use crate::ast::{self, BinOpKind};
5 /// Associative operator with precedence.
7 /// This is the enum which specifies operator precedence and fixity to the parser.
8 #[derive(PartialEq, Debug)]
50 /// `?=` where ? is one of the BinOpToken
62 #[derive(PartialEq, Debug)]
64 /// The operator is left-associative
66 /// The operator is right-associative
68 /// The operator is not associative
73 /// Creates a new AssocOP from a token
74 pub fn from_token(t: &Token) -> Option<AssocOp> {
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),
108 /// Creates a new AssocOp from ast::BinOpKind.
109 pub fn from_ast_binop(op: BinOpKind) -> Self {
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,
133 /// Gets the precedence of this operator
134 pub fn precedence(&self) -> usize {
138 Multiply | Divide | Modulus => 13,
139 Add | Subtract => 12,
140 ShiftLeft | ShiftRight => 11,
144 Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
147 DotDot | DotDotEq => 4,
148 ObsoleteInPlace => 3,
149 Assign | AssignOp(_) => 2,
153 /// Gets the fixity of this operator
154 pub fn fixity(&self) -> Fixity {
156 // NOTE: it is a bug to have an operators that has same precedence but different fixities!
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
166 pub fn is_comparison(&self) -> bool {
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
176 pub fn is_assign_like(&self) -> bool {
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
186 pub fn to_ast_binop(&self) -> Option<BinOpKind> {
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
211 pub fn can_continue_expr_unambiguously(&self) -> bool {
214 BitXor | // `{ 42 } ^ 3`
215 Assign | // `{ 42 } = { 42 }`
216 Divide | // `{ 42 } / 42`
217 Modulus | // `{ 42 } % 2`
218 ShiftRight | // `{ 42 } >> 2`
219 LessEqual | // `{ 42 } <= 3`
220 Greater | // `{ 42 } > 3`
221 GreaterEqual | // `{ 42 } >= 3`
222 AssignOp(_) | // `{ 42 } +=`
223 LAnd | // `{ 42 } &&foo`
224 As | // `{ 42 } as usize`
225 // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
226 // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
227 Colon => true, // `{ 42 }: usize`
234 pub const PREC_RESET: i8 = -100;
235 pub const PREC_CLOSURE: i8 = -40;
236 pub const PREC_JUMP: i8 = -30;
237 pub const PREC_RANGE: i8 = -10;
238 // The range 2 ... 14 is reserved for AssocOp binary operator precedences.
239 pub const PREC_PREFIX: i8 = 50;
240 pub const PREC_POSTFIX: i8 = 60;
241 pub const PREC_PAREN: i8 = 99;
242 pub const PREC_FORCE_PAREN: i8 = 100;
244 #[derive(Debug, Clone, Copy)]
245 pub enum ExprPrecedence {
295 impl ExprPrecedence {
296 pub fn order(self) -> i8 {
298 ExprPrecedence::Closure => PREC_CLOSURE,
300 ExprPrecedence::Break |
301 ExprPrecedence::Continue |
302 ExprPrecedence::Ret |
303 ExprPrecedence::Yield => PREC_JUMP,
305 // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
306 // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
307 // ensures that `pprust` will add parentheses in the right places to get the desired
309 ExprPrecedence::Range => PREC_RANGE,
311 // Binop-like expr kinds, handled by `AssocOp`.
312 ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
313 ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
314 ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
315 ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
317 ExprPrecedence::Assign |
318 ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
321 ExprPrecedence::Box |
322 ExprPrecedence::AddrOf |
323 ExprPrecedence::Unary => PREC_PREFIX,
326 ExprPrecedence::Call |
327 ExprPrecedence::MethodCall |
328 ExprPrecedence::Field |
329 ExprPrecedence::Index |
330 ExprPrecedence::Try |
331 ExprPrecedence::InlineAsm |
332 ExprPrecedence::Mac => PREC_POSTFIX,
335 ExprPrecedence::Array |
336 ExprPrecedence::Repeat |
337 ExprPrecedence::Tup |
338 ExprPrecedence::Lit |
339 ExprPrecedence::Path |
340 ExprPrecedence::Paren |
342 ExprPrecedence::IfLet |
343 ExprPrecedence::While |
344 ExprPrecedence::WhileLet |
345 ExprPrecedence::ForLoop |
346 ExprPrecedence::Loop |
347 ExprPrecedence::Match |
348 ExprPrecedence::Block |
349 ExprPrecedence::TryBlock |
350 ExprPrecedence::Async |
351 ExprPrecedence::Struct |
352 ExprPrecedence::Err => PREC_PAREN,
358 /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
359 /// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
360 /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
361 pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
363 ast::ExprKind::Struct(..) => true,
365 ast::ExprKind::Assign(ref lhs, ref rhs) |
366 ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
367 ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
368 // X { y: 1 } + X { y: 2 }
369 contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
371 ast::ExprKind::Unary(_, ref x) |
372 ast::ExprKind::Cast(ref x, _) |
373 ast::ExprKind::Type(ref x, _) |
374 ast::ExprKind::Field(ref x, _) |
375 ast::ExprKind::Index(ref x, _) => {
376 // &X { y: 1 }, X { y: 1 }.y
377 contains_exterior_struct_lit(&x)
380 ast::ExprKind::MethodCall(.., ref exprs) => {
381 // X { y: 1 }.bar(...)
382 contains_exterior_struct_lit(&exprs[0])