1use rustc_span::kw;
2
3use crate::ast::{self, BinOpKind, RangeLimits};
4use crate::token::{self, Token};
5
6#[derive(Copy, Clone, PartialEq, Debug)]
8pub enum AssocOp {
9 Binary(BinOpKind),
11 AssignOp(BinOpKind),
13 Assign,
15 Cast,
17 Range(RangeLimits),
19}
20
21#[derive(PartialEq, Debug)]
22pub enum Fixity {
23 Left,
25 Right,
27 None,
29}
30
31impl AssocOp {
32 pub fn from_token(t: &Token) -> Option<AssocOp> {
34 use AssocOp::*;
35 match t.kind {
36 token::Eq => Some(Assign),
37 token::Plus => Some(Binary(BinOpKind::Add)),
38 token::Minus => Some(Binary(BinOpKind::Sub)),
39 token::Star => Some(Binary(BinOpKind::Mul)),
40 token::Slash => Some(Binary(BinOpKind::Div)),
41 token::Percent => Some(Binary(BinOpKind::Rem)),
42 token::Caret => Some(Binary(BinOpKind::BitXor)),
43 token::And => Some(Binary(BinOpKind::BitAnd)),
44 token::Or => Some(Binary(BinOpKind::BitOr)),
45 token::Shl => Some(Binary(BinOpKind::Shl)),
46 token::Shr => Some(Binary(BinOpKind::Shr)),
47 token::PlusEq => Some(AssignOp(BinOpKind::Add)),
48 token::MinusEq => Some(AssignOp(BinOpKind::Sub)),
49 token::StarEq => Some(AssignOp(BinOpKind::Mul)),
50 token::SlashEq => Some(AssignOp(BinOpKind::Div)),
51 token::PercentEq => Some(AssignOp(BinOpKind::Rem)),
52 token::CaretEq => Some(AssignOp(BinOpKind::BitXor)),
53 token::AndEq => Some(AssignOp(BinOpKind::BitAnd)),
54 token::OrEq => Some(AssignOp(BinOpKind::BitOr)),
55 token::ShlEq => Some(AssignOp(BinOpKind::Shl)),
56 token::ShrEq => Some(AssignOp(BinOpKind::Shr)),
57 token::Lt => Some(Binary(BinOpKind::Lt)),
58 token::Le => Some(Binary(BinOpKind::Le)),
59 token::Ge => Some(Binary(BinOpKind::Ge)),
60 token::Gt => Some(Binary(BinOpKind::Gt)),
61 token::EqEq => Some(Binary(BinOpKind::Eq)),
62 token::Ne => Some(Binary(BinOpKind::Ne)),
63 token::AndAnd => Some(Binary(BinOpKind::And)),
64 token::OrOr => Some(Binary(BinOpKind::Or)),
65 token::DotDot => Some(Range(RangeLimits::HalfOpen)),
66 token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)),
68 token::LArrow => Some(Binary(BinOpKind::Lt)),
70 _ if t.is_keyword(kw::As) => Some(Cast),
71 _ => None,
72 }
73 }
74
75 pub fn precedence(&self) -> ExprPrecedence {
77 use AssocOp::*;
78 match *self {
79 Cast => ExprPrecedence::Cast,
80 Binary(bin_op) => bin_op.precedence(),
81 Range(_) => ExprPrecedence::Range,
82 Assign | AssignOp(_) => ExprPrecedence::Assign,
83 }
84 }
85
86 pub fn fixity(&self) -> Fixity {
88 use AssocOp::*;
89 match *self {
91 Assign | AssignOp(_) => Fixity::Right,
92 Binary(binop) => binop.fixity(),
93 Cast => Fixity::Left,
94 Range(_) => Fixity::None,
95 }
96 }
97
98 pub fn is_comparison(&self) -> bool {
99 use AssocOp::*;
100 match *self {
101 Binary(binop) => binop.is_comparison(),
102 Assign | AssignOp(_) | Cast | Range(_) => false,
103 }
104 }
105
106 pub fn is_assign_like(&self) -> bool {
107 use AssocOp::*;
108 match *self {
109 Assign | AssignOp(_) => true,
110 Cast | Binary(_) | Range(_) => false,
111 }
112 }
113
114 pub fn can_continue_expr_unambiguously(&self) -> bool {
119 use AssocOp::*;
120 use BinOpKind::*;
121 matches!(
122 self,
123 Assign | Binary(
125 BitXor | Div | Rem | Shr | Le | Gt | Ge ) |
133 AssignOp(_) | Cast )
138 }
139}
140
141#[derive(Clone, Copy, PartialEq, PartialOrd)]
142pub enum ExprPrecedence {
143 Jump,
145 Assign,
147 Range,
149 LOr,
151 LAnd,
153 Compare,
155 BitOr,
157 BitXor,
159 BitAnd,
161 Shift,
163 Sum,
165 Product,
167 Cast,
169 Prefix,
171 Unambiguous,
173}
174
175pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
177 ExprPrecedence::LAnd
178}
179
180pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
186 order <= prec_let_scrutinee_needs_par()
187}
188
189pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
193 match &value.kind {
194 ast::ExprKind::Struct(..) => true,
195
196 ast::ExprKind::Assign(lhs, rhs, _)
197 | ast::ExprKind::AssignOp(_, lhs, rhs)
198 | ast::ExprKind::Binary(_, lhs, rhs) => {
199 contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
201 }
202 ast::ExprKind::Await(x, _)
203 | ast::ExprKind::Unary(_, x)
204 | ast::ExprKind::Cast(x, _)
205 | ast::ExprKind::Type(x, _)
206 | ast::ExprKind::Field(x, _)
207 | ast::ExprKind::Index(x, _, _)
208 | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {
209 contains_exterior_struct_lit(x)
211 }
212
213 ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {
214 contains_exterior_struct_lit(receiver)
216 }
217
218 _ => false,
219 }
220}