(expr Expr)
| 582 | } |
| 583 | |
| 584 | func (constantFolderVisitor) VisitPost(expr Expr) (retExpr Expr) { |
| 585 | defer func() { |
| 586 | // go/constant operations can panic for a number of reasons (like division |
| 587 | // by zero), but it's difficult to preemptively detect when they will. It's |
| 588 | // safest to just recover here without folding the expression and let |
| 589 | // normalization or evaluation deal with error handling. |
| 590 | if r := recover(); r != nil { |
| 591 | retExpr = expr |
| 592 | } |
| 593 | }() |
| 594 | switch t := expr.(type) { |
| 595 | case *ParenExpr: |
| 596 | switch cv := t.Expr.(type) { |
| 597 | case *NumVal, *StrVal: |
| 598 | return cv |
| 599 | } |
| 600 | case *UnaryExpr: |
| 601 | switch cv := t.Expr.(type) { |
| 602 | case *NumVal: |
| 603 | if tok, ok := unaryOpToToken[t.Operator]; ok { |
| 604 | return &NumVal{value: constant.UnaryOp(tok, cv.AsConstantValue(), 0)} |
| 605 | } |
| 606 | if token, ok := unaryOpToTokenIntOnly[t.Operator]; ok { |
| 607 | if intVal, ok := cv.AsConstantInt(); ok { |
| 608 | return &NumVal{value: constant.UnaryOp(token, intVal, 0)} |
| 609 | } |
| 610 | } |
| 611 | } |
| 612 | case *BinaryExpr: |
| 613 | switch l := t.Left.(type) { |
| 614 | case *NumVal: |
| 615 | if r, ok := t.Right.(*NumVal); ok { |
| 616 | if token, ok := binaryOpToToken[t.Operator]; ok { |
| 617 | return &NumVal{value: constant.BinaryOp(l.AsConstantValue(), token, r.AsConstantValue())} |
| 618 | } |
| 619 | if token, ok := binaryOpToTokenIntOnly[t.Operator]; ok { |
| 620 | if lInt, ok := l.AsConstantInt(); ok { |
| 621 | if rInt, ok := r.AsConstantInt(); ok { |
| 622 | return &NumVal{value: constant.BinaryOp(lInt, token, rInt)} |
| 623 | } |
| 624 | } |
| 625 | } |
| 626 | // Explicitly ignore shift operators so the expression is evaluated as a |
| 627 | // non-const. This is because 1 << 63 as a 64-bit int (which is a negative |
| 628 | // number due to 2s complement) is different than 1 << 63 as constant, |
| 629 | // which is positive. |
| 630 | } |
| 631 | case *StrVal: |
| 632 | if r, ok := t.Right.(*StrVal); ok { |
| 633 | switch t.Operator { |
| 634 | case Concat: |
| 635 | // When folding string-like constants, if either was a byte |
| 636 | // array literal, the result is also a byte literal. |
| 637 | return &StrVal{s: l.s + r.s, scannedAsBytes: l.scannedAsBytes || r.scannedAsBytes} |
| 638 | } |
| 639 | } |
| 640 | } |
| 641 | case *ComparisonExpr: |
nothing calls this directly
no test coverage detected