|
31 | 31 | import org.openrewrite.marker.Marker; |
32 | 32 | import org.openrewrite.marker.Markers; |
33 | 33 |
|
| 34 | +import java.util.ArrayList; |
34 | 35 | import java.util.List; |
35 | 36 | import java.util.Objects; |
36 | 37 | import java.util.Optional; |
@@ -517,73 +518,82 @@ public J visitAnnotation(J.Annotation annotation, PrintOutputCapture<P> p) { |
517 | 518 |
|
518 | 519 | @Override |
519 | 520 | public J visitBinary(J.Binary binary, PrintOutputCapture<P> p) { |
520 | | - String keyword = ""; |
| 521 | + // Collect left-recursive binary chain to avoid StackOverflow on deeply nested expressions. |
| 522 | + // For a left-associative tree like ((a + b) + c) + d, this collects [outer, middle, inner] |
| 523 | + // and prints them iteratively instead of recursively. |
| 524 | + List<J.Binary> chain = new ArrayList<>(); |
| 525 | + J.Binary current = binary; |
| 526 | + while (true) { |
| 527 | + chain.add(current); |
| 528 | + if (current.getLeft() instanceof J.Binary) { |
| 529 | + current = (J.Binary) current.getLeft(); |
| 530 | + } else { |
| 531 | + break; |
| 532 | + } |
| 533 | + } |
| 534 | + |
| 535 | + // Print beforeSyntax for each binary, outermost first |
| 536 | + for (J.Binary b : chain) { |
| 537 | + beforeSyntax(b, Space.Location.BINARY_PREFIX, p); |
| 538 | + } |
| 539 | + |
| 540 | + // Visit the leftmost non-binary expression |
| 541 | + visit(chain.get(chain.size() - 1).getLeft(), p); |
| 542 | + |
| 543 | + // Unwind from innermost to outermost: print operator + right + afterSyntax |
| 544 | + for (int i = chain.size() - 1; i >= 0; i--) { |
| 545 | + J.Binary b = chain.get(i); |
| 546 | + visitSpace(b.getPadding().getOperator().getBefore(), Space.Location.BINARY_OPERATOR, p); |
| 547 | + p.append(binaryKeyword(b)); |
| 548 | + visit(b.getRight(), p); |
| 549 | + afterSyntax(b, p); |
| 550 | + } |
| 551 | + return binary; |
| 552 | + } |
| 553 | + |
| 554 | + private String binaryKeyword(J.Binary binary) { |
521 | 555 | switch (binary.getOperator()) { |
522 | 556 | case Addition: |
523 | | - keyword = "+"; |
524 | | - break; |
| 557 | + return "+"; |
525 | 558 | case Subtraction: |
526 | | - keyword = "-"; |
527 | | - break; |
| 559 | + return "-"; |
528 | 560 | case Multiplication: |
529 | | - keyword = "*"; |
530 | | - break; |
| 561 | + return "*"; |
531 | 562 | case Division: |
532 | | - keyword = "/"; |
533 | | - break; |
| 563 | + return "/"; |
534 | 564 | case Modulo: |
535 | | - keyword = "%"; |
536 | | - break; |
| 565 | + return "%"; |
537 | 566 | case LessThan: |
538 | | - keyword = "<"; |
539 | | - break; |
| 567 | + return "<"; |
540 | 568 | case GreaterThan: |
541 | | - keyword = ">"; |
542 | | - break; |
| 569 | + return ">"; |
543 | 570 | case LessThanOrEqual: |
544 | | - keyword = "<="; |
545 | | - break; |
| 571 | + return "<="; |
546 | 572 | case GreaterThanOrEqual: |
547 | | - keyword = ">="; |
548 | | - break; |
| 573 | + return ">="; |
549 | 574 | case Equal: |
550 | | - keyword = "=="; |
551 | | - break; |
| 575 | + return "=="; |
552 | 576 | case NotEqual: |
553 | | - keyword = "!="; |
554 | | - break; |
| 577 | + return "!="; |
555 | 578 | case BitAnd: |
556 | | - keyword = "and"; |
557 | | - break; |
| 579 | + return "and"; |
558 | 580 | case BitOr: |
559 | | - keyword = "or"; |
560 | | - break; |
| 581 | + return "or"; |
561 | 582 | case BitXor: |
562 | | - keyword = "xor"; |
563 | | - break; |
| 583 | + return "xor"; |
564 | 584 | case LeftShift: |
565 | | - keyword = "shl"; |
566 | | - break; |
| 585 | + return "shl"; |
567 | 586 | case RightShift: |
568 | | - keyword = "shr"; |
569 | | - break; |
| 587 | + return "shr"; |
570 | 588 | case UnsignedRightShift: |
571 | | - keyword = "ushr"; |
572 | | - break; |
| 589 | + return "ushr"; |
573 | 590 | case Or: |
574 | | - keyword = (binary.getMarkers().findFirst(LogicalComma.class).isPresent()) ? "," : "||"; |
575 | | - break; |
| 591 | + return binary.getMarkers().findFirst(LogicalComma.class).isPresent() ? "," : "||"; |
576 | 592 | case And: |
577 | | - keyword = "&&"; |
578 | | - break; |
| 593 | + return "&&"; |
| 594 | + default: |
| 595 | + return ""; |
579 | 596 | } |
580 | | - beforeSyntax(binary, Space.Location.BINARY_PREFIX, p); |
581 | | - visit(binary.getLeft(), p); |
582 | | - visitSpace(binary.getPadding().getOperator().getBefore(), Space.Location.BINARY_OPERATOR, p); |
583 | | - p.append(keyword); |
584 | | - visit(binary.getRight(), p); |
585 | | - afterSyntax(binary, p); |
586 | | - return binary; |
587 | 597 | } |
588 | 598 |
|
589 | 599 | @Override |
|
0 commit comments