2024-12-13 10:29:23 +11:00
|
|
|
use rustc_span::kw;
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2024-12-20 10:15:05 +11:00
|
|
|
use crate::ast::{self, AssignOpKind, BinOpKind, RangeLimits};
|
2024-12-20 07:28:16 +11:00
|
|
|
use crate::token::{self, Token};
|
2015-10-15 15:51:30 +03:00
|
|
|
|
2024-12-19 18:24:07 +11:00
|
|
|
/// Associative operator.
|
2020-06-22 21:01:49 +02:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2015-10-15 15:51:30 +03:00
|
|
|
pub enum AssocOp {
|
2024-12-19 18:24:07 +11:00
|
|
|
/// A binary op.
|
|
|
|
|
Binary(BinOpKind),
|
2024-12-19 16:24:06 +11:00
|
|
|
/// `?=` where ? is one of the assignable BinOps
|
2024-12-20 10:15:05 +11:00
|
|
|
AssignOp(AssignOpKind),
|
2024-12-19 18:24:07 +11:00
|
|
|
/// `=`
|
|
|
|
|
Assign,
|
2015-10-15 15:51:30 +03:00
|
|
|
/// `as`
|
2024-12-19 21:46:44 +11:00
|
|
|
Cast,
|
2024-12-19 21:42:46 +11:00
|
|
|
/// `..` or `..=` range
|
|
|
|
|
Range(RangeLimits),
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
|
|
|
|
|
2018-03-21 01:58:25 +03:00
|
|
|
#[derive(PartialEq, Debug)]
|
2015-10-15 15:51:30 +03:00
|
|
|
pub enum Fixity {
|
|
|
|
|
/// The operator is left-associative
|
|
|
|
|
Left,
|
|
|
|
|
/// The operator is right-associative
|
|
|
|
|
Right,
|
|
|
|
|
/// The operator is not associative
|
2019-12-22 17:42:04 -05:00
|
|
|
None,
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AssocOp {
|
2024-12-19 18:24:07 +11:00
|
|
|
/// Creates a new AssocOp from a token.
|
2019-10-15 22:48:13 +02:00
|
|
|
pub fn from_token(t: &Token) -> Option<AssocOp> {
|
2019-02-07 02:33:01 +09:00
|
|
|
use AssocOp::*;
|
2019-06-08 19:45:12 +03:00
|
|
|
match t.kind {
|
2019-05-24 02:04:56 +03:00
|
|
|
token::Eq => Some(Assign),
|
2024-12-20 07:28:16 +11:00
|
|
|
token::Plus => Some(Binary(BinOpKind::Add)),
|
|
|
|
|
token::Minus => Some(Binary(BinOpKind::Sub)),
|
|
|
|
|
token::Star => Some(Binary(BinOpKind::Mul)),
|
|
|
|
|
token::Slash => Some(Binary(BinOpKind::Div)),
|
|
|
|
|
token::Percent => Some(Binary(BinOpKind::Rem)),
|
|
|
|
|
token::Caret => Some(Binary(BinOpKind::BitXor)),
|
|
|
|
|
token::And => Some(Binary(BinOpKind::BitAnd)),
|
|
|
|
|
token::Or => Some(Binary(BinOpKind::BitOr)),
|
|
|
|
|
token::Shl => Some(Binary(BinOpKind::Shl)),
|
|
|
|
|
token::Shr => Some(Binary(BinOpKind::Shr)),
|
2024-12-20 10:15:05 +11:00
|
|
|
token::PlusEq => Some(AssignOp(AssignOpKind::AddAssign)),
|
|
|
|
|
token::MinusEq => Some(AssignOp(AssignOpKind::SubAssign)),
|
|
|
|
|
token::StarEq => Some(AssignOp(AssignOpKind::MulAssign)),
|
|
|
|
|
token::SlashEq => Some(AssignOp(AssignOpKind::DivAssign)),
|
|
|
|
|
token::PercentEq => Some(AssignOp(AssignOpKind::RemAssign)),
|
|
|
|
|
token::CaretEq => Some(AssignOp(AssignOpKind::BitXorAssign)),
|
|
|
|
|
token::AndEq => Some(AssignOp(AssignOpKind::BitAndAssign)),
|
|
|
|
|
token::OrEq => Some(AssignOp(AssignOpKind::BitOrAssign)),
|
|
|
|
|
token::ShlEq => Some(AssignOp(AssignOpKind::ShlAssign)),
|
|
|
|
|
token::ShrEq => Some(AssignOp(AssignOpKind::ShrAssign)),
|
2024-12-19 18:24:07 +11:00
|
|
|
token::Lt => Some(Binary(BinOpKind::Lt)),
|
|
|
|
|
token::Le => Some(Binary(BinOpKind::Le)),
|
|
|
|
|
token::Ge => Some(Binary(BinOpKind::Ge)),
|
|
|
|
|
token::Gt => Some(Binary(BinOpKind::Gt)),
|
|
|
|
|
token::EqEq => Some(Binary(BinOpKind::Eq)),
|
|
|
|
|
token::Ne => Some(Binary(BinOpKind::Ne)),
|
|
|
|
|
token::AndAnd => Some(Binary(BinOpKind::And)),
|
|
|
|
|
token::OrOr => Some(Binary(BinOpKind::Or)),
|
2024-12-19 21:42:46 +11:00
|
|
|
token::DotDot => Some(Range(RangeLimits::HalfOpen)),
|
2017-11-05 00:46:41 +01:00
|
|
|
// DotDotDot is no longer supported, but we need some way to display the error
|
2024-12-19 21:42:46 +11:00
|
|
|
token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)),
|
2019-08-11 23:37:05 +02:00
|
|
|
// `<-` should probably be `< -`
|
2024-12-19 18:24:07 +11:00
|
|
|
token::LArrow => Some(Binary(BinOpKind::Lt)),
|
2024-12-19 21:46:44 +11:00
|
|
|
_ if t.is_keyword(kw::As) => Some(Cast),
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => None,
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets the precedence of this operator
|
2024-11-28 12:47:18 -08:00
|
|
|
pub fn precedence(&self) -> ExprPrecedence {
|
2019-02-07 02:33:01 +09:00
|
|
|
use AssocOp::*;
|
2015-10-15 15:51:30 +03:00
|
|
|
match *self {
|
2024-12-19 21:46:44 +11:00
|
|
|
Cast => ExprPrecedence::Cast,
|
2024-12-19 18:24:07 +11:00
|
|
|
Binary(bin_op) => bin_op.precedence(),
|
2024-12-19 21:42:46 +11:00
|
|
|
Range(_) => ExprPrecedence::Range,
|
2024-11-28 12:47:18 -08:00
|
|
|
Assign | AssignOp(_) => ExprPrecedence::Assign,
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets the fixity of this operator
|
|
|
|
|
pub fn fixity(&self) -> Fixity {
|
2019-02-07 02:33:01 +09:00
|
|
|
use AssocOp::*;
|
2015-10-15 15:51:30 +03:00
|
|
|
// NOTE: it is a bug to have an operators that has same precedence but different fixities!
|
|
|
|
|
match *self {
|
2019-05-06 14:53:22 +01:00
|
|
|
Assign | AssignOp(_) => Fixity::Right,
|
2024-12-19 18:24:07 +11:00
|
|
|
Binary(binop) => binop.fixity(),
|
2024-12-19 21:46:44 +11:00
|
|
|
Cast => Fixity::Left,
|
2024-12-19 21:42:46 +11:00
|
|
|
Range(_) => Fixity::None,
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_comparison(&self) -> bool {
|
2019-02-07 02:33:01 +09:00
|
|
|
use AssocOp::*;
|
2015-10-15 15:51:30 +03:00
|
|
|
match *self {
|
2024-12-19 18:24:07 +11:00
|
|
|
Binary(binop) => binop.is_comparison(),
|
2024-12-19 21:46:44 +11:00
|
|
|
Assign | AssignOp(_) | Cast | Range(_) => false,
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-16 22:42:06 +03:00
|
|
|
pub fn is_assign_like(&self) -> bool {
|
2019-02-07 02:33:01 +09:00
|
|
|
use AssocOp::*;
|
2015-10-16 22:42:06 +03:00
|
|
|
match *self {
|
2019-05-06 14:53:22 +01:00
|
|
|
Assign | AssignOp(_) => true,
|
2024-12-19 21:46:44 +11:00
|
|
|
Cast | Binary(_) | Range(_) => false,
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-22 19:37:23 -07:00
|
|
|
|
2019-05-06 16:00:21 -07:00
|
|
|
/// This operator could be used to follow a block unambiguously.
|
|
|
|
|
///
|
|
|
|
|
/// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
|
|
|
|
|
/// parentheses while having a high degree of confidence on the correctness of the suggestion.
|
2019-04-22 19:37:23 -07:00
|
|
|
pub fn can_continue_expr_unambiguously(&self) -> bool {
|
|
|
|
|
use AssocOp::*;
|
2024-12-19 18:24:07 +11:00
|
|
|
use BinOpKind::*;
|
2021-11-06 01:31:32 +01:00
|
|
|
matches!(
|
|
|
|
|
self,
|
2019-04-22 19:37:23 -07:00
|
|
|
Assign | // `{ 42 } = { 42 }`
|
2024-12-19 18:24:07 +11:00
|
|
|
Binary(
|
|
|
|
|
BitXor | // `{ 42 } ^ 3`
|
|
|
|
|
Div | // `{ 42 } / 42`
|
|
|
|
|
Rem | // `{ 42 } % 2`
|
|
|
|
|
Shr | // `{ 42 } >> 2`
|
|
|
|
|
Le | // `{ 42 } <= 3`
|
|
|
|
|
Gt | // `{ 42 } > 3`
|
|
|
|
|
Ge // `{ 42 } >= 3`
|
|
|
|
|
) |
|
2019-04-22 19:37:23 -07:00
|
|
|
AssignOp(_) | // `{ 42 } +=`
|
|
|
|
|
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
|
2022-11-16 21:46:06 +01:00
|
|
|
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
|
2024-12-19 21:46:44 +11:00
|
|
|
Cast // `{ 42 } as usize`
|
2021-11-06 01:31:32 +01:00
|
|
|
)
|
2019-04-22 19:37:23 -07:00
|
|
|
}
|
2015-10-15 15:51:30 +03:00
|
|
|
}
|
2017-07-20 16:53:56 -04:00
|
|
|
|
2024-11-28 12:47:18 -08:00
|
|
|
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
|
|
|
|
pub enum ExprPrecedence {
|
2024-12-02 17:17:37 -08:00
|
|
|
// return, break, yield, closures
|
2024-11-28 12:47:18 -08:00
|
|
|
Jump,
|
|
|
|
|
// = += -= *= /= %= &= |= ^= <<= >>=
|
|
|
|
|
Assign,
|
|
|
|
|
// .. ..=
|
|
|
|
|
Range,
|
|
|
|
|
// ||
|
|
|
|
|
LOr,
|
|
|
|
|
// &&
|
|
|
|
|
LAnd,
|
|
|
|
|
// == != < > <= >=
|
|
|
|
|
Compare,
|
|
|
|
|
// |
|
|
|
|
|
BitOr,
|
|
|
|
|
// ^
|
|
|
|
|
BitXor,
|
|
|
|
|
// &
|
|
|
|
|
BitAnd,
|
|
|
|
|
// << >>
|
|
|
|
|
Shift,
|
|
|
|
|
// + -
|
|
|
|
|
Sum,
|
|
|
|
|
// * / %
|
|
|
|
|
Product,
|
|
|
|
|
// as
|
|
|
|
|
Cast,
|
|
|
|
|
// unary - * ! & &mut
|
|
|
|
|
Prefix,
|
|
|
|
|
// paths, loops, function calls, array indexing, field expressions, method calls
|
|
|
|
|
Unambiguous,
|
|
|
|
|
}
|
2017-07-20 16:53:56 -04:00
|
|
|
|
2021-10-17 12:04:01 +02:00
|
|
|
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
|
2024-11-28 12:47:18 -08:00
|
|
|
pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
|
|
|
|
|
ExprPrecedence::LAnd
|
2019-06-18 01:28:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Suppose we have `let _ = e` and the `order` of `e`.
|
2021-10-17 12:04:01 +02:00
|
|
|
/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
|
2019-06-18 01:28:20 +02:00
|
|
|
///
|
|
|
|
|
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
|
|
|
|
|
/// Can we print this as `let _ = a OP b`?
|
2024-11-28 12:47:18 -08:00
|
|
|
pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
|
|
|
|
|
order <= prec_let_scrutinee_needs_par()
|
2019-06-18 01:28:20 +02:00
|
|
|
}
|
2018-01-15 15:09:39 -08:00
|
|
|
|
2018-11-27 02:59:49 +00:00
|
|
|
/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
|
|
|
|
|
/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
|
2017-07-20 16:53:56 -04:00
|
|
|
/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
|
|
|
|
|
pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
|
2022-11-16 19:26:38 +00:00
|
|
|
match &value.kind {
|
2017-07-20 16:53:56 -04:00
|
|
|
ast::ExprKind::Struct(..) => true,
|
|
|
|
|
|
2022-11-16 19:26:38 +00:00
|
|
|
ast::ExprKind::Assign(lhs, rhs, _)
|
|
|
|
|
| ast::ExprKind::AssignOp(_, lhs, rhs)
|
|
|
|
|
| ast::ExprKind::Binary(_, lhs, rhs) => {
|
2017-07-20 16:53:56 -04:00
|
|
|
// X { y: 1 } + X { y: 2 }
|
2022-11-29 11:01:17 +00:00
|
|
|
contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
|
2017-07-20 16:53:56 -04:00
|
|
|
}
|
2023-04-25 18:59:16 +00:00
|
|
|
ast::ExprKind::Await(x, _)
|
2022-11-16 19:26:38 +00:00
|
|
|
| ast::ExprKind::Unary(_, x)
|
|
|
|
|
| ast::ExprKind::Cast(x, _)
|
|
|
|
|
| ast::ExprKind::Type(x, _)
|
|
|
|
|
| ast::ExprKind::Field(x, _)
|
2024-04-02 19:40:12 -04:00
|
|
|
| ast::ExprKind::Index(x, _, _)
|
|
|
|
|
| ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {
|
2017-07-20 16:53:56 -04:00
|
|
|
// &X { y: 1 }, X { y: 1 }.y
|
2022-11-29 11:01:17 +00:00
|
|
|
contains_exterior_struct_lit(x)
|
2017-07-20 16:53:56 -04:00
|
|
|
}
|
|
|
|
|
|
2022-11-16 19:26:38 +00:00
|
|
|
ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {
|
2017-07-20 16:53:56 -04:00
|
|
|
// X { y: 1 }.bar(...)
|
2022-11-29 11:01:17 +00:00
|
|
|
contains_exterior_struct_lit(receiver)
|
2017-07-20 16:53:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ => false,
|
|
|
|
|
}
|
|
|
|
|
}
|