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