1use crate::classify;
2use crate::expr::Expr;
3#[cfg(feature = "full")]
4use crate::expr::{
5 ExprBreak, ExprRange, ExprRawAddr, ExprReference, ExprReturn, ExprUnary, ExprYield,
6};
7use crate::precedence::Precedence;
8#[cfg(feature = "full")]
9use crate::ty::ReturnType;
10
11pub(crate) struct FixupContext {
12 #[cfg(feature = "full")]
13 previous_operator: Precedence,
14 #[cfg(feature = "full")]
15 next_operator: Precedence,
16
17 #[cfg(feature = "full")]
28 stmt: bool,
29
30 #[cfg(feature = "full")]
60 leftmost_subexpression_in_stmt: bool,
61
62 #[cfg(feature = "full")]
76 match_arm: bool,
77
78 #[cfg(feature = "full")]
92 leftmost_subexpression_in_match_arm: bool,
93
94 #[cfg(feature = "full")]
103 condition: bool,
104
105 #[cfg(feature = "full")]
112 rightmost_subexpression_in_condition: bool,
113
114 #[cfg(feature = "full")]
121 leftmost_subexpression_in_optional_operand: bool,
122
123 #[cfg(feature = "full")]
130 next_operator_can_begin_expr: bool,
131
132 #[cfg(feature = "full")]
139 next_operator_can_continue_expr: bool,
140
141 next_operator_can_begin_generics: bool,
149}
150
151impl FixupContext {
152 pub const NONE: Self = FixupContext {
155 #[cfg(feature = "full")]
156 previous_operator: Precedence::MIN,
157 #[cfg(feature = "full")]
158 next_operator: Precedence::MIN,
159 #[cfg(feature = "full")]
160 stmt: false,
161 #[cfg(feature = "full")]
162 leftmost_subexpression_in_stmt: false,
163 #[cfg(feature = "full")]
164 match_arm: false,
165 #[cfg(feature = "full")]
166 leftmost_subexpression_in_match_arm: false,
167 #[cfg(feature = "full")]
168 condition: false,
169 #[cfg(feature = "full")]
170 rightmost_subexpression_in_condition: false,
171 #[cfg(feature = "full")]
172 leftmost_subexpression_in_optional_operand: false,
173 #[cfg(feature = "full")]
174 next_operator_can_begin_expr: false,
175 #[cfg(feature = "full")]
176 next_operator_can_continue_expr: false,
177 next_operator_can_begin_generics: false,
178 };
179
180 #[cfg(feature = "full")]
183 pub fn new_stmt() -> Self {
184 FixupContext {
185 stmt: true,
186 ..FixupContext::NONE
187 }
188 }
189
190 #[cfg(feature = "full")]
193 pub fn new_match_arm() -> Self {
194 FixupContext {
195 match_arm: true,
196 ..FixupContext::NONE
197 }
198 }
199
200 #[cfg(feature = "full")]
205 pub fn new_condition() -> Self {
206 FixupContext {
207 condition: true,
208 rightmost_subexpression_in_condition: true,
209 ..FixupContext::NONE
210 }
211 }
212
213 pub fn leftmost_subexpression_with_operator(
225 self,
226 expr: &Expr,
227 #[cfg(feature = "full")] next_operator_can_begin_expr: bool,
228 next_operator_can_begin_generics: bool,
229 #[cfg(feature = "full")] precedence: Precedence,
230 ) -> (Precedence, Self) {
231 let fixup = FixupContext {
232 #[cfg(feature = "full")]
233 next_operator: precedence,
234 #[cfg(feature = "full")]
235 stmt: false,
236 #[cfg(feature = "full")]
237 leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt,
238 #[cfg(feature = "full")]
239 match_arm: false,
240 #[cfg(feature = "full")]
241 leftmost_subexpression_in_match_arm: self.match_arm
242 || self.leftmost_subexpression_in_match_arm,
243 #[cfg(feature = "full")]
244 rightmost_subexpression_in_condition: false,
245 #[cfg(feature = "full")]
246 next_operator_can_begin_expr,
247 #[cfg(feature = "full")]
248 next_operator_can_continue_expr: true,
249 next_operator_can_begin_generics,
250 ..self
251 };
252
253 (fixup.leftmost_subexpression_precedence(expr), fixup)
254 }
255
256 pub fn leftmost_subexpression_with_dot(self, expr: &Expr) -> (Precedence, Self) {
261 let fixup = FixupContext {
262 #[cfg(feature = "full")]
263 next_operator: Precedence::Unambiguous,
264 #[cfg(feature = "full")]
265 stmt: self.stmt || self.leftmost_subexpression_in_stmt,
266 #[cfg(feature = "full")]
267 leftmost_subexpression_in_stmt: false,
268 #[cfg(feature = "full")]
269 match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
270 #[cfg(feature = "full")]
271 leftmost_subexpression_in_match_arm: false,
272 #[cfg(feature = "full")]
273 rightmost_subexpression_in_condition: false,
274 #[cfg(feature = "full")]
275 next_operator_can_begin_expr: false,
276 #[cfg(feature = "full")]
277 next_operator_can_continue_expr: true,
278 next_operator_can_begin_generics: false,
279 ..self
280 };
281
282 (fixup.leftmost_subexpression_precedence(expr), fixup)
283 }
284
285 fn leftmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
286 #[cfg(feature = "full")]
287 if !self.next_operator_can_begin_expr || self.next_operator == Precedence::Range {
288 if let Scan::Bailout = scan_right(expr, self, Precedence::MIN, 0, 0) {
289 if scan_left(expr, self) {
290 return Precedence::Unambiguous;
291 }
292 }
293 }
294
295 self.precedence(expr)
296 }
297
298 pub fn rightmost_subexpression(
310 self,
311 expr: &Expr,
312 #[cfg(feature = "full")] precedence: Precedence,
313 ) -> (Precedence, Self) {
314 let fixup = self.rightmost_subexpression_fixup(
315 #[cfg(feature = "full")]
316 false,
317 #[cfg(feature = "full")]
318 false,
319 #[cfg(feature = "full")]
320 precedence,
321 );
322 (fixup.rightmost_subexpression_precedence(expr), fixup)
323 }
324
325 pub fn rightmost_subexpression_fixup(
326 self,
327 #[cfg(feature = "full")] reset_allow_struct: bool,
328 #[cfg(feature = "full")] optional_operand: bool,
329 #[cfg(feature = "full")] precedence: Precedence,
330 ) -> Self {
331 FixupContext {
332 #[cfg(feature = "full")]
333 previous_operator: precedence,
334 #[cfg(feature = "full")]
335 stmt: false,
336 #[cfg(feature = "full")]
337 leftmost_subexpression_in_stmt: false,
338 #[cfg(feature = "full")]
339 match_arm: false,
340 #[cfg(feature = "full")]
341 leftmost_subexpression_in_match_arm: false,
342 #[cfg(feature = "full")]
343 condition: self.condition && !reset_allow_struct,
344 #[cfg(feature = "full")]
345 leftmost_subexpression_in_optional_operand: self.condition && optional_operand,
346 ..self
347 }
348 }
349
350 pub fn rightmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
351 let default_prec = self.precedence(expr);
352
353 #[cfg(feature = "full")]
354 if match self.previous_operator {
355 Precedence::Assign | Precedence::Let | Precedence::Prefix => {
356 default_prec < self.previous_operator
357 }
358 _ => default_prec <= self.previous_operator,
359 } && match self.next_operator {
360 Precedence::Range | Precedence::Or | Precedence::And => true,
361 _ => !self.next_operator_can_begin_expr,
362 } {
363 if let Scan::Bailout | Scan::Fail = scan_right(expr, self, self.previous_operator, 1, 0)
364 {
365 if scan_left(expr, self) {
366 return Precedence::Prefix;
367 }
368 }
369 }
370
371 default_prec
372 }
373
374 #[cfg(feature = "full")]
377 pub fn parenthesize(self, expr: &Expr) -> bool {
378 (self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr))
379 || ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_)))
380 || (self.leftmost_subexpression_in_match_arm
381 && !classify::requires_comma_to_be_match_arm(expr))
382 || (self.condition && matches!(expr, Expr::Struct(_)))
383 || (self.rightmost_subexpression_in_condition
384 && matches!(
385 expr,
386 Expr::Return(ExprReturn { expr: None, .. })
387 | Expr::Yield(ExprYield { expr: None, .. })
388 ))
389 || (self.rightmost_subexpression_in_condition
390 && !self.condition
391 && matches!(
392 expr,
393 Expr::Break(ExprBreak { expr: None, .. })
394 | Expr::Path(_)
395 | Expr::Range(ExprRange { end: None, .. })
396 ))
397 || (self.leftmost_subexpression_in_optional_operand
398 && matches!(expr, Expr::Block(expr) if expr.attrs.is_empty() && expr.label.is_none()))
399 }
400
401 fn precedence(self, expr: &Expr) -> Precedence {
404 #[cfg(feature = "full")]
405 if self.next_operator_can_begin_expr {
406 if let Expr::Break(ExprBreak { expr: None, .. })
410 | Expr::Return(ExprReturn { expr: None, .. })
411 | Expr::Yield(ExprYield { expr: None, .. }) = expr
412 {
413 return Precedence::Jump;
414 }
415 }
416
417 #[cfg(feature = "full")]
418 if !self.next_operator_can_continue_expr {
419 match expr {
420 Expr::Break(_)
423 | Expr::Closure(_)
424 | Expr::Let(_)
425 | Expr::Return(_)
426 | Expr::Yield(_) => {
427 return Precedence::Prefix;
428 }
429 Expr::Range(e) if e.start.is_none() => return Precedence::Prefix,
430 _ => {}
431 }
432 }
433
434 if self.next_operator_can_begin_generics {
435 if let Expr::Cast(cast) = expr {
436 if classify::trailing_unparameterized_path(&cast.ty) {
437 return Precedence::MIN;
438 }
439 }
440 }
441
442 Precedence::of(expr)
443 }
444}
445
446impl Copy for FixupContext {}
447
448impl Clone for FixupContext {
449 fn clone(&self) -> Self {
450 *self
451 }
452}
453
454#[cfg(feature = "full")]
455enum Scan {
456 Fail,
457 Bailout,
458 Consume,
459}
460
461#[cfg(feature = "full")]
462impl Copy for Scan {}
463
464#[cfg(feature = "full")]
465impl Clone for Scan {
466 fn clone(&self) -> Self {
467 *self
468 }
469}
470
471#[cfg(feature = "full")]
472impl PartialEq for Scan {
473 fn eq(&self, other: &Self) -> bool {
474 *self as u8 == *other as u8
475 }
476}
477
478#[cfg(feature = "full")]
479fn scan_left(expr: &Expr, fixup: FixupContext) -> bool {
480 match expr {
481 Expr::Assign(_) => fixup.previous_operator <= Precedence::Assign,
482 Expr::Binary(e) => match Precedence::of_binop(&e.op) {
483 Precedence::Assign => fixup.previous_operator <= Precedence::Assign,
484 binop_prec => fixup.previous_operator < binop_prec,
485 },
486 Expr::Cast(_) => fixup.previous_operator < Precedence::Cast,
487 Expr::Range(e) => e.start.is_none() || fixup.previous_operator < Precedence::Assign,
488 _ => true,
489 }
490}
491
492#[cfg(feature = "full")]
493fn scan_right(
494 expr: &Expr,
495 fixup: FixupContext,
496 precedence: Precedence,
497 fail_offset: u8,
498 bailout_offset: u8,
499) -> Scan {
500 let consume_by_precedence = if match precedence {
501 Precedence::Assign | Precedence::Compare => precedence <= fixup.next_operator,
502 _ => precedence < fixup.next_operator,
503 } || fixup.next_operator == Precedence::MIN
504 {
505 Scan::Consume
506 } else {
507 Scan::Bailout
508 };
509 if fixup.parenthesize(expr) {
510 return consume_by_precedence;
511 }
512 match expr {
513 Expr::Assign(e) => {
514 if match fixup.next_operator {
515 Precedence::Unambiguous => fail_offset >= 2,
516 _ => bailout_offset >= 1,
517 } {
518 return Scan::Consume;
519 }
520 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign);
521 let scan = scan_right(
522 &e.right,
523 right_fixup,
524 Precedence::Assign,
525 match fixup.next_operator {
526 Precedence::Unambiguous => fail_offset,
527 _ => 1,
528 },
529 1,
530 );
531 if let Scan::Bailout | Scan::Consume = scan {
532 Scan::Consume
533 } else if let Precedence::Unambiguous = fixup.next_operator {
534 Scan::Fail
535 } else {
536 Scan::Bailout
537 }
538 }
539 Expr::Binary(e) => {
540 if match fixup.next_operator {
541 Precedence::Unambiguous => {
542 fail_offset >= 2
543 && (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
544 }
545 _ => bailout_offset >= 1,
546 } {
547 return Scan::Consume;
548 }
549 let binop_prec = Precedence::of_binop(&e.op);
550 if binop_prec == Precedence::Compare && fixup.next_operator == Precedence::Compare {
551 return Scan::Consume;
552 }
553 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, binop_prec);
554 let scan = scan_right(
555 &e.right,
556 right_fixup,
557 binop_prec,
558 match fixup.next_operator {
559 Precedence::Unambiguous => fail_offset,
560 _ => 1,
561 },
562 consume_by_precedence as u8 - Scan::Bailout as u8,
563 );
564 match scan {
565 Scan::Fail => {}
566 Scan::Bailout => return consume_by_precedence,
567 Scan::Consume => return Scan::Consume,
568 }
569 let right_needs_group = binop_prec != Precedence::Assign
570 && right_fixup.rightmost_subexpression_precedence(&e.right) <= binop_prec;
571 if right_needs_group {
572 consume_by_precedence
573 } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
574 Scan::Fail
575 } else {
576 Scan::Bailout
577 }
578 }
579 Expr::RawAddr(ExprRawAddr { expr, .. })
580 | Expr::Reference(ExprReference { expr, .. })
581 | Expr::Unary(ExprUnary { expr, .. }) => {
582 if match fixup.next_operator {
583 Precedence::Unambiguous => {
584 fail_offset >= 2
585 && (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
586 }
587 _ => bailout_offset >= 1,
588 } {
589 return Scan::Consume;
590 }
591 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Prefix);
592 let scan = scan_right(
593 expr,
594 right_fixup,
595 precedence,
596 match fixup.next_operator {
597 Precedence::Unambiguous => fail_offset,
598 _ => 1,
599 },
600 consume_by_precedence as u8 - Scan::Bailout as u8,
601 );
602 match scan {
603 Scan::Fail => {}
604 Scan::Bailout => return consume_by_precedence,
605 Scan::Consume => return Scan::Consume,
606 }
607 if right_fixup.rightmost_subexpression_precedence(expr) < Precedence::Prefix {
608 consume_by_precedence
609 } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
610 Scan::Fail
611 } else {
612 Scan::Bailout
613 }
614 }
615 Expr::Range(e) => match &e.end {
616 Some(end) => {
617 if fail_offset >= 2 {
618 return Scan::Consume;
619 }
620 let right_fixup =
621 fixup.rightmost_subexpression_fixup(false, true, Precedence::Range);
622 let scan = scan_right(
623 end,
624 right_fixup,
625 Precedence::Range,
626 fail_offset,
627 match fixup.next_operator {
628 Precedence::Assign | Precedence::Range => 0,
629 _ => 1,
630 },
631 );
632 if match (scan, fixup.next_operator) {
633 (Scan::Fail, _) => false,
634 (Scan::Bailout, Precedence::Assign | Precedence::Range) => false,
635 (Scan::Bailout | Scan::Consume, _) => true,
636 } {
637 return Scan::Consume;
638 }
639 if right_fixup.rightmost_subexpression_precedence(end) <= Precedence::Range {
640 Scan::Consume
641 } else {
642 Scan::Fail
643 }
644 }
645 None => {
646 if fixup.next_operator_can_begin_expr {
647 Scan::Consume
648 } else {
649 Scan::Fail
650 }
651 }
652 },
653 Expr::Break(e) => match &e.expr {
654 Some(value) => {
655 if bailout_offset >= 1 || e.label.is_none() && classify::expr_leading_label(value) {
656 return Scan::Consume;
657 }
658 let right_fixup = fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump);
659 match scan_right(value, right_fixup, Precedence::Jump, 1, 1) {
660 Scan::Fail => Scan::Bailout,
661 Scan::Bailout | Scan::Consume => Scan::Consume,
662 }
663 }
664 None => match fixup.next_operator {
665 Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
666 _ => Scan::Consume,
667 },
668 },
669 Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr {
670 Some(e) => {
671 if bailout_offset >= 1 {
672 return Scan::Consume;
673 }
674 let right_fixup =
675 fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump);
676 match scan_right(e, right_fixup, Precedence::Jump, 1, 1) {
677 Scan::Fail => Scan::Bailout,
678 Scan::Bailout | Scan::Consume => Scan::Consume,
679 }
680 }
681 None => match fixup.next_operator {
682 Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
683 _ => Scan::Consume,
684 },
685 },
686 Expr::Closure(e) => {
687 if matches!(e.output, ReturnType::Default)
688 || matches!(&*e.body, Expr::Block(body) if body.attrs.is_empty() && body.label.is_none())
689 {
690 if bailout_offset >= 1 {
691 return Scan::Consume;
692 }
693 let right_fixup =
694 fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump);
695 match scan_right(&e.body, right_fixup, Precedence::Jump, 1, 1) {
696 Scan::Fail => Scan::Bailout,
697 Scan::Bailout | Scan::Consume => Scan::Consume,
698 }
699 } else {
700 Scan::Consume
701 }
702 }
703 Expr::Let(e) => {
704 if bailout_offset >= 1 {
705 return Scan::Consume;
706 }
707 let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Let);
708 let scan = scan_right(
709 &e.expr,
710 right_fixup,
711 Precedence::Let,
712 1,
713 if fixup.next_operator < Precedence::Let {
714 0
715 } else {
716 1
717 },
718 );
719 match scan {
720 Scan::Fail | Scan::Bailout if fixup.next_operator < Precedence::Let => {
721 return Scan::Bailout;
722 }
723 Scan::Consume => return Scan::Consume,
724 _ => {}
725 }
726 if right_fixup.rightmost_subexpression_precedence(&e.expr) < Precedence::Let {
727 Scan::Consume
728 } else if let Scan::Fail = scan {
729 Scan::Bailout
730 } else {
731 Scan::Consume
732 }
733 }
734 Expr::Array(_)
735 | Expr::Async(_)
736 | Expr::Await(_)
737 | Expr::Block(_)
738 | Expr::Call(_)
739 | Expr::Cast(_)
740 | Expr::Const(_)
741 | Expr::Continue(_)
742 | Expr::Field(_)
743 | Expr::ForLoop(_)
744 | Expr::Group(_)
745 | Expr::If(_)
746 | Expr::Index(_)
747 | Expr::Infer(_)
748 | Expr::Lit(_)
749 | Expr::Loop(_)
750 | Expr::Macro(_)
751 | Expr::Match(_)
752 | Expr::MethodCall(_)
753 | Expr::Paren(_)
754 | Expr::Path(_)
755 | Expr::Repeat(_)
756 | Expr::Struct(_)
757 | Expr::Try(_)
758 | Expr::TryBlock(_)
759 | Expr::Tuple(_)
760 | Expr::Unsafe(_)
761 | Expr::Verbatim(_)
762 | Expr::While(_) => match fixup.next_operator {
763 Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail,
764 _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => {
765 Scan::Fail
766 }
767 _ => consume_by_precedence,
768 },
769 }
770}