github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/cmd/compile/internal/syntax/printer.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file implements printing of syntax trees in source format. 6 7 package syntax 8 9 import ( 10 "bytes" 11 "fmt" 12 "io" 13 "strings" 14 ) 15 16 // TODO(gri) Consider removing the linebreaks flag from this signature. 17 // Its likely rarely used in common cases. 18 19 func Fprint(w io.Writer, x Node, linebreaks bool) (n int, err error) { 20 p := printer{ 21 output: w, 22 linebreaks: linebreaks, 23 } 24 25 defer func() { 26 n = p.written 27 if e := recover(); e != nil { 28 err = e.(localError).err // re-panics if it's not a localError 29 } 30 }() 31 32 p.print(x) 33 p.flush(_EOF) 34 35 return 36 } 37 38 func String(n Node) string { 39 var buf bytes.Buffer 40 _, err := Fprint(&buf, n, false) 41 if err != nil { 42 panic(err) // TODO(gri) print something sensible into buf instead 43 } 44 return buf.String() 45 } 46 47 type ctrlSymbol int 48 49 const ( 50 none ctrlSymbol = iota 51 semi 52 blank 53 newline 54 indent 55 outdent 56 // comment 57 // eolComment 58 ) 59 60 type whitespace struct { 61 last token 62 kind ctrlSymbol 63 //text string // comment text (possibly ""); valid if kind == comment 64 } 65 66 type printer struct { 67 output io.Writer 68 written int // number of bytes written 69 linebreaks bool // print linebreaks instead of semis 70 71 indent int // current indentation level 72 nlcount int // number of consecutive newlines 73 74 pending []whitespace // pending whitespace 75 lastTok token // last token (after any pending semi) processed by print 76 } 77 78 // write is a thin wrapper around p.output.Write 79 // that takes care of accounting and error handling. 80 func (p *printer) write(data []byte) { 81 n, err := p.output.Write(data) 82 p.written += n 83 if err != nil { 84 panic(localError{err}) 85 } 86 } 87 88 var ( 89 tabBytes = []byte("\t\t\t\t\t\t\t\t") 90 newlineByte = []byte("\n") 91 blankByte = []byte(" ") 92 ) 93 94 func (p *printer) writeBytes(data []byte) { 95 if len(data) == 0 { 96 panic("expected non-empty []byte") 97 } 98 if p.nlcount > 0 && p.indent > 0 { 99 // write indentation 100 n := p.indent 101 for n > len(tabBytes) { 102 p.write(tabBytes) 103 n -= len(tabBytes) 104 } 105 p.write(tabBytes[:n]) 106 } 107 p.write(data) 108 p.nlcount = 0 109 } 110 111 func (p *printer) writeString(s string) { 112 p.writeBytes([]byte(s)) 113 } 114 115 // If impliesSemi returns true for a non-blank line's final token tok, 116 // a semicolon is automatically inserted. Vice versa, a semicolon may 117 // be omitted in those cases. 118 func impliesSemi(tok token) bool { 119 switch tok { 120 case _Name, 121 _Break, _Continue, _Fallthrough, _Return, 122 /*_Inc, _Dec,*/ _Rparen, _Rbrack, _Rbrace: // TODO(gri) fix this 123 return true 124 } 125 return false 126 } 127 128 // TODO(gri) provide table of []byte values for all tokens to avoid repeated string conversion 129 130 func lineComment(text string) bool { 131 return strings.HasPrefix(text, "//") 132 } 133 134 func (p *printer) addWhitespace(kind ctrlSymbol, text string) { 135 p.pending = append(p.pending, whitespace{p.lastTok, kind /*text*/}) 136 switch kind { 137 case semi: 138 p.lastTok = _Semi 139 case newline: 140 p.lastTok = 0 141 // TODO(gri) do we need to handle /*-style comments containing newlines here? 142 } 143 } 144 145 func (p *printer) flush(next token) { 146 // eliminate semis and redundant whitespace 147 sawNewline := next == _EOF 148 sawParen := next == _Rparen || next == _Rbrace 149 for i := len(p.pending) - 1; i >= 0; i-- { 150 switch p.pending[i].kind { 151 case semi: 152 k := semi 153 if sawParen { 154 sawParen = false 155 k = none // eliminate semi 156 } else if sawNewline && impliesSemi(p.pending[i].last) { 157 sawNewline = false 158 k = none // eliminate semi 159 } 160 p.pending[i].kind = k 161 case newline: 162 sawNewline = true 163 case blank, indent, outdent: 164 // nothing to do 165 // case comment: 166 // // A multi-line comment acts like a newline; and a "" 167 // // comment implies by definition at least one newline. 168 // if text := p.pending[i].text; strings.HasPrefix(text, "/*") && strings.ContainsRune(text, '\n') { 169 // sawNewline = true 170 // } 171 // case eolComment: 172 // // TODO(gri) act depending on sawNewline 173 default: 174 panic("unreachable") 175 } 176 } 177 178 // print pending 179 prev := none 180 for i := range p.pending { 181 switch p.pending[i].kind { 182 case none: 183 // nothing to do 184 case semi: 185 p.writeString(";") 186 p.nlcount = 0 187 prev = semi 188 case blank: 189 if prev != blank { 190 // at most one blank 191 p.writeBytes(blankByte) 192 p.nlcount = 0 193 prev = blank 194 } 195 case newline: 196 const maxEmptyLines = 1 197 if p.nlcount <= maxEmptyLines { 198 p.write(newlineByte) 199 p.nlcount++ 200 prev = newline 201 } 202 case indent: 203 p.indent++ 204 case outdent: 205 p.indent-- 206 if p.indent < 0 { 207 panic("negative indentation") 208 } 209 // case comment: 210 // if text := p.pending[i].text; text != "" { 211 // p.writeString(text) 212 // p.nlcount = 0 213 // prev = comment 214 // } 215 // // TODO(gri) should check that line comments are always followed by newline 216 default: 217 panic("unreachable") 218 } 219 } 220 221 p.pending = p.pending[:0] // re-use underlying array 222 } 223 224 func mayCombine(prev token, next byte) (b bool) { 225 return // for now 226 // switch prev { 227 // case lexical.Int: 228 // b = next == '.' // 1. 229 // case lexical.Add: 230 // b = next == '+' // ++ 231 // case lexical.Sub: 232 // b = next == '-' // -- 233 // case lexical.Quo: 234 // b = next == '*' // /* 235 // case lexical.Lss: 236 // b = next == '-' || next == '<' // <- or << 237 // case lexical.And: 238 // b = next == '&' || next == '^' // && or &^ 239 // } 240 // return 241 } 242 243 func (p *printer) print(args ...interface{}) { 244 for i := 0; i < len(args); i++ { 245 switch x := args[i].(type) { 246 case nil: 247 // we should not reach here but don't crash 248 249 case Node: 250 p.printNode(x) 251 252 case token: 253 // _Name implies an immediately following string 254 // argument which is the actual value to print. 255 var s string 256 if x == _Name { 257 i++ 258 if i >= len(args) { 259 panic("missing string argument after _Name") 260 } 261 s = args[i].(string) 262 } else { 263 s = x.String() 264 } 265 266 // TODO(gri) This check seems at the wrong place since it doesn't 267 // take into account pending white space. 268 if mayCombine(p.lastTok, s[0]) { 269 panic("adjacent tokens combine without whitespace") 270 } 271 272 if x == _Semi { 273 // delay printing of semi 274 p.addWhitespace(semi, "") 275 } else { 276 p.flush(x) 277 p.writeString(s) 278 p.nlcount = 0 279 p.lastTok = x 280 } 281 282 case Operator: 283 if x != 0 { 284 p.flush(_Operator) 285 p.writeString(x.String()) 286 } 287 288 case ctrlSymbol: 289 switch x { 290 case none, semi /*, comment*/ : 291 panic("unreachable") 292 case newline: 293 // TODO(gri) need to handle mandatory newlines after a //-style comment 294 if !p.linebreaks { 295 x = blank 296 } 297 } 298 p.addWhitespace(x, "") 299 300 // case *Comment: // comments are not Nodes 301 // p.addWhitespace(comment, x.Text) 302 303 default: 304 panic(fmt.Sprintf("unexpected argument %v (%T)", x, x)) 305 } 306 } 307 } 308 309 func (p *printer) printNode(n Node) { 310 // ncom := *n.Comments() 311 // if ncom != nil { 312 // // TODO(gri) in general we cannot make assumptions about whether 313 // // a comment is a /*- or a //-style comment since the syntax 314 // // tree may have been manipulated. Need to make sure the correct 315 // // whitespace is emitted. 316 // for _, c := range ncom.Alone { 317 // p.print(c, newline) 318 // } 319 // for _, c := range ncom.Before { 320 // if c.Text == "" || lineComment(c.Text) { 321 // panic("unexpected empty line or //-style 'before' comment") 322 // } 323 // p.print(c, blank) 324 // } 325 // } 326 327 p.printRawNode(n) 328 329 // if ncom != nil && len(ncom.After) > 0 { 330 // for i, c := range ncom.After { 331 // if i+1 < len(ncom.After) { 332 // if c.Text == "" || lineComment(c.Text) { 333 // panic("unexpected empty line or //-style non-final 'after' comment") 334 // } 335 // } 336 // p.print(blank, c) 337 // } 338 // //p.print(newline) 339 // } 340 } 341 342 func (p *printer) printRawNode(n Node) { 343 switch n := n.(type) { 344 // expressions and types 345 case *Name: 346 p.print(_Name, n.Value) // _Name requires actual value following immediately 347 348 case *BasicLit: 349 p.print(_Name, n.Value) // _Name requires actual value following immediately 350 351 case *FuncLit: 352 p.print(n.Type, blank) 353 p.printBody(n.Body) 354 355 case *CompositeLit: 356 if n.Type != nil { 357 p.print(n.Type) 358 } 359 p.print(_Lbrace) 360 if n.NKeys > 0 && n.NKeys == len(n.ElemList) { 361 p.printExprLines(n.ElemList) 362 } else { 363 p.printExprList(n.ElemList) 364 } 365 p.print(_Rbrace) 366 367 case *ParenExpr: 368 p.print(_Lparen, n.X, _Rparen) 369 370 case *SelectorExpr: 371 p.print(n.X, _Dot, n.Sel) 372 373 case *IndexExpr: 374 p.print(n.X, _Lbrack, n.Index, _Rbrack) 375 376 case *SliceExpr: 377 p.print(n.X, _Lbrack) 378 if i := n.Index[0]; i != nil { 379 p.printNode(i) 380 } 381 p.print(_Colon) 382 if j := n.Index[1]; j != nil { 383 p.printNode(j) 384 } 385 if k := n.Index[2]; k != nil { 386 p.print(_Colon, k) 387 } 388 p.print(_Rbrack) 389 390 case *AssertExpr: 391 p.print(n.X, _Dot, _Lparen) 392 if n.Type != nil { 393 p.printNode(n.Type) 394 } else { 395 p.print(_Type) 396 } 397 p.print(_Rparen) 398 399 case *CallExpr: 400 p.print(n.Fun, _Lparen) 401 p.printExprList(n.ArgList) 402 if n.HasDots { 403 p.print(_DotDotDot) 404 } 405 p.print(_Rparen) 406 407 case *Operation: 408 if n.Y == nil { 409 // unary expr 410 p.print(n.Op) 411 // if n.Op == lexical.Range { 412 // p.print(blank) 413 // } 414 p.print(n.X) 415 } else { 416 // binary expr 417 // TODO(gri) eventually take precedence into account 418 // to control possibly missing parentheses 419 p.print(n.X, blank, n.Op, blank, n.Y) 420 } 421 422 case *KeyValueExpr: 423 p.print(n.Key, _Colon, blank, n.Value) 424 425 case *ListExpr: 426 p.printExprList(n.ElemList) 427 428 case *ArrayType: 429 var len interface{} = _DotDotDot 430 if n.Len != nil { 431 len = n.Len 432 } 433 p.print(_Lbrack, len, _Rbrack, n.Elem) 434 435 case *SliceType: 436 p.print(_Lbrack, _Rbrack, n.Elem) 437 438 case *DotsType: 439 p.print(_DotDotDot, n.Elem) 440 441 case *StructType: 442 p.print(_Struct) 443 if len(n.FieldList) > 0 && p.linebreaks { 444 p.print(blank) 445 } 446 p.print(_Lbrace) 447 if len(n.FieldList) > 0 { 448 p.print(newline, indent) 449 p.printFieldList(n.FieldList, n.TagList) 450 p.print(outdent, newline) 451 } 452 p.print(_Rbrace) 453 454 case *FuncType: 455 p.print(_Func) 456 p.printSignature(n) 457 458 case *InterfaceType: 459 p.print(_Interface) 460 if len(n.MethodList) > 0 && p.linebreaks { 461 p.print(blank) 462 } 463 p.print(_Lbrace) 464 if len(n.MethodList) > 0 { 465 p.print(newline, indent) 466 p.printMethodList(n.MethodList) 467 p.print(outdent, newline) 468 } 469 p.print(_Rbrace) 470 471 case *MapType: 472 p.print(_Map, _Lbrack, n.Key, _Rbrack, n.Value) 473 474 case *ChanType: 475 if n.Dir == RecvOnly { 476 p.print(_Arrow) 477 } 478 p.print(_Chan) 479 if n.Dir == SendOnly { 480 p.print(_Arrow) 481 } 482 p.print(blank, n.Elem) 483 484 // statements 485 case *DeclStmt: 486 p.printDecl(n.DeclList) 487 488 case *EmptyStmt: 489 // nothing to print 490 491 case *LabeledStmt: 492 p.print(outdent, n.Label, _Colon, indent, newline, n.Stmt) 493 494 case *ExprStmt: 495 p.print(n.X) 496 497 case *SendStmt: 498 p.print(n.Chan, blank, _Arrow, blank, n.Value) 499 500 case *AssignStmt: 501 p.print(n.Lhs) 502 if n.Rhs == ImplicitOne { 503 // TODO(gri) This is going to break the mayCombine 504 // check once we enable that again. 505 p.print(n.Op, n.Op) // ++ or -- 506 } else { 507 p.print(blank, n.Op, _Assign, blank) 508 p.print(n.Rhs) 509 } 510 511 case *CallStmt: 512 p.print(n.Tok, blank, n.Call) 513 514 case *ReturnStmt: 515 p.print(_Return) 516 if n.Results != nil { 517 p.print(blank, n.Results) 518 } 519 520 case *BranchStmt: 521 p.print(n.Tok) 522 if n.Label != nil { 523 p.print(blank, n.Label) 524 } 525 526 case *BlockStmt: 527 p.printBody(n.Body) 528 529 case *IfStmt: 530 p.print(_If, blank) 531 if n.Init != nil { 532 p.print(n.Init, _Semi, blank) 533 } 534 p.print(n.Cond, blank) 535 p.printBody(n.Then) 536 if n.Else != nil { 537 p.print(blank, _Else, blank, n.Else) 538 } 539 540 case *SwitchStmt: 541 p.print(_Switch, blank) 542 if n.Init != nil { 543 p.print(n.Init, _Semi, blank) 544 } 545 if n.Tag != nil { 546 p.print(n.Tag, blank) 547 } 548 p.printSwitchBody(n.Body) 549 550 case *TypeSwitchGuard: 551 if n.Lhs != nil { 552 p.print(n.Lhs, blank, _Define, blank) 553 } 554 p.print(n.X, _Dot, _Lparen, _Type, _Rparen) 555 556 case *SelectStmt: 557 p.print(_Select, blank) // for now 558 p.printSelectBody(n.Body) 559 560 case *RangeClause: 561 if n.Lhs != nil { 562 tok := _Assign 563 if n.Def { 564 tok = _Define 565 } 566 p.print(n.Lhs, blank, tok, blank) 567 } 568 p.print(_Range, blank, n.X) 569 570 case *ForStmt: 571 p.print(_For, blank) 572 if n.Init == nil && n.Post == nil { 573 if n.Cond != nil { 574 p.print(n.Cond, blank) 575 } 576 } else { 577 if n.Init != nil { 578 p.print(n.Init) 579 // TODO(gri) clean this up 580 if _, ok := n.Init.(*RangeClause); ok { 581 p.print(blank) 582 p.printBody(n.Body) 583 break 584 } 585 } 586 p.print(_Semi, blank) 587 if n.Cond != nil { 588 p.print(n.Cond) 589 } 590 p.print(_Semi, blank) 591 if n.Post != nil { 592 p.print(n.Post, blank) 593 } 594 } 595 p.printBody(n.Body) 596 597 case *ImportDecl: 598 if n.Group == nil { 599 p.print(_Import, blank) 600 } 601 if n.LocalPkgName != nil { 602 p.print(n.LocalPkgName, blank) 603 } 604 p.print(n.Path) 605 606 case *ConstDecl: 607 if n.Group == nil { 608 p.print(_Const, blank) 609 } 610 p.printNameList(n.NameList) 611 if n.Type != nil { 612 p.print(blank, n.Type) 613 } 614 if n.Values != nil { 615 p.print(blank, _Assign, blank, n.Values) 616 } 617 618 case *TypeDecl: 619 if n.Group == nil { 620 p.print(_Type, blank) 621 } 622 p.print(n.Name, blank) 623 if n.Alias { 624 p.print(_Assign, blank) 625 } 626 p.print(n.Type) 627 628 case *VarDecl: 629 if n.Group == nil { 630 p.print(_Var, blank) 631 } 632 p.printNameList(n.NameList) 633 if n.Type != nil { 634 p.print(blank, n.Type) 635 } 636 if n.Values != nil { 637 p.print(blank, _Assign, blank, n.Values) 638 } 639 640 case *FuncDecl: 641 p.print(_Func, blank) 642 if r := n.Recv; r != nil { 643 p.print(_Lparen) 644 if r.Name != nil { 645 p.print(r.Name, blank) 646 } 647 p.printNode(r.Type) 648 p.print(_Rparen, blank) 649 } 650 p.print(n.Name) 651 p.printSignature(n.Type) 652 if n.Body != nil { 653 p.print(blank) 654 p.printBody(n.Body) 655 } 656 657 case *printGroup: 658 p.print(n.Tok, blank, _Lparen) 659 if len(n.Decls) > 0 { 660 p.print(newline, indent) 661 for _, d := range n.Decls { 662 p.printNode(d) 663 p.print(_Semi, newline) 664 } 665 p.print(outdent) 666 } 667 p.print(_Rparen) 668 669 // files 670 case *File: 671 p.print(_Package, blank, n.PkgName) 672 if len(n.DeclList) > 0 { 673 p.print(_Semi, newline, newline) 674 p.printDeclList(n.DeclList) 675 } 676 677 default: 678 panic(fmt.Sprintf("syntax.Iterate: unexpected node type %T", n)) 679 } 680 } 681 682 func (p *printer) printFields(fields []*Field, tags []*BasicLit, i, j int) { 683 if i+1 == j && fields[i].Name == nil { 684 // anonymous field 685 p.printNode(fields[i].Type) 686 } else { 687 for k, f := range fields[i:j] { 688 if k > 0 { 689 p.print(_Comma, blank) 690 } 691 p.printNode(f.Name) 692 } 693 p.print(blank) 694 p.printNode(fields[i].Type) 695 } 696 if i < len(tags) && tags[i] != nil { 697 p.print(blank) 698 p.printNode(tags[i]) 699 } 700 } 701 702 func (p *printer) printFieldList(fields []*Field, tags []*BasicLit) { 703 i0 := 0 704 var typ Expr 705 for i, f := range fields { 706 if f.Name == nil || f.Type != typ { 707 if i0 < i { 708 p.printFields(fields, tags, i0, i) 709 p.print(_Semi, newline) 710 i0 = i 711 } 712 typ = f.Type 713 } 714 } 715 p.printFields(fields, tags, i0, len(fields)) 716 } 717 718 func (p *printer) printMethodList(methods []*Field) { 719 for i, m := range methods { 720 if i > 0 { 721 p.print(_Semi, newline) 722 } 723 if m.Name != nil { 724 p.printNode(m.Name) 725 p.printSignature(m.Type.(*FuncType)) 726 } else { 727 p.printNode(m.Type) 728 } 729 } 730 } 731 732 func (p *printer) printNameList(list []*Name) { 733 for i, x := range list { 734 if i > 0 { 735 p.print(_Comma, blank) 736 } 737 p.printNode(x) 738 } 739 } 740 741 func (p *printer) printExprList(list []Expr) { 742 for i, x := range list { 743 if i > 0 { 744 p.print(_Comma, blank) 745 } 746 p.printNode(x) 747 } 748 } 749 750 func (p *printer) printExprLines(list []Expr) { 751 if len(list) > 0 { 752 p.print(newline, indent) 753 for _, x := range list { 754 p.print(x, _Comma, newline) 755 } 756 p.print(outdent) 757 } 758 } 759 760 func groupFor(d Decl) (token, *Group) { 761 switch d := d.(type) { 762 case *ImportDecl: 763 return _Import, d.Group 764 case *ConstDecl: 765 return _Const, d.Group 766 case *TypeDecl: 767 return _Type, d.Group 768 case *VarDecl: 769 return _Var, d.Group 770 case *FuncDecl: 771 return _Func, nil 772 default: 773 panic("unreachable") 774 } 775 } 776 777 type printGroup struct { 778 node 779 Tok token 780 Decls []Decl 781 } 782 783 func (p *printer) printDecl(list []Decl) { 784 tok, group := groupFor(list[0]) 785 786 if group == nil { 787 if len(list) != 1 { 788 panic("unreachable") 789 } 790 p.printNode(list[0]) 791 return 792 } 793 794 // if _, ok := list[0].(*EmptyDecl); ok { 795 // if len(list) != 1 { 796 // panic("unreachable") 797 // } 798 // // TODO(gri) if there are comments inside the empty 799 // // group, we may need to keep the list non-nil 800 // list = nil 801 // } 802 803 // printGroup is here for consistent comment handling 804 // (this is not yet used) 805 var pg printGroup 806 // *pg.Comments() = *group.Comments() 807 pg.Tok = tok 808 pg.Decls = list 809 p.printNode(&pg) 810 } 811 812 func (p *printer) printDeclList(list []Decl) { 813 i0 := 0 814 var tok token 815 var group *Group 816 for i, x := range list { 817 if s, g := groupFor(x); g == nil || g != group { 818 if i0 < i { 819 p.printDecl(list[i0:i]) 820 p.print(_Semi, newline) 821 // print empty line between different declaration groups, 822 // different kinds of declarations, or between functions 823 if g != group || s != tok || s == _Func { 824 p.print(newline) 825 } 826 i0 = i 827 } 828 tok, group = s, g 829 } 830 } 831 p.printDecl(list[i0:]) 832 } 833 834 func (p *printer) printSignature(sig *FuncType) { 835 p.printParameterList(sig.ParamList) 836 if list := sig.ResultList; list != nil { 837 p.print(blank) 838 if len(list) == 1 && list[0].Name == nil { 839 p.printNode(list[0].Type) 840 } else { 841 p.printParameterList(list) 842 } 843 } 844 } 845 846 func (p *printer) printParameterList(list []*Field) { 847 p.print(_Lparen) 848 if len(list) > 0 { 849 for i, f := range list { 850 if i > 0 { 851 p.print(_Comma, blank) 852 } 853 if f.Name != nil { 854 p.printNode(f.Name) 855 if i+1 < len(list) { 856 f1 := list[i+1] 857 if f1.Name != nil && f1.Type == f.Type { 858 continue // no need to print type 859 } 860 } 861 p.print(blank) 862 } 863 p.printNode(f.Type) 864 } 865 } 866 p.print(_Rparen) 867 } 868 869 func (p *printer) printStmtList(list []Stmt, braces bool) { 870 for i, x := range list { 871 p.print(x, _Semi) 872 if i+1 < len(list) { 873 p.print(newline) 874 } else if braces { 875 // Print an extra semicolon if the last statement is 876 // an empty statement and we are in a braced block 877 // because one semicolon is automatically removed. 878 if _, ok := x.(*EmptyStmt); ok { 879 p.print(x, _Semi) 880 } 881 } 882 } 883 } 884 885 func (p *printer) printBody(list []Stmt) { 886 p.print(_Lbrace) 887 if len(list) > 0 { 888 p.print(newline, indent) 889 p.printStmtList(list, true) 890 p.print(outdent, newline) 891 } 892 p.print(_Rbrace) 893 } 894 895 func (p *printer) printSwitchBody(list []*CaseClause) { 896 p.print(_Lbrace) 897 if len(list) > 0 { 898 p.print(newline) 899 for i, c := range list { 900 p.printCaseClause(c, i+1 == len(list)) 901 p.print(newline) 902 } 903 } 904 p.print(_Rbrace) 905 } 906 907 func (p *printer) printSelectBody(list []*CommClause) { 908 p.print(_Lbrace) 909 if len(list) > 0 { 910 p.print(newline) 911 for i, c := range list { 912 p.printCommClause(c, i+1 == len(list)) 913 p.print(newline) 914 } 915 } 916 p.print(_Rbrace) 917 } 918 919 func (p *printer) printCaseClause(c *CaseClause, braces bool) { 920 if c.Cases != nil { 921 p.print(_Case, blank, c.Cases) 922 } else { 923 p.print(_Default) 924 } 925 p.print(_Colon) 926 if len(c.Body) > 0 { 927 p.print(newline, indent) 928 p.printStmtList(c.Body, braces) 929 p.print(outdent) 930 } 931 } 932 933 func (p *printer) printCommClause(c *CommClause, braces bool) { 934 if c.Comm != nil { 935 p.print(_Case, blank) 936 p.print(c.Comm) 937 } else { 938 p.print(_Default) 939 } 940 p.print(_Colon) 941 if len(c.Body) > 0 { 942 p.print(newline, indent) 943 p.printStmtList(c.Body, braces) 944 p.print(outdent) 945 } 946 }