Source file src/cmd/compile/internal/syntax/printer.go

     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 (p *printer) addWhitespace(kind ctrlSymbol, text string) {
   142  	p.pending = append(p.pending, whitespace{p.lastTok, kind /*text*/})
   143  	switch kind {
   144  	case semi:
   145  		p.lastTok = _Semi
   146  	case newline:
   147  		p.lastTok = 0
   148  		// TODO(gri) do we need to handle /*-style comments containing newlines here?
   149  	}
   150  }
   151  
   152  func (p *printer) flush(next token) {
   153  	// eliminate semis and redundant whitespace
   154  	sawNewline := next == _EOF
   155  	sawParen := next == _Rparen || next == _Rbrace
   156  	for i := len(p.pending) - 1; i >= 0; i-- {
   157  		switch p.pending[i].kind {
   158  		case semi:
   159  			k := semi
   160  			if sawParen {
   161  				sawParen = false
   162  				k = none // eliminate semi
   163  			} else if sawNewline && impliesSemi(p.pending[i].last) {
   164  				sawNewline = false
   165  				k = none // eliminate semi
   166  			}
   167  			p.pending[i].kind = k
   168  		case newline:
   169  			sawNewline = true
   170  		case blank, indent, outdent:
   171  			// nothing to do
   172  		// case comment:
   173  		// 	// A multi-line comment acts like a newline; and a ""
   174  		// 	// comment implies by definition at least one newline.
   175  		// 	if text := p.pending[i].text; strings.HasPrefix(text, "/*") && strings.ContainsRune(text, '\n') {
   176  		// 		sawNewline = true
   177  		// 	}
   178  		// case eolComment:
   179  		// 	// TODO(gri) act depending on sawNewline
   180  		default:
   181  			panic("unreachable")
   182  		}
   183  	}
   184  
   185  	// print pending
   186  	prev := none
   187  	for i := range p.pending {
   188  		switch p.pending[i].kind {
   189  		case none:
   190  			// nothing to do
   191  		case semi:
   192  			p.writeString(";")
   193  			p.nlcount = 0
   194  			prev = semi
   195  		case blank:
   196  			if prev != blank {
   197  				// at most one blank
   198  				p.writeBytes(blankByte)
   199  				p.nlcount = 0
   200  				prev = blank
   201  			}
   202  		case newline:
   203  			const maxEmptyLines = 1
   204  			if p.nlcount <= maxEmptyLines {
   205  				p.write(newlineByte)
   206  				p.nlcount++
   207  				prev = newline
   208  			}
   209  		case indent:
   210  			p.indent++
   211  		case outdent:
   212  			p.indent--
   213  			if p.indent < 0 {
   214  				panic("negative indentation")
   215  			}
   216  		// case comment:
   217  		// 	if text := p.pending[i].text; text != "" {
   218  		// 		p.writeString(text)
   219  		// 		p.nlcount = 0
   220  		// 		prev = comment
   221  		// 	}
   222  		// 	// TODO(gri) should check that line comments are always followed by newline
   223  		default:
   224  			panic("unreachable")
   225  		}
   226  	}
   227  
   228  	p.pending = p.pending[:0] // re-use underlying array
   229  }
   230  
   231  func mayCombine(prev token, next byte) (b bool) {
   232  	return // for now
   233  	// switch prev {
   234  	// case lexical.Int:
   235  	// 	b = next == '.' // 1.
   236  	// case lexical.Add:
   237  	// 	b = next == '+' // ++
   238  	// case lexical.Sub:
   239  	// 	b = next == '-' // --
   240  	// case lexical.Quo:
   241  	// 	b = next == '*' // /*
   242  	// case lexical.Lss:
   243  	// 	b = next == '-' || next == '<' // <- or <<
   244  	// case lexical.And:
   245  	// 	b = next == '&' || next == '^' // && or &^
   246  	// }
   247  	// return
   248  }
   249  
   250  func (p *printer) print(args ...interface{}) {
   251  	for i := 0; i < len(args); i++ {
   252  		switch x := args[i].(type) {
   253  		case nil:
   254  			// we should not reach here but don't crash
   255  
   256  		case Node:
   257  			p.printNode(x)
   258  
   259  		case token:
   260  			// _Name implies an immediately following string
   261  			// argument which is the actual value to print.
   262  			var s string
   263  			if x == _Name {
   264  				i++
   265  				if i >= len(args) {
   266  					panic("missing string argument after _Name")
   267  				}
   268  				s = args[i].(string)
   269  			} else {
   270  				s = x.String()
   271  			}
   272  
   273  			// TODO(gri) This check seems at the wrong place since it doesn't
   274  			//           take into account pending white space.
   275  			if mayCombine(p.lastTok, s[0]) {
   276  				panic("adjacent tokens combine without whitespace")
   277  			}
   278  
   279  			if x == _Semi {
   280  				// delay printing of semi
   281  				p.addWhitespace(semi, "")
   282  			} else {
   283  				p.flush(x)
   284  				p.writeString(s)
   285  				p.nlcount = 0
   286  				p.lastTok = x
   287  			}
   288  
   289  		case Operator:
   290  			if x != 0 {
   291  				p.flush(_Operator)
   292  				p.writeString(x.String())
   293  			}
   294  
   295  		case ctrlSymbol:
   296  			switch x {
   297  			case none, semi /*, comment*/ :
   298  				panic("unreachable")
   299  			case newline:
   300  				// TODO(gri) need to handle mandatory newlines after a //-style comment
   301  				if !p.linebreaks {
   302  					x = blank
   303  				}
   304  			}
   305  			p.addWhitespace(x, "")
   306  
   307  		// case *Comment: // comments are not Nodes
   308  		// 	p.addWhitespace(comment, x.Text)
   309  
   310  		default:
   311  			panic(fmt.Sprintf("unexpected argument %v (%T)", x, x))
   312  		}
   313  	}
   314  }
   315  
   316  func (p *printer) printNode(n Node) {
   317  	// ncom := *n.Comments()
   318  	// if ncom != nil {
   319  	// 	// TODO(gri) in general we cannot make assumptions about whether
   320  	// 	// a comment is a /*- or a //-style comment since the syntax
   321  	// 	// tree may have been manipulated. Need to make sure the correct
   322  	// 	// whitespace is emitted.
   323  	// 	for _, c := range ncom.Alone {
   324  	// 		p.print(c, newline)
   325  	// 	}
   326  	// 	for _, c := range ncom.Before {
   327  	// 		if c.Text == "" || lineComment(c.Text) {
   328  	// 			panic("unexpected empty line or //-style 'before' comment")
   329  	// 		}
   330  	// 		p.print(c, blank)
   331  	// 	}
   332  	// }
   333  
   334  	p.printRawNode(n)
   335  
   336  	// if ncom != nil && len(ncom.After) > 0 {
   337  	// 	for i, c := range ncom.After {
   338  	// 		if i+1 < len(ncom.After) {
   339  	// 			if c.Text == "" || lineComment(c.Text) {
   340  	// 				panic("unexpected empty line or //-style non-final 'after' comment")
   341  	// 			}
   342  	// 		}
   343  	// 		p.print(blank, c)
   344  	// 	}
   345  	// 	//p.print(newline)
   346  	// }
   347  }
   348  
   349  func (p *printer) printRawNode(n Node) {
   350  	switch n := n.(type) {
   351  	case nil:
   352  		// we should not reach here but don't crash
   353  
   354  	// expressions and types
   355  	case *BadExpr:
   356  		p.print(_Name, "<bad expr>")
   357  
   358  	case *Name:
   359  		p.print(_Name, n.Value) // _Name requires actual value following immediately
   360  
   361  	case *BasicLit:
   362  		p.print(_Name, n.Value) // _Name requires actual value following immediately
   363  
   364  	case *FuncLit:
   365  		p.print(n.Type, blank)
   366  		if n.Body != nil {
   367  			if p.form == ShortForm {
   368  				p.print(_Lbrace)
   369  				if len(n.Body.List) > 0 {
   370  					p.print(_Name, "…")
   371  				}
   372  				p.print(_Rbrace)
   373  			} else {
   374  				p.print(n.Body)
   375  			}
   376  		}
   377  
   378  	case *CompositeLit:
   379  		if n.Type != nil {
   380  			p.print(n.Type)
   381  		}
   382  		p.print(_Lbrace)
   383  		if p.form == ShortForm {
   384  			if len(n.ElemList) > 0 {
   385  				p.print(_Name, "…")
   386  			}
   387  		} else {
   388  			if n.NKeys > 0 && n.NKeys == len(n.ElemList) {
   389  				p.printExprLines(n.ElemList)
   390  			} else {
   391  				p.printExprList(n.ElemList)
   392  			}
   393  		}
   394  		p.print(_Rbrace)
   395  
   396  	case *ParenExpr:
   397  		p.print(_Lparen, n.X, _Rparen)
   398  
   399  	case *SelectorExpr:
   400  		p.print(n.X, _Dot, n.Sel)
   401  
   402  	case *IndexExpr:
   403  		p.print(n.X, _Lbrack, n.Index, _Rbrack)
   404  
   405  	case *SliceExpr:
   406  		p.print(n.X, _Lbrack)
   407  		if i := n.Index[0]; i != nil {
   408  			p.printNode(i)
   409  		}
   410  		p.print(_Colon)
   411  		if j := n.Index[1]; j != nil {
   412  			p.printNode(j)
   413  		}
   414  		if k := n.Index[2]; k != nil {
   415  			p.print(_Colon, k)
   416  		}
   417  		p.print(_Rbrack)
   418  
   419  	case *AssertExpr:
   420  		p.print(n.X, _Dot, _Lparen, n.Type, _Rparen)
   421  
   422  	case *TypeSwitchGuard:
   423  		if n.Lhs != nil {
   424  			p.print(n.Lhs, blank, _Define, blank)
   425  		}
   426  		p.print(n.X, _Dot, _Lparen, _Type, _Rparen)
   427  
   428  	case *CallExpr:
   429  		p.print(n.Fun, _Lparen)
   430  		p.printExprList(n.ArgList)
   431  		if n.HasDots {
   432  			p.print(_DotDotDot)
   433  		}
   434  		p.print(_Rparen)
   435  
   436  	case *Operation:
   437  		if n.Y == nil {
   438  			// unary expr
   439  			p.print(n.Op)
   440  			// if n.Op == lexical.Range {
   441  			// 	p.print(blank)
   442  			// }
   443  			p.print(n.X)
   444  		} else {
   445  			// binary expr
   446  			// TODO(gri) eventually take precedence into account
   447  			// to control possibly missing parentheses
   448  			p.print(n.X, blank, n.Op, blank, n.Y)
   449  		}
   450  
   451  	case *KeyValueExpr:
   452  		p.print(n.Key, _Colon, blank, n.Value)
   453  
   454  	case *ListExpr:
   455  		p.printExprList(n.ElemList)
   456  
   457  	case *ArrayType:
   458  		var len interface{} = _DotDotDot
   459  		if n.Len != nil {
   460  			len = n.Len
   461  		}
   462  		p.print(_Lbrack, len, _Rbrack, n.Elem)
   463  
   464  	case *SliceType:
   465  		p.print(_Lbrack, _Rbrack, n.Elem)
   466  
   467  	case *DotsType:
   468  		p.print(_DotDotDot, n.Elem)
   469  
   470  	case *StructType:
   471  		p.print(_Struct)
   472  		if len(n.FieldList) > 0 && p.linebreaks {
   473  			p.print(blank)
   474  		}
   475  		p.print(_Lbrace)
   476  		if len(n.FieldList) > 0 {
   477  			if p.linebreaks {
   478  				p.print(newline, indent)
   479  				p.printFieldList(n.FieldList, n.TagList, _Semi)
   480  				p.print(outdent, newline)
   481  			} else {
   482  				p.printFieldList(n.FieldList, n.TagList, _Semi)
   483  			}
   484  		}
   485  		p.print(_Rbrace)
   486  
   487  	case *FuncType:
   488  		p.print(_Func)
   489  		p.printSignature(n)
   490  
   491  	case *InterfaceType:
   492  		p.print(_Interface)
   493  		if p.linebreaks && len(n.MethodList) > 1 {
   494  			p.print(blank)
   495  			p.print(_Lbrace)
   496  			p.print(newline, indent)
   497  			p.printMethodList(n.MethodList)
   498  			p.print(outdent, newline)
   499  		} else {
   500  			p.print(_Lbrace)
   501  			p.printMethodList(n.MethodList)
   502  		}
   503  		p.print(_Rbrace)
   504  
   505  	case *MapType:
   506  		p.print(_Map, _Lbrack, n.Key, _Rbrack, n.Value)
   507  
   508  	case *ChanType:
   509  		if n.Dir == RecvOnly {
   510  			p.print(_Arrow)
   511  		}
   512  		p.print(_Chan)
   513  		if n.Dir == SendOnly {
   514  			p.print(_Arrow)
   515  		}
   516  		p.print(blank)
   517  		if e, _ := n.Elem.(*ChanType); n.Dir == 0 && e != nil && e.Dir == RecvOnly {
   518  			// don't print chan (<-chan T) as chan <-chan T
   519  			p.print(_Lparen)
   520  			p.print(n.Elem)
   521  			p.print(_Rparen)
   522  		} else {
   523  			p.print(n.Elem)
   524  		}
   525  
   526  	// statements
   527  	case *DeclStmt:
   528  		p.printDecl(n.DeclList)
   529  
   530  	case *EmptyStmt:
   531  		// nothing to print
   532  
   533  	case *LabeledStmt:
   534  		p.print(outdent, n.Label, _Colon, indent, newline, n.Stmt)
   535  
   536  	case *ExprStmt:
   537  		p.print(n.X)
   538  
   539  	case *SendStmt:
   540  		p.print(n.Chan, blank, _Arrow, blank, n.Value)
   541  
   542  	case *AssignStmt:
   543  		p.print(n.Lhs)
   544  		if n.Rhs == nil {
   545  			// TODO(gri) This is going to break the mayCombine
   546  			//           check once we enable that again.
   547  			p.print(n.Op, n.Op) // ++ or --
   548  		} else {
   549  			p.print(blank, n.Op, _Assign, blank)
   550  			p.print(n.Rhs)
   551  		}
   552  
   553  	case *CallStmt:
   554  		p.print(n.Tok, blank, n.Call)
   555  
   556  	case *ReturnStmt:
   557  		p.print(_Return)
   558  		if n.Results != nil {
   559  			p.print(blank, n.Results)
   560  		}
   561  
   562  	case *BranchStmt:
   563  		p.print(n.Tok)
   564  		if n.Label != nil {
   565  			p.print(blank, n.Label)
   566  		}
   567  
   568  	case *BlockStmt:
   569  		p.print(_Lbrace)
   570  		if len(n.List) > 0 {
   571  			p.print(newline, indent)
   572  			p.printStmtList(n.List, true)
   573  			p.print(outdent, newline)
   574  		}
   575  		p.print(_Rbrace)
   576  
   577  	case *IfStmt:
   578  		p.print(_If, blank)
   579  		if n.Init != nil {
   580  			p.print(n.Init, _Semi, blank)
   581  		}
   582  		p.print(n.Cond, blank, n.Then)
   583  		if n.Else != nil {
   584  			p.print(blank, _Else, blank, n.Else)
   585  		}
   586  
   587  	case *SwitchStmt:
   588  		p.print(_Switch, blank)
   589  		if n.Init != nil {
   590  			p.print(n.Init, _Semi, blank)
   591  		}
   592  		if n.Tag != nil {
   593  			p.print(n.Tag, blank)
   594  		}
   595  		p.printSwitchBody(n.Body)
   596  
   597  	case *SelectStmt:
   598  		p.print(_Select, blank) // for now
   599  		p.printSelectBody(n.Body)
   600  
   601  	case *RangeClause:
   602  		if n.Lhs != nil {
   603  			tok := _Assign
   604  			if n.Def {
   605  				tok = _Define
   606  			}
   607  			p.print(n.Lhs, blank, tok, blank)
   608  		}
   609  		p.print(_Range, blank, n.X)
   610  
   611  	case *ForStmt:
   612  		p.print(_For, blank)
   613  		if n.Init == nil && n.Post == nil {
   614  			if n.Cond != nil {
   615  				p.print(n.Cond, blank)
   616  			}
   617  		} else {
   618  			if n.Init != nil {
   619  				p.print(n.Init)
   620  				// TODO(gri) clean this up
   621  				if _, ok := n.Init.(*RangeClause); ok {
   622  					p.print(blank, n.Body)
   623  					break
   624  				}
   625  			}
   626  			p.print(_Semi, blank)
   627  			if n.Cond != nil {
   628  				p.print(n.Cond)
   629  			}
   630  			p.print(_Semi, blank)
   631  			if n.Post != nil {
   632  				p.print(n.Post, blank)
   633  			}
   634  		}
   635  		p.print(n.Body)
   636  
   637  	case *ImportDecl:
   638  		if n.Group == nil {
   639  			p.print(_Import, blank)
   640  		}
   641  		if n.LocalPkgName != nil {
   642  			p.print(n.LocalPkgName, blank)
   643  		}
   644  		p.print(n.Path)
   645  
   646  	case *ConstDecl:
   647  		if n.Group == nil {
   648  			p.print(_Const, blank)
   649  		}
   650  		p.printNameList(n.NameList)
   651  		if n.Type != nil {
   652  			p.print(blank, n.Type)
   653  		}
   654  		if n.Values != nil {
   655  			p.print(blank, _Assign, blank, n.Values)
   656  		}
   657  
   658  	case *TypeDecl:
   659  		if n.Group == nil {
   660  			p.print(_Type, blank)
   661  		}
   662  		p.print(n.Name)
   663  		if n.TParamList != nil {
   664  			p.printParameterList(n.TParamList, _Type)
   665  		}
   666  		p.print(blank)
   667  		if n.Alias {
   668  			p.print(_Assign, blank)
   669  		}
   670  		p.print(n.Type)
   671  
   672  	case *VarDecl:
   673  		if n.Group == nil {
   674  			p.print(_Var, blank)
   675  		}
   676  		p.printNameList(n.NameList)
   677  		if n.Type != nil {
   678  			p.print(blank, n.Type)
   679  		}
   680  		if n.Values != nil {
   681  			p.print(blank, _Assign, blank, n.Values)
   682  		}
   683  
   684  	case *FuncDecl:
   685  		p.print(_Func, blank)
   686  		if r := n.Recv; r != nil {
   687  			p.print(_Lparen)
   688  			if r.Name != nil {
   689  				p.print(r.Name, blank)
   690  			}
   691  			p.printNode(r.Type)
   692  			p.print(_Rparen, blank)
   693  		}
   694  		p.print(n.Name)
   695  		if n.TParamList != nil {
   696  			p.printParameterList(n.TParamList, _Func)
   697  		}
   698  		p.printSignature(n.Type)
   699  		if n.Body != nil {
   700  			p.print(blank, n.Body)
   701  		}
   702  
   703  	case *printGroup:
   704  		p.print(n.Tok, blank, _Lparen)
   705  		if len(n.Decls) > 0 {
   706  			p.print(newline, indent)
   707  			for _, d := range n.Decls {
   708  				p.printNode(d)
   709  				p.print(_Semi, newline)
   710  			}
   711  			p.print(outdent)
   712  		}
   713  		p.print(_Rparen)
   714  
   715  	// files
   716  	case *File:
   717  		p.print(_Package, blank, n.PkgName)
   718  		if len(n.DeclList) > 0 {
   719  			p.print(_Semi, newline, newline)
   720  			p.printDeclList(n.DeclList)
   721  		}
   722  
   723  	default:
   724  		panic(fmt.Sprintf("syntax.Iterate: unexpected node type %T", n))
   725  	}
   726  }
   727  
   728  func (p *printer) printFields(fields []*Field, tags []*BasicLit, i, j int) {
   729  	if i+1 == j && fields[i].Name == nil {
   730  		// anonymous field
   731  		p.printNode(fields[i].Type)
   732  	} else {
   733  		for k, f := range fields[i:j] {
   734  			if k > 0 {
   735  				p.print(_Comma, blank)
   736  			}
   737  			p.printNode(f.Name)
   738  		}
   739  		p.print(blank)
   740  		p.printNode(fields[i].Type)
   741  	}
   742  	if i < len(tags) && tags[i] != nil {
   743  		p.print(blank)
   744  		p.printNode(tags[i])
   745  	}
   746  }
   747  
   748  func (p *printer) printFieldList(fields []*Field, tags []*BasicLit, sep token) {
   749  	i0 := 0
   750  	var typ Expr
   751  	for i, f := range fields {
   752  		if f.Name == nil || f.Type != typ {
   753  			if i0 < i {
   754  				p.printFields(fields, tags, i0, i)
   755  				p.print(sep, newline)
   756  				i0 = i
   757  			}
   758  			typ = f.Type
   759  		}
   760  	}
   761  	p.printFields(fields, tags, i0, len(fields))
   762  }
   763  
   764  func (p *printer) printMethodList(methods []*Field) {
   765  	for i, m := range methods {
   766  		if i > 0 {
   767  			p.print(_Semi, newline)
   768  		}
   769  		if m.Name != nil {
   770  			p.printNode(m.Name)
   771  			p.printSignature(m.Type.(*FuncType))
   772  		} else {
   773  			p.printNode(m.Type)
   774  		}
   775  	}
   776  }
   777  
   778  func (p *printer) printNameList(list []*Name) {
   779  	for i, x := range list {
   780  		if i > 0 {
   781  			p.print(_Comma, blank)
   782  		}
   783  		p.printNode(x)
   784  	}
   785  }
   786  
   787  func (p *printer) printExprList(list []Expr) {
   788  	for i, x := range list {
   789  		if i > 0 {
   790  			p.print(_Comma, blank)
   791  		}
   792  		p.printNode(x)
   793  	}
   794  }
   795  
   796  func (p *printer) printExprLines(list []Expr) {
   797  	if len(list) > 0 {
   798  		p.print(newline, indent)
   799  		for _, x := range list {
   800  			p.print(x, _Comma, newline)
   801  		}
   802  		p.print(outdent)
   803  	}
   804  }
   805  
   806  func groupFor(d Decl) (token, *Group) {
   807  	switch d := d.(type) {
   808  	case *ImportDecl:
   809  		return _Import, d.Group
   810  	case *ConstDecl:
   811  		return _Const, d.Group
   812  	case *TypeDecl:
   813  		return _Type, d.Group
   814  	case *VarDecl:
   815  		return _Var, d.Group
   816  	case *FuncDecl:
   817  		return _Func, nil
   818  	default:
   819  		panic("unreachable")
   820  	}
   821  }
   822  
   823  type printGroup struct {
   824  	node
   825  	Tok   token
   826  	Decls []Decl
   827  }
   828  
   829  func (p *printer) printDecl(list []Decl) {
   830  	tok, group := groupFor(list[0])
   831  
   832  	if group == nil {
   833  		if len(list) != 1 {
   834  			panic("unreachable")
   835  		}
   836  		p.printNode(list[0])
   837  		return
   838  	}
   839  
   840  	// if _, ok := list[0].(*EmptyDecl); ok {
   841  	// 	if len(list) != 1 {
   842  	// 		panic("unreachable")
   843  	// 	}
   844  	// 	// TODO(gri) if there are comments inside the empty
   845  	// 	// group, we may need to keep the list non-nil
   846  	// 	list = nil
   847  	// }
   848  
   849  	// printGroup is here for consistent comment handling
   850  	// (this is not yet used)
   851  	var pg printGroup
   852  	// *pg.Comments() = *group.Comments()
   853  	pg.Tok = tok
   854  	pg.Decls = list
   855  	p.printNode(&pg)
   856  }
   857  
   858  func (p *printer) printDeclList(list []Decl) {
   859  	i0 := 0
   860  	var tok token
   861  	var group *Group
   862  	for i, x := range list {
   863  		if s, g := groupFor(x); g == nil || g != group {
   864  			if i0 < i {
   865  				p.printDecl(list[i0:i])
   866  				p.print(_Semi, newline)
   867  				// print empty line between different declaration groups,
   868  				// different kinds of declarations, or between functions
   869  				if g != group || s != tok || s == _Func {
   870  					p.print(newline)
   871  				}
   872  				i0 = i
   873  			}
   874  			tok, group = s, g
   875  		}
   876  	}
   877  	p.printDecl(list[i0:])
   878  }
   879  
   880  func (p *printer) printSignature(sig *FuncType) {
   881  	p.printParameterList(sig.ParamList, 0)
   882  	if list := sig.ResultList; list != nil {
   883  		p.print(blank)
   884  		if len(list) == 1 && list[0].Name == nil {
   885  			p.printNode(list[0].Type)
   886  		} else {
   887  			p.printParameterList(list, 0)
   888  		}
   889  	}
   890  }
   891  
   892  // If tok != 0 print a type parameter list: tok == _Type means
   893  // a type parameter list for a type, tok == _Func means a type
   894  // parameter list for a func.
   895  func (p *printer) printParameterList(list []*Field, tok token) {
   896  	open, close := _Lparen, _Rparen
   897  	if tok != 0 {
   898  		open, close = _Lbrack, _Rbrack
   899  	}
   900  	p.print(open)
   901  	for i, f := range list {
   902  		if i > 0 {
   903  			p.print(_Comma, blank)
   904  		}
   905  		if f.Name != nil {
   906  			p.printNode(f.Name)
   907  			if i+1 < len(list) {
   908  				f1 := list[i+1]
   909  				if f1.Name != nil && f1.Type == f.Type {
   910  					continue // no need to print type
   911  				}
   912  			}
   913  			p.print(blank)
   914  		}
   915  		p.printNode(f.Type)
   916  	}
   917  	// A type parameter list [P T] where the name P and the type expression T syntactically
   918  	// combine to another valid (value) expression requires a trailing comma, as in [P *T,]
   919  	// (or an enclosing interface as in [P interface(*T)]), so that the type parameter list
   920  	// is not parsed as an array length [P*T].
   921  	if tok == _Type && len(list) == 1 && combinesWithName(list[0].Type) {
   922  		p.print(_Comma)
   923  	}
   924  	p.print(close)
   925  }
   926  
   927  // combinesWithName reports whether a name followed by the expression x
   928  // syntactically combines to another valid (value) expression. For instance
   929  // using *T for x, "name *T" syntactically appears as the expression x*T.
   930  // On the other hand, using  P|Q or *P|~Q for x, "name P|Q" or "name *P|~Q"
   931  // cannot be combined into a valid (value) expression.
   932  func combinesWithName(x Expr) bool {
   933  	switch x := x.(type) {
   934  	case *Operation:
   935  		if x.Y == nil {
   936  			// name *x.X combines to name*x.X if x.X is not a type element
   937  			return x.Op == Mul && !isTypeElem(x.X)
   938  		}
   939  		// binary expressions
   940  		return combinesWithName(x.X) && !isTypeElem(x.Y)
   941  	case *ParenExpr:
   942  		// Note that the parser strips parentheses in these cases
   943  		// (see extractName, parser.typeOrNil) unless keep_parens
   944  		// is set, so we should never reach here.
   945  		// Do the right thing (rather than panic) for testing and
   946  		// in case we change parser behavior.
   947  		// See also go.dev/issues/69206.
   948  		return !isTypeElem(x.X)
   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  }
  1021  

View as plain text