1use crate::classify;
2use crate::precedence::Precedence;
3use syn::{
4 Expr, ExprBreak, ExprRange, ExprRawAddr, ExprReference, ExprReturn, ExprUnary, ExprYield,
5};
6
7#[derive(Copy, Clone)]
8pub struct FixupContext {
9 previous_operator: Precedence,
10 next_operator: Precedence,
11
12 stmt: bool,
23
24 leftmost_subexpression_in_stmt: bool,
54
55 match_arm: bool,
69
70 leftmost_subexpression_in_match_arm: bool,
84
85 condition: bool,
94
95 rightmost_subexpression_in_condition: bool,
102
103 leftmost_subexpression_in_optional_operand: bool,
110
111 next_operator_can_begin_expr: bool,
118
119 next_operator_can_continue_expr: bool,
126
127 next_operator_can_begin_generics: bool,
135}
136
137impl FixupContext {
138 pub const NONE: Self = FixupContext {
141 previous_operator: Precedence::MIN,
142 next_operator: Precedence::MIN,
143 stmt: false,
144 leftmost_subexpression_in_stmt: false,
145 match_arm: false,
146 leftmost_subexpression_in_match_arm: false,
147 condition: false,
148 rightmost_subexpression_in_condition: false,
149 leftmost_subexpression_in_optional_operand: false,
150 next_operator_can_begin_expr: false,
151 next_operator_can_continue_expr: false,
152 next_operator_can_begin_generics: false,
153 };
154
155 pub fn new_stmt() -> Self {
158 FixupContext {
159 stmt: true,
160 ..FixupContext::NONE
161 }
162 }
163
164 pub fn new_match_arm() -> Self {
167 FixupContext {
168 match_arm: true,
169 ..FixupContext::NONE
170 }
171 }
172
173 pub fn new_condition() -> Self {
178 FixupContext {
179 condition: true,
180 rightmost_subexpression_in_condition: true,
181 ..FixupContext::NONE
182 }
183 }
184
185 pub fn leftmost_subexpression_with_operator(
197 self,
198 expr: &Expr,
199 next_operator_can_begin_expr: bool,
200 next_operator_can_begin_generics: bool,
201 precedence: Precedence,
202 ) -> (Precedence, Self) {
203 let fixup = FixupContext {
204 next_operator: precedence,
205 stmt: false,
206 leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt,
207 match_arm: false,
208 leftmost_subexpression_in_match_arm: self.match_arm
209 || self.leftmost_subexpression_in_match_arm,
210 rightmost_subexpression_in_condition: false,
211 next_operator_can_begin_expr,
212 next_operator_can_continue_expr: true,
213 next_operator_can_begin_generics,
214 ..self
215 };
216
217 (fixup.leftmost_subexpression_precedence(expr), fixup)
218 }
219
220 pub fn leftmost_subexpression_with_dot(self, expr: &Expr) -> (Precedence, Self) {
225 let fixup = FixupContext {
226 next_operator: Precedence::Unambiguous,
227 stmt: self.stmt || self.leftmost_subexpression_in_stmt,
228 leftmost_subexpression_in_stmt: false,
229 match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
230 leftmost_subexpression_in_match_arm: false,
231 rightmost_subexpression_in_condition: false,
232 next_operator_can_begin_expr: false,
233 next_operator_can_continue_expr: true,
234 next_operator_can_begin_generics: false,
235 ..self
236 };
237
238 (fixup.leftmost_subexpression_precedence(expr), fixup)
239 }
240
241 fn leftmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
242 if !self.next_operator_can_begin_expr || self.next_operator == Precedence::Range {
243 if let Scan::Bailout = scan_right(expr, self, Precedence::MIN, 0, 0) {
244 if scan_left(expr, self) {
245 return Precedence::Unambiguous;
246 }
247 }
248 }
249
250 self.precedence(expr)
251 }
252
253 pub fn rightmost_subexpression(
265 self,
266 expr: &Expr,
267 precedence: Precedence,
268 ) -> (Precedence, Self) {
269 let fixup = self.rightmost_subexpression_fixup(false, false, precedence);
270 (fixup.rightmost_subexpression_precedence(expr), fixup)
271 }
272
273 pub fn rightmost_subexpression_fixup(
274 self,
275 reset_allow_struct: bool,
276 optional_operand: bool,
277 precedence: Precedence,
278 ) -> Self {
279 FixupContext {
280 previous_operator: precedence,
281 stmt: false,
282 leftmost_subexpression_in_stmt: false,
283 match_arm: false,
284 leftmost_subexpression_in_match_arm: false,
285 condition: self.condition && !reset_allow_struct,
286 leftmost_subexpression_in_optional_operand: self.condition && optional_operand,
287 ..self
288 }
289 }
290
291 pub fn rightmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
292 let default_prec = self.precedence(expr);
293
294 if match self.previous_operator {
295 Precedence::Assign | Precedence::Let | Precedence::Prefix => {
296 default_prec < self.previous_operator
297 }
298 _ => default_prec <= self.previous_operator,
299 } && match self.next_operator {
300 Precedence::Range | Precedence::Or | Precedence::And => true,
301 _ => !self.next_operator_can_begin_expr,
302 } {
303 if let Scan::Bailout | Scan::Fail = scan_right(expr, self, self.previous_operator, 1, 0)
304 {
305 if scan_left(expr, self) {
306 return Precedence::Prefix;
307 }
308 }
309 }
310
311 default_prec
312 }
313
314 pub fn parenthesize(self, expr: &Expr) -> bool {
317 (self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr))
318 || ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_)))
319 || (self.leftmost_subexpression_in_match_arm
320 && !classify::requires_comma_to_be_match_arm(expr))
321 || (self.condition && matches!(expr, Expr::Struct(_)))
322 || (self.rightmost_subexpression_in_condition
323 && matches!(
324 expr,
325 Expr::Return(ExprReturn { expr: None, .. })
326 | Expr::Yield(ExprYield { expr: None, .. })
327 ))
328 || (self.rightmost_subexpression_in_condition
329 && !self.condition
330 && matches!(
331 expr,
332 Expr::Break(ExprBreak { expr: None, .. })
333 | Expr::Path(_)
334 | Expr::Range(ExprRange { end: None, .. })
335 ))
336 || (self.leftmost_subexpression_in_optional_operand
337 && matches!(expr, Expr::Block(expr) if expr.attrs.is_empty() && expr.label.is_none()))
338 }
339
340 fn precedence(self, expr: &Expr) -> Precedence {
343 if self.next_operator_can_begin_expr {
344 if let Expr::Break(ExprBreak { expr: None, .. })
348 | Expr::Return(ExprReturn { expr: None, .. })
349 | Expr::Yield(ExprYield { expr: None, .. }) = expr
350 {
351 return Precedence::Jump;
352 }
353 }
354
355 if !self.next_operator_can_continue_expr {
356 match expr {
357 Expr::Break(_)
360 | Expr::Closure(_)
361 | Expr::Let(_)
362 | Expr::Return(_)
363 | Expr::Yield(_) => {
364 return Precedence::Prefix;
365 }
366 Expr::Range(e) if e.start.is_none() => return Precedence::Prefix,
367 _ => {}
368 }
369 }
370
371 if self.next_operator_can_begin_generics {
372 if let Expr::Cast(cast) = expr {
373 if classify::trailing_unparameterized_path(&cast.ty) {
374 return Precedence::MIN;
375 }
376 }
377 }
378
379 Precedence::of(expr)
380 }
381}
382
383#[derive(Copy, Clone, PartialEq)]
384enum Scan {
385 Fail,
386 Bailout,
387 Consume,
388}
389
390fn scan_left(expr: &Expr, fixup: FixupContext) -> bool {
391 match expr {
392 Expr::Assign(_) => fixup.previous_operator <= Precedence::Assign,
393 Expr::Binary(e) => match Precedence::of_binop(&e.op) {
394 Precedence::Assign => fixup.previous_operator <= Precedence::Assign,
395 binop_prec => fixup.previous_operator < binop_prec,
396 },
397 Expr::Cast(_) => fixup.previous_operator < Precedence::Cast,
398 Expr::Range(e) => e.start.is_none() || fixup.previous_operator < Precedence::Assign,
399 _ => true,
400 }
401}
402
403fn scan_right(
404 expr: &Expr,
405 fixup: FixupContext,
406 precedence: Precedence,
407 fail_offset: u8,
408 bailout_offset: u8,
409) -> Scan {
410 let consume_by_precedence = if match precedence {
411 Precedence::Assign | Precedence::Compare => precedence <= fixup.next_operator,
412 _ => precedence < fixup.next_operator,
413 } || fixup.next_operator == Precedence::MIN
414 {
415 Scan::Consume
416 } else {
417 Scan::Bailout
418 };
419 if fixup.parenthesize(expr) {
420 return consume_by_precedence;
421 }
422 match expr {
423 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
424 Expr::Assign(e) => {
425 if match fixup.next_operator {
426 Precedence::Unambiguous => fail_offset >= 2,
427 _ => bailout_offset >= 1,
428 } {
429 return Scan::Consume;
430 }
431 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign);
432 let scan = scan_right(
433 &e.right,
434 right_fixup,
435 Precedence::Assign,
436 match fixup.next_operator {
437 Precedence::Unambiguous => fail_offset,
438 _ => 1,
439 },
440 1,
441 );
442 if let Scan::Bailout | Scan::Consume = scan {
443 Scan::Consume
444 } else if let Precedence::Unambiguous = fixup.next_operator {
445 Scan::Fail
446 } else {
447 Scan::Bailout
448 }
449 }
450 Expr::Binary(e) => {
451 if match fixup.next_operator {
452 Precedence::Unambiguous => {
453 fail_offset >= 2
454 && (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
455 }
456 _ => bailout_offset >= 1,
457 } {
458 return Scan::Consume;
459 }
460 let binop_prec = Precedence::of_binop(&e.op);
461 if binop_prec == Precedence::Compare && fixup.next_operator == Precedence::Compare {
462 return Scan::Consume;
463 }
464 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, binop_prec);
465 let scan = scan_right(
466 &e.right,
467 right_fixup,
468 binop_prec,
469 match fixup.next_operator {
470 Precedence::Unambiguous => fail_offset,
471 _ => 1,
472 },
473 consume_by_precedence as u8 - Scan::Bailout as u8,
474 );
475 match scan {
476 Scan::Fail => {}
477 Scan::Bailout => return consume_by_precedence,
478 Scan::Consume => return Scan::Consume,
479 }
480 let right_needs_group = binop_prec != Precedence::Assign
481 && right_fixup.rightmost_subexpression_precedence(&e.right) <= binop_prec;
482 if right_needs_group {
483 consume_by_precedence
484 } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
485 Scan::Fail
486 } else {
487 Scan::Bailout
488 }
489 }
490 Expr::RawAddr(ExprRawAddr { expr, .. })
491 | Expr::Reference(ExprReference { expr, .. })
492 | Expr::Unary(ExprUnary { expr, .. }) => {
493 if match fixup.next_operator {
494 Precedence::Unambiguous => {
495 fail_offset >= 2
496 && (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
497 }
498 _ => bailout_offset >= 1,
499 } {
500 return Scan::Consume;
501 }
502 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Prefix);
503 let scan = scan_right(
504 expr,
505 right_fixup,
506 precedence,
507 match fixup.next_operator {
508 Precedence::Unambiguous => fail_offset,
509 _ => 1,
510 },
511 consume_by_precedence as u8 - Scan::Bailout as u8,
512 );
513 match scan {
514 Scan::Fail => {}
515 Scan::Bailout => return consume_by_precedence,
516 Scan::Consume => return Scan::Consume,
517 }
518 if right_fixup.rightmost_subexpression_precedence(expr) < Precedence::Prefix {
519 consume_by_precedence
520 } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
521 Scan::Fail
522 } else {
523 Scan::Bailout
524 }
525 }
526 Expr::Range(e) => match &e.end {
527 Some(end) => {
528 if fail_offset >= 2 {
529 return Scan::Consume;
530 }
531 let right_fixup =
532 fixup.rightmost_subexpression_fixup(false, true, Precedence::Range);
533 let scan = scan_right(
534 end,
535 right_fixup,
536 Precedence::Range,
537 fail_offset,
538 match fixup.next_operator {
539 Precedence::Assign | Precedence::Range => 0,
540 _ => 1,
541 },
542 );
543 if match (scan, fixup.next_operator) {
544 (Scan::Fail, _) => false,
545 (Scan::Bailout, Precedence::Assign | Precedence::Range) => false,
546 (Scan::Bailout | Scan::Consume, _) => true,
547 } {
548 return Scan::Consume;
549 }
550 if right_fixup.rightmost_subexpression_precedence(end) <= Precedence::Range {
551 Scan::Consume
552 } else {
553 Scan::Fail
554 }
555 }
556 None => {
557 if fixup.next_operator_can_begin_expr {
558 Scan::Consume
559 } else {
560 Scan::Fail
561 }
562 }
563 },
564 Expr::Break(e) => match &e.expr {
565 Some(value) => {
566 if bailout_offset >= 1 || e.label.is_none() && classify::expr_leading_label(value) {
567 return Scan::Consume;
568 }
569 let right_fixup = fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump);
570 match scan_right(value, right_fixup, Precedence::Jump, 1, 1) {
571 Scan::Fail => Scan::Bailout,
572 Scan::Bailout | Scan::Consume => Scan::Consume,
573 }
574 }
575 None => match fixup.next_operator {
576 Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
577 _ => Scan::Consume,
578 },
579 },
580 Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr {
581 Some(e) => {
582 if bailout_offset >= 1 {
583 return Scan::Consume;
584 }
585 let right_fixup =
586 fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump);
587 match scan_right(e, right_fixup, Precedence::Jump, 1, 1) {
588 Scan::Fail => Scan::Bailout,
589 Scan::Bailout | Scan::Consume => Scan::Consume,
590 }
591 }
592 None => match fixup.next_operator {
593 Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
594 _ => Scan::Consume,
595 },
596 },
597 Expr::Closure(_) => Scan::Consume,
598 Expr::Let(e) => {
599 if bailout_offset >= 1 {
600 return Scan::Consume;
601 }
602 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Let);
603 let scan = scan_right(
604 &e.expr,
605 right_fixup,
606 Precedence::Let,
607 1,
608 if fixup.next_operator < Precedence::Let {
609 0
610 } else {
611 1
612 },
613 );
614 match scan {
615 Scan::Fail | Scan::Bailout if fixup.next_operator < Precedence::Let => {
616 return Scan::Bailout;
617 }
618 Scan::Consume => return Scan::Consume,
619 _ => {}
620 }
621 if right_fixup.rightmost_subexpression_precedence(&e.expr) < Precedence::Let {
622 Scan::Consume
623 } else if let Scan::Fail = scan {
624 Scan::Bailout
625 } else {
626 Scan::Consume
627 }
628 }
629 Expr::Group(e) => scan_right(&e.expr, fixup, precedence, fail_offset, bailout_offset),
630 Expr::Array(_)
631 | Expr::Async(_)
632 | Expr::Await(_)
633 | Expr::Block(_)
634 | Expr::Call(_)
635 | Expr::Cast(_)
636 | Expr::Const(_)
637 | Expr::Continue(_)
638 | Expr::Field(_)
639 | Expr::ForLoop(_)
640 | Expr::If(_)
641 | Expr::Index(_)
642 | Expr::Infer(_)
643 | Expr::Lit(_)
644 | Expr::Loop(_)
645 | Expr::Macro(_)
646 | Expr::Match(_)
647 | Expr::MethodCall(_)
648 | Expr::Paren(_)
649 | Expr::Path(_)
650 | Expr::Repeat(_)
651 | Expr::Struct(_)
652 | Expr::Try(_)
653 | Expr::TryBlock(_)
654 | Expr::Tuple(_)
655 | Expr::Unsafe(_)
656 | Expr::Verbatim(_)
657 | Expr::While(_) => match fixup.next_operator {
658 Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail,
659 _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => {
660 Scan::Fail
661 }
662 _ => consume_by_precedence,
663 },
664
665 _ => match fixup.next_operator {
666 Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail,
667 _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => {
668 Scan::Fail
669 }
670 _ => consume_by_precedence,
671 },
672 }
673}