1use stdx::always;
4
5use crate::{
6 AstNode, Direction, SyntaxNode, T,
7 algo::skip_trivia_token,
8 ast::{self, BinaryOp, Expr, HasArgList, RangeItem},
9 match_ast,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
13pub enum ExprPrecedence {
14 Jump,
16 Assign,
18 Range,
20 LOr,
22 LAnd,
24 Compare,
26 BitOr,
28 BitXor,
30 BitAnd,
32 Shift,
34 Sum,
36 Product,
38 Cast,
40 Prefix,
42 Postfix,
44 Unambiguous,
46}
47
48impl ExprPrecedence {
49 pub fn needs_parentheses_in(self, other: ExprPrecedence) -> bool {
50 match other {
51 ExprPrecedence::Unambiguous => false,
52 ExprPrecedence::Postfix => self < ExprPrecedence::Postfix,
55 ExprPrecedence::Prefix => ExprPrecedence::Jump < self && self < ExprPrecedence::Prefix,
58 parent => self <= parent,
59 }
60 }
61}
62
63#[derive(PartialEq, Debug)]
64pub enum Fixity {
65 Left,
67 Right,
69 None,
71}
72
73pub fn precedence(expr: &ast::Expr) -> ExprPrecedence {
74 match expr {
75 Expr::ClosureExpr(closure) => match closure.ret_type() {
76 None => ExprPrecedence::Jump,
77 Some(_) => ExprPrecedence::Unambiguous,
78 },
79
80 Expr::BreakExpr(_)
81 | Expr::BecomeExpr(_)
82 | Expr::ReturnExpr(_)
83 | Expr::YeetExpr(_)
84 | Expr::YieldExpr(_)
85 | Expr::ContinueExpr(_) => ExprPrecedence::Jump,
86
87 Expr::RangeExpr(..) => ExprPrecedence::Range,
88
89 Expr::BinExpr(bin_expr) => match bin_expr.op_kind() {
90 Some(it) => match it {
91 BinaryOp::LogicOp(logic_op) => match logic_op {
92 ast::LogicOp::And => ExprPrecedence::LAnd,
93 ast::LogicOp::Or => ExprPrecedence::LOr,
94 },
95 BinaryOp::ArithOp(arith_op) => match arith_op {
96 ast::ArithOp::Add | ast::ArithOp::Sub => ExprPrecedence::Sum,
97 ast::ArithOp::Div | ast::ArithOp::Rem | ast::ArithOp::Mul => {
98 ExprPrecedence::Product
99 }
100 ast::ArithOp::Shl | ast::ArithOp::Shr => ExprPrecedence::Shift,
101 ast::ArithOp::BitXor => ExprPrecedence::BitXor,
102 ast::ArithOp::BitOr => ExprPrecedence::BitOr,
103 ast::ArithOp::BitAnd => ExprPrecedence::BitAnd,
104 },
105 BinaryOp::CmpOp(_) => ExprPrecedence::Compare,
106 BinaryOp::Assignment { .. } => ExprPrecedence::Assign,
107 },
108 None => ExprPrecedence::Unambiguous,
109 },
110 Expr::CastExpr(_) => ExprPrecedence::Cast,
111
112 Expr::LetExpr(_) | Expr::PrefixExpr(_) | Expr::RefExpr(_) => ExprPrecedence::Prefix,
113
114 Expr::AwaitExpr(_)
115 | Expr::CallExpr(_)
116 | Expr::FieldExpr(_)
117 | Expr::IndexExpr(_)
118 | Expr::MethodCallExpr(_)
119 | Expr::TryExpr(_) => ExprPrecedence::Postfix,
120
121 Expr::ArrayExpr(_)
122 | Expr::AsmExpr(_)
123 | Expr::BlockExpr(_)
124 | Expr::ForExpr(_)
125 | Expr::FormatArgsExpr(_)
126 | Expr::IfExpr(_)
127 | Expr::Literal(_)
128 | Expr::LoopExpr(_)
129 | Expr::MacroExpr(_)
130 | Expr::MatchExpr(_)
131 | Expr::OffsetOfExpr(_)
132 | Expr::ParenExpr(_)
133 | Expr::PathExpr(_)
134 | Expr::RecordExpr(_)
135 | Expr::TupleExpr(_)
136 | Expr::UnderscoreExpr(_)
137 | Expr::WhileExpr(_) => ExprPrecedence::Unambiguous,
138 }
139}
140
141fn check_ancestry(ancestor: &SyntaxNode, descendent: &SyntaxNode) -> bool {
142 let bail = || always!(false, "{} is not an ancestor of {}", ancestor, descendent);
143
144 if !ancestor.text_range().contains_range(descendent.text_range()) {
145 return bail();
146 }
147
148 for anc in descendent.ancestors() {
149 if anc == *ancestor {
150 return true;
151 }
152 }
153
154 bail()
155}
156
157impl Expr {
158 pub fn precedence(&self) -> ExprPrecedence {
159 precedence(self)
160 }
161
162 pub fn needs_parens_in(&self, parent: &SyntaxNode) -> bool {
170 self.needs_parens_in_place_of(parent, self.syntax())
171 }
172
173 pub fn needs_parens_in_place_of(&self, parent: &SyntaxNode, place_of: &SyntaxNode) -> bool {
176 if !check_ancestry(parent, place_of) {
177 return false;
178 }
179
180 match_ast! {
181 match parent {
182 ast::Expr(e) => self.needs_parens_in_expr(&e, place_of),
183 ast::Stmt(e) => self.needs_parens_in_stmt(Some(&e)),
184 ast::StmtList(_) => self.needs_parens_in_stmt(None),
185 ast::ArgList(_) => false,
186 ast::MatchArm(_) => false,
187 _ => false,
188 }
189 }
190 }
191
192 fn needs_parens_in_expr(&self, parent: &Expr, place_of: &SyntaxNode) -> bool {
193 let is_parent_call_expr = matches!(parent, ast::Expr::CallExpr(_));
196 let is_field_expr = matches!(self, ast::Expr::FieldExpr(_));
197 if is_parent_call_expr && is_field_expr {
198 return true;
199 }
200
201 if parent.child_is_followed_by_a_block() {
203 use Expr::*;
204 match self {
205 ReturnExpr(e) if e.expr().is_none() => return true,
207 BreakExpr(e) if e.expr().is_none() => return true,
208 YieldExpr(e) if e.expr().is_none() => return true,
209
210 RangeExpr(e) if matches!(e.end(), Some(BlockExpr(..))) => return true,
212
213 _ if self.contains_exterior_struct_lit() => return true,
215 _ => {}
216 }
217 }
218
219 if self.is_ret_like_with_no_value() && parent.is_postfix() {
221 return false;
222 }
223
224 if self.precedence() == ExprPrecedence::Jump
229 && let Some(node) =
230 place_of.ancestors().find(|it| it.parent().is_none_or(|p| &p == parent.syntax()))
231 && let Some(next) =
232 node.last_token().and_then(|t| skip_trivia_token(t.next_token()?, Direction::Next))
233 && matches!(next.kind(), T![||] | T![&&])
234 {
235 return true;
236 }
237
238 if self.is_paren_like()
239 || parent.is_paren_like()
240 || self.is_prefix()
241 && (parent.is_prefix()
242 || !self.is_ordered_before_parent_in_place_of(parent, place_of))
243 || self.is_postfix()
244 && (parent.is_postfix()
245 || self.is_ordered_before_parent_in_place_of(parent, place_of))
246 {
247 return false;
248 }
249
250 let (left, right, inv) = match self.is_ordered_before_parent_in_place_of(parent, place_of) {
251 true => (self, parent, false),
252 false => (parent, self, true),
253 };
254
255 let (_, left_right_bp) = left.binding_power();
256 let (right_left_bp, _) = right.binding_power();
257
258 (left_right_bp < right_left_bp) ^ inv
259 }
260
261 fn needs_parens_in_stmt(&self, stmt: Option<&ast::Stmt>) -> bool {
262 use Expr::*;
263
264 let mut innermost = self.clone();
268 loop {
269 let next = match &innermost {
270 BinExpr(e) => e.lhs(),
271 CallExpr(e) => e.expr(),
272 CastExpr(e) => e.expr(),
273 IndexExpr(e) => e.base(),
274 _ => break,
275 };
276
277 if let Some(next) = next {
278 innermost = next;
279 if !innermost.requires_semi_to_be_stmt() {
280 return true;
281 }
282 } else {
283 break;
284 }
285 }
286
287 if let Some(ast::Stmt::LetStmt(e)) = stmt
289 && e.let_else().is_some()
290 {
291 match self {
292 BinExpr(e)
293 if e.op_kind()
294 .map(|op| matches!(op, BinaryOp::LogicOp(_)))
295 .unwrap_or(false) =>
296 {
297 return true;
298 }
299 _ if self.clone().trailing_brace().is_some() => return true,
300 _ => {}
301 }
302 }
303
304 false
305 }
306
307 fn binding_power(&self) -> (u8, u8) {
309 use ast::{ArithOp::*, BinaryOp::*, Expr::*, LogicOp::*};
310
311 match self {
312 ContinueExpr(_) => (0, 0),
321
322 ClosureExpr(_) | ReturnExpr(_) | BecomeExpr(_) | YieldExpr(_) | YeetExpr(_)
323 | BreakExpr(_) | OffsetOfExpr(_) | FormatArgsExpr(_) | AsmExpr(_) => (0, 1),
324
325 RangeExpr(_) => (5, 5),
326
327 BinExpr(e) => {
328 let Some(op) = e.op_kind() else { return (0, 0) };
330 match op {
331 Assignment { .. } => (4, 3),
332 LogicOp(op) => match op {
336 Or => (7, 8),
337 And => (9, 10),
338 },
339 CmpOp(_) => (11, 11),
340 ArithOp(op) => match op {
341 BitOr => (13, 14),
342 BitXor => (15, 16),
343 BitAnd => (17, 18),
344 Shl | Shr => (19, 20),
345 Add | Sub => (21, 22),
346 Mul | Div | Rem => (23, 24),
347 },
348 }
349 }
350
351 CastExpr(_) => (25, 26),
352
353 RefExpr(_) | LetExpr(_) | PrefixExpr(_) => (0, 27),
354
355 AwaitExpr(_) | CallExpr(_) | MethodCallExpr(_) | IndexExpr(_) | TryExpr(_)
356 | MacroExpr(_) => (29, 0),
357
358 FieldExpr(_) => (31, 32),
359
360 ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_) | IfExpr(_)
361 | WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_) | BlockExpr(_)
362 | RecordExpr(_) | UnderscoreExpr(_) => (0, 0),
363 }
364 }
365
366 fn is_paren_like(&self) -> bool {
367 matches!(self.binding_power(), (0, 0))
368 }
369
370 fn is_prefix(&self) -> bool {
371 matches!(self.binding_power(), (0, 1..))
372 }
373
374 fn is_postfix(&self) -> bool {
375 matches!(self.binding_power(), (1.., 0))
376 }
377
378 fn requires_semi_to_be_stmt(&self) -> bool {
380 use Expr::*;
381 !matches!(
382 self,
383 IfExpr(..) | MatchExpr(..) | BlockExpr(..) | WhileExpr(..) | LoopExpr(..) | ForExpr(..)
384 )
385 }
386
387 fn trailing_brace(mut self) -> Option<Expr> {
389 use Expr::*;
390
391 loop {
392 let rhs = match self {
393 RefExpr(e) => e.expr(),
394 BinExpr(e) => e.rhs(),
395 BreakExpr(e) => e.expr(),
396 LetExpr(e) => e.expr(),
397 RangeExpr(e) => e.end(),
398 ReturnExpr(e) => e.expr(),
399 PrefixExpr(e) => e.expr(),
400 YieldExpr(e) => e.expr(),
401 ClosureExpr(e) => e.body(),
402
403 BlockExpr(..) | ForExpr(..) | IfExpr(..) | LoopExpr(..) | MatchExpr(..)
404 | RecordExpr(..) | WhileExpr(..) => break Some(self),
405 _ => break None,
406 };
407
408 self = rhs?;
409 }
410 }
411
412 fn contains_exterior_struct_lit(&self) -> bool {
416 return contains_exterior_struct_lit_inner(self).is_some();
417
418 fn contains_exterior_struct_lit_inner(expr: &Expr) -> Option<()> {
419 use Expr::*;
420
421 match expr {
422 RecordExpr(..) => Some(()),
423
424 BinExpr(e) => e
426 .lhs()
427 .as_ref()
428 .and_then(contains_exterior_struct_lit_inner)
429 .or_else(|| e.rhs().as_ref().and_then(contains_exterior_struct_lit_inner)),
430
431 IndexExpr(e) => contains_exterior_struct_lit_inner(&e.base()?),
433 AwaitExpr(e) => contains_exterior_struct_lit_inner(&e.expr()?),
434 PrefixExpr(e) => contains_exterior_struct_lit_inner(&e.expr()?),
435 CastExpr(e) => contains_exterior_struct_lit_inner(&e.expr()?),
436 FieldExpr(e) => contains_exterior_struct_lit_inner(&e.expr()?),
437 MethodCallExpr(e) => contains_exterior_struct_lit_inner(&e.receiver()?),
438
439 _ => None,
440 }
441 }
442 }
443
444 pub fn is_ret_like_with_no_value(&self) -> bool {
446 use Expr::*;
447
448 match self {
449 ReturnExpr(e) => e.expr().is_none(),
450 BreakExpr(e) => e.expr().is_none(),
451 ContinueExpr(_) => true,
452 YieldExpr(e) => e.expr().is_none(),
453 BecomeExpr(e) => e.expr().is_none(),
454 _ => false,
455 }
456 }
457
458 fn is_ordered_before_parent_in_place_of(&self, parent: &Expr, place_of: &SyntaxNode) -> bool {
459 use Expr::*;
460 use rowan::TextSize;
461
462 let self_range = self.syntax().text_range();
463 let place_of_range = place_of.text_range();
464
465 let self_order_adjusted = order(self) - self_range.start() + place_of_range.start();
466
467 let parent_order = order(parent);
468 let parent_order_adjusted = if parent_order <= place_of_range.start() {
469 parent_order
470 } else if parent_order >= place_of_range.end() {
471 parent_order - place_of_range.len() + self_range.len()
472 } else {
473 return false;
474 };
475
476 return self_order_adjusted < parent_order_adjusted;
477
478 fn order(this: &Expr) -> TextSize {
480 let token = match this {
482 RangeExpr(e) => e.op_token(),
483 BinExpr(e) => e.op_token(),
484 CastExpr(e) => e.as_token(),
485 FieldExpr(e) => e.dot_token(),
486 AwaitExpr(e) => e.dot_token(),
487 BreakExpr(e) => e.break_token(),
488 CallExpr(e) => e.arg_list().and_then(|args| args.l_paren_token()),
489 ClosureExpr(e) => e.param_list().and_then(|params| params.l_paren_token()),
490 ContinueExpr(e) => e.continue_token(),
491 IndexExpr(e) => e.l_brack_token(),
492 MethodCallExpr(e) => e.dot_token(),
493 PrefixExpr(e) => e.op_token(),
494 RefExpr(e) => e.amp_token(),
495 ReturnExpr(e) => e.return_token(),
496 BecomeExpr(e) => e.become_token(),
497 TryExpr(e) => e.question_mark_token(),
498 YieldExpr(e) => e.yield_token(),
499 YeetExpr(e) => e.do_token(),
500 LetExpr(e) => e.let_token(),
501 OffsetOfExpr(e) => e.builtin_token(),
502 FormatArgsExpr(e) => e.builtin_token(),
503 AsmExpr(e) => e.builtin_token(),
504 ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_)
505 | IfExpr(_) | WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_)
506 | BlockExpr(_) | RecordExpr(_) | UnderscoreExpr(_) | MacroExpr(_) => None,
507 };
508
509 token.map(|t| t.text_range()).unwrap_or_else(|| this.syntax().text_range()).start()
510 }
511 }
512
513 fn child_is_followed_by_a_block(&self) -> bool {
514 use Expr::*;
515
516 match self {
517 ArrayExpr(_) | AwaitExpr(_) | BlockExpr(_) | CallExpr(_) | CastExpr(_)
518 | ClosureExpr(_) | FieldExpr(_) | IndexExpr(_) | Literal(_) | LoopExpr(_)
519 | MacroExpr(_) | MethodCallExpr(_) | ParenExpr(_) | PathExpr(_) | RecordExpr(_)
520 | TryExpr(_) | TupleExpr(_) | UnderscoreExpr(_) | OffsetOfExpr(_)
521 | FormatArgsExpr(_) | AsmExpr(_) => false,
522
523 BinExpr(_) | RangeExpr(_) | BreakExpr(_) | ContinueExpr(_) | PrefixExpr(_)
525 | RefExpr(_) | ReturnExpr(_) | BecomeExpr(_) | YieldExpr(_) | YeetExpr(_)
526 | LetExpr(_) => self
527 .syntax()
528 .parent()
529 .and_then(Expr::cast)
530 .map(|e| e.child_is_followed_by_a_block())
531 .unwrap_or(false),
532
533 ForExpr(_) | IfExpr(_) | MatchExpr(_) | WhileExpr(_) => true,
534 }
535 }
536}