cuelang.org/go@v0.10.1/cue/format/node.go (about) 1 // Copyright 2018 The CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package format 16 17 import ( 18 "fmt" 19 "strings" 20 21 "cuelang.org/go/cue/ast" 22 "cuelang.org/go/cue/literal" 23 "cuelang.org/go/cue/token" 24 "cuelang.org/go/internal" 25 ) 26 27 func printNode(node interface{}, f *printer) error { 28 s := newFormatter(f) 29 30 ls := labelSimplifier{scope: map[string]bool{}} 31 32 // format node 33 f.allowed = nooverride // gobble initial whitespace. 34 switch x := node.(type) { 35 case *ast.File: 36 if f.cfg.simplify { 37 ls.markReferences(x) 38 } 39 s.file(x) 40 case ast.Expr: 41 if f.cfg.simplify { 42 ls.markReferences(x) 43 } 44 s.expr(x) 45 case ast.Decl: 46 if f.cfg.simplify { 47 ls.markReferences(x) 48 } 49 s.decl(x) 50 // case ast.Node: // TODO: do we need this? 51 // s.walk(x) 52 case []ast.Decl: 53 if f.cfg.simplify { 54 ls.processDecls(x) 55 } 56 s.walkDeclList(x) 57 default: 58 goto unsupported 59 } 60 61 return s.errs 62 63 unsupported: 64 return fmt.Errorf("cue/format: unsupported node type %T", node) 65 } 66 67 func isRegularField(tok token.Token) bool { 68 return tok == token.ILLEGAL || tok == token.COLON 69 } 70 71 // Helper functions for common node lists. They may be empty. 72 73 func nestDepth(f *ast.Field) int { 74 d := 1 75 if s, ok := f.Value.(*ast.StructLit); ok { 76 switch { 77 case len(s.Elts) != 1: 78 d = 0 79 default: 80 if f, ok := s.Elts[0].(*ast.Field); ok { 81 d += nestDepth(f) 82 } 83 } 84 } 85 return d 86 } 87 88 // TODO: be more accurate and move to astutil 89 func hasDocComments(d ast.Decl) bool { 90 if len(ast.Comments(d)) > 0 { 91 return true 92 } 93 switch x := d.(type) { 94 case *ast.Field: 95 return len(ast.Comments(x.Label)) > 0 96 case *ast.Alias: 97 return len(ast.Comments(x.Ident)) > 0 98 case *ast.LetClause: 99 return len(ast.Comments(x.Ident)) > 0 100 } 101 return false 102 } 103 104 func (f *formatter) walkDeclList(list []ast.Decl) { 105 f.before(nil) 106 d := 0 107 var ellipsis ast.Decl 108 for i, x := range list { 109 if i > 0 { 110 f.print(declcomma) 111 nd := 0 112 if f, ok := x.(*ast.Field); ok { 113 nd = nestDepth(f) 114 } 115 if f.current.parentSep == newline && (d == 0 || nd != d) { 116 f.print(f.formfeed()) 117 } 118 if hasDocComments(x) { 119 switch x := list[i-1].(type) { 120 case *ast.Field: 121 if internal.IsDefinition(x.Label) { 122 f.print(newsection) 123 } 124 125 default: 126 f.print(newsection) 127 } 128 } 129 } 130 if f.printer.cfg.simplify && internal.IsEllipsis(x) { 131 ellipsis = x 132 continue 133 } 134 f.decl(x) 135 d = 0 136 if f, ok := x.(*ast.Field); ok { 137 d = nestDepth(f) 138 } 139 if j := i + 1; j < len(list) { 140 switch x := list[j].(type) { 141 case *ast.Field: 142 switch x := x.Value.(type) { 143 case *ast.StructLit: 144 // TODO: not entirely correct: could have multiple elements, 145 // not have a valid Lbrace, and be marked multiline. This 146 // cannot occur for ASTs resulting from a parse, though. 147 if x.Lbrace.IsValid() || len(x.Elts) != 1 { 148 f.print(f.formfeed()) 149 continue 150 } 151 case *ast.ListLit: 152 f.print(f.formfeed()) 153 continue 154 } 155 } 156 } 157 f.print(f.current.parentSep) 158 } 159 if ellipsis != nil { 160 // ensure that comments associated with the original ellipsis are preserved 161 n := &ast.Ellipsis{} 162 ast.SetComments(n, ast.Comments(ellipsis)) 163 f.decl(n) 164 f.print(f.current.parentSep) 165 } 166 f.after(nil) 167 } 168 169 func (f *formatter) walkSpecList(list []*ast.ImportSpec) { 170 f.before(nil) 171 for _, x := range list { 172 f.before(x) 173 f.importSpec(x) 174 f.after(x) 175 } 176 f.after(nil) 177 } 178 179 func (f *formatter) walkClauseList(list []ast.Clause, ws whiteSpace) { 180 f.before(nil) 181 for i, x := range list { 182 f.before(x) 183 // Only print the whitespace between the clauses. 184 if i > 0 { 185 f.print(ws) 186 } 187 f.clause(x) 188 f.after(x) 189 } 190 f.after(nil) 191 } 192 193 func (f *formatter) walkListElems(list []ast.Expr) { 194 f.before(nil) 195 for _, x := range list { 196 f.before(x) 197 198 // This is a hack to ensure that comments are printed correctly in lists. 199 // A comment must be printed after each element in a list, but we can't 200 // print a comma at the end of a comment because it will be considered 201 // part of the comment and ignored. 202 // To fix this we collect all comments that appear after the element, 203 // and only handle them after it's formatted. 204 var commentsAfter []*ast.CommentGroup 205 splitComments := x.Pos().IsValid() 206 if splitComments { 207 for _, cg := range ast.Comments(x) { 208 if x.Pos().Before(cg.Pos()) { 209 commentsAfter = append(commentsAfter, cg) 210 } 211 } 212 } 213 214 if splitComments { 215 f.current.cg = nil 216 } 217 switch n := x.(type) { 218 case *ast.Comprehension: 219 f.walkClauseList(n.Clauses, blank) 220 f.print(blank, nooverride) 221 f.expr(n.Value) 222 223 case *ast.Ellipsis: 224 f.ellipsis(n) 225 226 case *ast.Alias: 227 f.expr(n.Ident) 228 f.print(n.Equal, token.BIND) 229 f.expr(n.Expr) 230 231 // TODO: ast.CommentGroup: allows comment groups in ListLits. 232 233 case ast.Expr: 234 f.exprRaw(n, token.LowestPrec, 1) 235 } 236 f.print(comma, blank) 237 238 if splitComments { 239 f.current.cg = commentsAfter 240 } 241 f.after(x) 242 } 243 f.after(nil) 244 } 245 246 func (f *formatter) walkArgsList(list []ast.Expr, depth int) { 247 f.before(nil) 248 for _, x := range list { 249 f.before(x) 250 f.exprRaw(x, token.LowestPrec, depth) 251 f.print(comma, blank) 252 f.after(x) 253 } 254 f.after(nil) 255 } 256 257 func (f *formatter) file(file *ast.File) { 258 f.before(file) 259 f.walkDeclList(file.Decls) 260 f.after(file) 261 f.print(token.EOF) 262 } 263 264 func (f *formatter) inlineField(n *ast.Field) *ast.Field { 265 regular := internal.IsRegularField(n) 266 // shortcut single-element structs. 267 // If the label has a valid position, we assume that an unspecified 268 // Lbrace signals the intent to collapse fields. 269 if !n.Label.Pos().IsValid() && !(f.printer.cfg.simplify && regular) { 270 return nil 271 } 272 273 obj, ok := n.Value.(*ast.StructLit) 274 if !ok || len(obj.Elts) != 1 || 275 (obj.Lbrace.IsValid() && !f.printer.cfg.simplify) || 276 (obj.Lbrace.IsValid() && hasDocComments(n)) || 277 len(n.Attrs) > 0 { 278 return nil 279 } 280 281 mem, ok := obj.Elts[0].(*ast.Field) 282 if !ok || len(mem.Attrs) > 0 { 283 return nil 284 } 285 286 if hasDocComments(mem) { 287 // TODO: this inserts curly braces even in spaces where this 288 // may not be desirable, such as: 289 // a: 290 // // foo 291 // b: 3 292 return nil 293 } 294 return mem 295 } 296 297 func (f *formatter) decl(decl ast.Decl) { 298 if decl == nil { 299 return 300 } 301 defer f.after(decl) 302 if !f.before(decl) { 303 return 304 } 305 306 switch n := decl.(type) { 307 case *ast.Field: 308 constraint, _ := internal.ConstraintToken(n) 309 f.label(n.Label, constraint) 310 311 regular := isRegularField(n.Token) 312 if regular { 313 f.print(noblank, nooverride, n.TokenPos, token.COLON) 314 } else { 315 f.print(blank, nooverride, n.Token) 316 } 317 f.visitComments(f.current.pos) 318 319 if mem := f.inlineField(n); mem != nil { 320 switch { 321 default: 322 fallthrough 323 324 case regular && f.cfg.simplify: 325 f.print(blank, nooverride) 326 f.decl(mem) 327 328 case mem.Label.Pos().IsNewline(): 329 f.print(indent, formfeed) 330 f.decl(mem) 331 f.indent-- 332 } 333 return 334 } 335 336 nextFF := f.nextNeedsFormfeed(n.Value) 337 tab := vtab 338 if nextFF || f.prevLbraceOnLine { 339 tab = blank 340 } 341 342 f.print(tab) 343 344 if n.Value != nil { 345 switch n.Value.(type) { 346 case *ast.ListLit, *ast.StructLit: 347 f.expr(n.Value) 348 default: 349 f.print(indent) 350 f.expr(n.Value) 351 f.markUnindentLine() 352 } 353 } else { 354 f.current.pos++ 355 f.visitComments(f.current.pos) 356 } 357 358 space := tab 359 for _, a := range n.Attrs { 360 if f.before(a) { 361 f.print(space, a.At, a) 362 } 363 f.after(a) 364 space = blank 365 } 366 367 if nextFF { 368 f.print(formfeed) 369 } 370 371 case *ast.BadDecl: 372 f.print(n.From, "*bad decl*", declcomma) 373 374 case *ast.Package: 375 f.print(n.PackagePos, "package") 376 f.print(blank, n.Name, newsection, nooverride) 377 378 case *ast.ImportDecl: 379 f.print(n.Import, "import") 380 if len(n.Specs) == 0 { 381 f.print(blank, n.Lparen, token.LPAREN, n.Rparen, token.RPAREN, newline) 382 break 383 } 384 switch { 385 case len(n.Specs) == 1 && len(n.Specs[0].Comments()) == 0: 386 if !n.Lparen.IsValid() { 387 f.print(blank) 388 f.walkSpecList(n.Specs) 389 break 390 } 391 fallthrough 392 default: 393 f.print(blank, n.Lparen, token.LPAREN, newline, indent) 394 f.walkSpecList(n.Specs) 395 f.print(unindent, newline, n.Rparen, token.RPAREN, newline) 396 } 397 f.print(newsection, nooverride) 398 399 case *ast.LetClause: 400 if !decl.Pos().HasRelPos() || decl.Pos().RelPos() >= token.Newline { 401 f.print(formfeed) 402 } 403 f.print(n.Let, token.LET, blank, nooverride) 404 f.expr(n.Ident) 405 f.print(blank, nooverride, n.Equal, token.BIND, blank) 406 f.expr(n.Expr) 407 f.print(declcomma) // implied 408 409 case *ast.EmbedDecl: 410 if !n.Pos().HasRelPos() || n.Pos().RelPos() >= token.Newline { 411 f.print(formfeed) 412 } 413 f.expr(n.Expr) 414 f.print(newline) 415 416 case *ast.Attribute: 417 f.print(n.At, n) 418 419 case *ast.CommentGroup: 420 f.printComment(n) 421 f.print(newsection) 422 423 case ast.Expr: 424 f.embedding(n) 425 } 426 } 427 428 func (f *formatter) embedding(decl ast.Expr) { 429 switch n := decl.(type) { 430 case *ast.Comprehension: 431 if !n.Pos().HasRelPos() || n.Pos().RelPos() >= token.Newline { 432 f.print(formfeed) 433 } 434 f.walkClauseList(n.Clauses, blank) 435 f.print(blank, nooverride) 436 f.expr(n.Value) 437 438 case *ast.Ellipsis: 439 f.ellipsis(n) 440 441 case *ast.Alias: 442 if !decl.Pos().HasRelPos() || decl.Pos().RelPos() >= token.Newline { 443 f.print(formfeed) 444 } 445 f.expr(n.Ident) 446 f.print(blank, n.Equal, token.BIND, blank) 447 f.expr(n.Expr) 448 f.print(declcomma) // implied 449 450 // TODO: ast.CommentGroup: allows comment groups in ListLits. 451 452 case ast.Expr: 453 f.exprRaw(n, token.LowestPrec, 1) 454 } 455 } 456 457 func (f *formatter) nextNeedsFormfeed(n ast.Expr) bool { 458 switch x := n.(type) { 459 case *ast.StructLit: 460 return true 461 case *ast.BasicLit: 462 return strings.IndexByte(x.Value, '\n') >= 0 463 case *ast.ListLit: 464 return true 465 case *ast.ParenExpr: 466 return f.nextNeedsFormfeed(x.X) 467 case *ast.UnaryExpr: 468 return f.nextNeedsFormfeed(x.X) 469 case *ast.BinaryExpr: 470 return f.nextNeedsFormfeed(x.X) || f.nextNeedsFormfeed(x.Y) 471 case *ast.IndexExpr: 472 return f.nextNeedsFormfeed(x.X) 473 case *ast.SelectorExpr: 474 return f.nextNeedsFormfeed(x.X) 475 case *ast.CallExpr: 476 for _, arg := range x.Args { 477 if f.nextNeedsFormfeed(arg) { 478 return true 479 } 480 } 481 } 482 return false 483 } 484 485 func (f *formatter) importSpec(x *ast.ImportSpec) { 486 if x.Name != nil { 487 f.label(x.Name, token.ILLEGAL) 488 f.print(blank) 489 } else { 490 f.current.pos++ 491 f.visitComments(f.current.pos) 492 } 493 f.expr(x.Path) 494 f.print(newline) 495 } 496 497 func (f *formatter) label(l ast.Label, constraint token.Token) { 498 f.before(l) 499 defer f.after(l) 500 switch n := l.(type) { 501 case *ast.Alias: 502 f.expr(n) 503 504 case *ast.Ident: 505 // Escape an identifier that has invalid characters. This may happen, 506 // if the AST is not generated by the parser. 507 name := n.Name 508 if !ast.IsValidIdent(name) { 509 name = literal.Label.Quote(n.Name) 510 } 511 f.print(n.NamePos, name) 512 513 case *ast.BasicLit: 514 str := n.Value 515 // Allow any CUE string in the AST, but ensure it is formatted 516 // according to spec. 517 if strings.HasPrefix(str, `"""`) || strings.HasPrefix(str, "#") { 518 if u, err := literal.Unquote(str); err == nil { 519 str = literal.Label.Quote(u) 520 } 521 } 522 f.print(n.ValuePos, str) 523 524 case *ast.ListLit: 525 f.expr(n) 526 527 case *ast.ParenExpr: 528 f.expr(n) 529 530 case *ast.Interpolation: 531 f.expr(n) 532 533 default: 534 panic(fmt.Sprintf("unknown label type %T", n)) 535 } 536 if constraint != token.ILLEGAL { 537 f.print(constraint) 538 } 539 } 540 541 func (f *formatter) ellipsis(x *ast.Ellipsis) { 542 f.print(x.Ellipsis, token.ELLIPSIS) 543 if x.Type != nil && !isTop(x.Type) { 544 f.expr(x.Type) 545 } 546 } 547 548 func (f *formatter) expr(x ast.Expr) { 549 const depth = 1 550 f.expr1(x, token.LowestPrec, depth) 551 } 552 553 func (f *formatter) expr0(x ast.Expr, depth int) { 554 f.expr1(x, token.LowestPrec, depth) 555 } 556 557 func (f *formatter) expr1(expr ast.Expr, prec1, depth int) { 558 if f.before(expr) { 559 f.exprRaw(expr, prec1, depth) 560 } 561 f.after(expr) 562 } 563 564 func (f *formatter) exprRaw(expr ast.Expr, prec1, depth int) { 565 566 switch x := expr.(type) { 567 case *ast.BadExpr: 568 f.print(x.From, "_|_") 569 570 case *ast.BottomLit: 571 f.print(x.Bottom, token.BOTTOM) 572 573 case *ast.Alias: 574 // Aliases in expression positions are printed in short form. 575 f.label(x.Ident, token.ILLEGAL) 576 f.print(x.Equal, token.BIND) 577 f.expr(x.Expr) 578 579 case *ast.Ident: 580 f.print(x.NamePos, x) 581 582 case *ast.BinaryExpr: 583 if depth < 1 { 584 f.internalError("depth < 1:", depth) 585 depth = 1 586 } 587 f.binaryExpr(x, prec1, cutoff(x, depth), depth) 588 589 case *ast.UnaryExpr: 590 const prec = token.UnaryPrec 591 if prec < prec1 { 592 // parenthesis needed 593 f.print(token.LPAREN, nooverride) 594 f.expr(x) 595 f.print(token.RPAREN) 596 } else { 597 // no parenthesis needed 598 f.print(x.OpPos, x.Op, nooverride) 599 f.expr1(x.X, prec, depth) 600 } 601 602 case *ast.BasicLit: 603 f.print(x.ValuePos, x) 604 605 case *ast.Interpolation: 606 f.before(nil) 607 for _, x := range x.Elts { 608 f.expr0(x, depth+1) 609 } 610 f.after(nil) 611 612 case *ast.ParenExpr: 613 if _, hasParens := x.X.(*ast.ParenExpr); hasParens { 614 // don't print parentheses around an already parenthesized expression 615 // TODO: consider making this more general and incorporate precedence levels 616 f.expr0(x.X, depth) 617 } else { 618 f.print(x.Lparen, token.LPAREN) 619 f.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth 620 f.print(x.Rparen, token.RPAREN) 621 } 622 623 case *ast.SelectorExpr: 624 f.selectorExpr(x, depth) 625 626 case *ast.IndexExpr: 627 f.expr1(x.X, token.HighestPrec, 1) 628 f.print(x.Lbrack, token.LBRACK) 629 f.expr0(x.Index, depth+1) 630 f.print(x.Rbrack, token.RBRACK) 631 632 case *ast.SliceExpr: 633 f.expr1(x.X, token.HighestPrec, 1) 634 f.print(x.Lbrack, token.LBRACK) 635 indices := []ast.Expr{x.Low, x.High} 636 for i, y := range indices { 637 if i > 0 { 638 // blanks around ":" if both sides exist and either side is a binary expression 639 x := indices[i-1] 640 if depth <= 1 && x != nil && y != nil && (isBinary(x) || isBinary(y)) { 641 f.print(blank, token.COLON, blank) 642 } else { 643 f.print(token.COLON) 644 } 645 } 646 if y != nil { 647 f.expr0(y, depth+1) 648 } 649 } 650 f.print(x.Rbrack, token.RBRACK) 651 652 case *ast.CallExpr: 653 if len(x.Args) > 1 { 654 depth++ 655 } 656 wasIndented := f.possibleSelectorExpr(x.Fun, token.HighestPrec, depth) 657 f.print(x.Lparen, token.LPAREN) 658 f.walkArgsList(x.Args, depth) 659 f.print(trailcomma, noblank, x.Rparen, token.RPAREN) 660 if wasIndented { 661 f.print(unindent) 662 } 663 664 case *ast.StructLit: 665 var l line 666 ws := noblank 667 ff := f.formfeed() 668 669 switch { 670 case len(x.Elts) == 0: 671 // collapse curly braces if the body is empty. 672 ffAlt := blank | nooverride 673 for _, c := range x.Comments() { 674 if c.Position == 1 { 675 ffAlt = ff 676 break 677 } 678 } 679 ff = ffAlt 680 case !x.Rbrace.HasRelPos() || !x.Elts[0].Pos().HasRelPos(): 681 ws |= newline | nooverride 682 } 683 f.print(x.Lbrace, token.LBRACE, &l, ws, ff, indent) 684 f.prevLbraceOnLine = l == f.lineout 685 686 f.walkDeclList(x.Elts) 687 f.matchUnindent() 688 689 ws = noblank 690 if f.lineout != l { 691 ws |= newline 692 if f.lastTok != token.RBRACE && f.lastTok != token.RBRACK { 693 ws |= nooverride 694 } 695 } 696 f.print(ws, x.Rbrace, token.RBRACE) 697 698 case *ast.ListLit: 699 ws := noblank | indent 700 if len(x.Elts) == 0 { 701 // collapse square brackets if the body is empty. 702 collapseWs := blank | nooverride 703 for _, c := range x.Comments() { 704 if c.Position == 1 { 705 collapseWs = ws 706 break 707 } 708 } 709 ws |= collapseWs 710 } 711 712 f.print(x.Lbrack, token.LBRACK, ws) 713 f.walkListElems(x.Elts) 714 f.print(trailcomma, noblank) 715 f.visitComments(f.current.pos) 716 f.matchUnindent() 717 f.print(noblank, x.Rbrack, token.RBRACK) 718 719 case *ast.Ellipsis: 720 f.ellipsis(x) 721 722 default: 723 panic(fmt.Sprintf("unimplemented type %T", x)) 724 } 725 } 726 727 func (f *formatter) clause(clause ast.Clause) { 728 switch n := clause.(type) { 729 case *ast.ForClause: 730 f.print(n.For, "for", blank) 731 f.print(indent) 732 if n.Key != nil { 733 f.label(n.Key, token.ILLEGAL) 734 f.print(n.Colon, token.COMMA, blank) 735 } else { 736 f.current.pos++ 737 f.visitComments(f.current.pos) 738 } 739 f.label(n.Value, token.ILLEGAL) 740 f.print(blank, n.In, "in", blank) 741 f.expr(n.Source) 742 f.markUnindentLine() 743 744 case *ast.IfClause: 745 f.print(n.If, "if", blank) 746 f.print(indent) 747 f.expr(n.Condition) 748 f.markUnindentLine() 749 750 case *ast.LetClause: 751 // TODO(mvdan): LetClause is handled in both the clause and decl methods, 752 // because at the semantic level it is different in each case, but the code is repetitive. 753 f.print(n.Let, token.LET, blank, nooverride) 754 f.print(indent) 755 f.expr(n.Ident) 756 f.print(blank, nooverride, n.Equal, token.BIND, blank) 757 f.expr(n.Expr) 758 f.markUnindentLine() 759 760 default: 761 panic("unknown clause type") 762 } 763 } 764 765 func walkBinary(e *ast.BinaryExpr) (has6, has7, has8 bool, maxProblem int) { 766 switch e.Op.Precedence() { 767 case 6: 768 has6 = true 769 case 7: 770 has7 = true 771 case 8: 772 has8 = true 773 } 774 775 switch l := e.X.(type) { 776 case *ast.BinaryExpr: 777 if l.Op.Precedence() < e.Op.Precedence() { 778 // parens will be inserted. 779 // pretend this is an *syntax.ParenExpr and do nothing. 780 break 781 } 782 h6, h7, h8, mp := walkBinary(l) 783 has6 = has6 || h6 784 has7 = has7 || h7 785 has8 = has8 || h8 786 if maxProblem < mp { 787 maxProblem = mp 788 } 789 } 790 791 switch r := e.Y.(type) { 792 case *ast.BinaryExpr: 793 if r.Op.Precedence() <= e.Op.Precedence() { 794 // parens will be inserted. 795 // pretend this is an *syntax.ParenExpr and do nothing. 796 break 797 } 798 h6, h7, h8, mp := walkBinary(r) 799 has6 = has6 || h6 800 has7 = has7 || h7 801 has8 = has8 || h8 802 if maxProblem < mp { 803 maxProblem = mp 804 } 805 806 case *ast.UnaryExpr: 807 switch e.Op.String() + r.Op.String() { 808 case "/*": 809 maxProblem = 8 810 case "++", "--": 811 if maxProblem < 6 { 812 maxProblem = 6 813 } 814 } 815 } 816 return 817 } 818 819 func cutoff(e *ast.BinaryExpr, depth int) int { 820 has6, has7, has8, maxProblem := walkBinary(e) 821 if maxProblem > 0 { 822 return maxProblem + 1 823 } 824 if (has6 || has7) && has8 { 825 if depth == 1 { 826 return 8 827 } 828 if has7 { 829 return 7 830 } 831 return 6 832 } 833 if has6 && has7 { 834 if depth == 1 { 835 return 7 836 } 837 return 6 838 } 839 if depth == 1 { 840 return 8 841 } 842 return 6 843 } 844 845 func diffPrec(expr ast.Expr, prec int) int { 846 x, ok := expr.(*ast.BinaryExpr) 847 if !ok || prec != x.Op.Precedence() { 848 return 1 849 } 850 return 0 851 } 852 853 func reduceDepth(depth int) int { 854 depth-- 855 if depth < 1 { 856 depth = 1 857 } 858 return depth 859 } 860 861 // Format the binary expression: decide the cutoff and then format. 862 // Let's call depth == 1 Normal mode, and depth > 1 Compact mode. 863 // (Algorithm suggestion by Russ Cox.) 864 // 865 // The precedences are: 866 // 867 // 7 * / % quo rem div mod 868 // 6 + - 869 // 5 == != < <= > >= 870 // 4 && 871 // 3 || 872 // 2 & 873 // 1 | 874 // 875 // The only decision is whether there will be spaces around levels 6 and 7. 876 // There are never spaces at level 8 (unary), and always spaces at levels 5 and below. 877 // 878 // To choose the cutoff, look at the whole expression but excluding primary 879 // expressions (function calls, parenthesized exprs), and apply these rules: 880 // 881 // 1. If there is a binary operator with a right side unary operand 882 // that would clash without a space, the cutoff must be (in order): 883 // 884 // /* 8 885 // ++ 7 // not necessary, but to avoid confusion 886 // -- 7 887 // 888 // (Comparison operators always have spaces around them.) 889 // 890 // 2. If there is a mix of level 7 and level 6 operators, then the cutoff 891 // is 7 (use spaces to distinguish precedence) in Normal mode 892 // and 6 (never use spaces) in Compact mode. 893 // 894 // 3. If there are no level 6 operators or no level 7 operators, then the 895 // cutoff is 8 (always use spaces) in Normal mode 896 // and 6 (never use spaces) in Compact mode. 897 func (f *formatter) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) { 898 f.nestExpr++ 899 defer func() { f.nestExpr-- }() 900 901 prec := x.Op.Precedence() 902 if prec < prec1 { 903 // parenthesis needed 904 // Note: The parser inserts a syntax.ParenExpr node; thus this case 905 // can only occur if the AST is created in a different way. 906 // defer p.pushComment(nil).pop() 907 f.print(token.LPAREN, nooverride) 908 f.expr0(x, reduceDepth(depth)) // parentheses undo one level of depth 909 f.print(token.RPAREN) 910 return 911 } 912 913 printBlank := prec < cutoff 914 915 f.expr1(x.X, prec, depth+diffPrec(x.X, prec)) 916 f.print(nooverride) 917 if printBlank { 918 f.print(blank) 919 } 920 f.print(x.OpPos, x.Op) 921 if x.Y.Pos().IsNewline() { 922 // at least one line break, but respect an extra empty line 923 // in the source 924 f.print(formfeed) 925 printBlank = false // no blank after line break 926 } else { 927 f.print(nooverride) 928 } 929 if printBlank { 930 f.print(blank) 931 } 932 f.expr1(x.Y, prec+1, depth+1) 933 } 934 935 func isBinary(expr ast.Expr) bool { 936 _, ok := expr.(*ast.BinaryExpr) 937 return ok 938 } 939 940 func (f *formatter) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool { 941 if x, ok := expr.(*ast.SelectorExpr); ok { 942 return f.selectorExpr(x, depth) 943 } 944 f.expr1(expr, prec1, depth) 945 return false 946 } 947 948 // selectorExpr handles an *syntax.SelectorExpr node and returns whether x spans 949 // multiple lines. 950 func (f *formatter) selectorExpr(x *ast.SelectorExpr, depth int) bool { 951 f.expr1(x.X, token.HighestPrec, depth) 952 f.print(token.PERIOD) 953 if x.Sel.Pos().IsNewline() { 954 f.print(indent, formfeed) 955 f.expr(x.Sel.(ast.Expr)) 956 f.print(unindent) 957 return true 958 } 959 f.print(noblank) 960 f.expr(x.Sel.(ast.Expr)) 961 return false 962 } 963 964 func isTop(e ast.Expr) bool { 965 ident, ok := e.(*ast.Ident) 966 return ok && ident.Name == "_" 967 }