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 ...any) {
   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 any = _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  		if len(n.DeclList) > 0 {
   529  			p.printDecl(n.DeclList)
   530  		}
   531  
   532  	case *EmptyStmt:
   533  		// nothing to print
   534  
   535  	case *LabeledStmt:
   536  		p.print(outdent, n.Label, _Colon, indent, newline, n.Stmt)
   537  
   538  	case *ExprStmt:
   539  		p.print(n.X)
   540  
   541  	case *SendStmt:
   542  		p.print(n.Chan, blank, _Arrow, blank, n.Value)
   543  
   544  	case *AssignStmt:
   545  		p.print(n.Lhs)
   546  		if n.Rhs == nil {
   547  			// TODO(gri) This is going to break the mayCombine
   548  			//           check once we enable that again.
   549  			p.print(n.Op, n.Op) // ++ or --
   550  		} else {
   551  			p.print(blank, n.Op, _Assign, blank)
   552  			p.print(n.Rhs)
   553  		}
   554  
   555  	case *CallStmt:
   556  		p.print(n.Tok, blank, n.Call)
   557  
   558  	case *ReturnStmt:
   559  		p.print(_Return)
   560  		if n.Results != nil {
   561  			p.print(blank, n.Results)
   562  		}
   563  
   564  	case *BranchStmt:
   565  		p.print(n.Tok)
   566  		if n.Label != nil {
   567  			p.print(blank, n.Label)
   568  		}
   569  
   570  	case *BlockStmt:
   571  		p.print(_Lbrace)
   572  		if len(n.List) > 0 {
   573  			p.print(newline, indent)
   574  			p.printStmtList(n.List, true)
   575  			p.print(outdent, newline)
   576  		}
   577  		p.print(_Rbrace)
   578  
   579  	case *IfStmt:
   580  		p.print(_If, blank)
   581  		if n.Init != nil {
   582  			p.print(n.Init, _Semi, blank)
   583  		}
   584  		p.print(n.Cond, blank, n.Then)
   585  		if n.Else != nil {
   586  			p.print(blank, _Else, blank, n.Else)
   587  		}
   588  
   589  	case *SwitchStmt:
   590  		p.print(_Switch, blank)
   591  		if n.Init != nil {
   592  			p.print(n.Init, _Semi, blank)
   593  		}
   594  		if n.Tag != nil {
   595  			p.print(n.Tag, blank)
   596  		}
   597  		p.printSwitchBody(n.Body)
   598  
   599  	case *SelectStmt:
   600  		p.print(_Select, blank) // for now
   601  		p.printSelectBody(n.Body)
   602  
   603  	case *RangeClause:
   604  		if n.Lhs != nil {
   605  			tok := _Assign
   606  			if n.Def {
   607  				tok = _Define
   608  			}
   609  			p.print(n.Lhs, blank, tok, blank)
   610  		}
   611  		p.print(_Range, blank, n.X)
   612  
   613  	case *ForStmt:
   614  		p.print(_For, blank)
   615  		if n.Init == nil && n.Post == nil {
   616  			if n.Cond != nil {
   617  				p.print(n.Cond, blank)
   618  			}
   619  		} else {
   620  			if n.Init != nil {
   621  				p.print(n.Init)
   622  				// TODO(gri) clean this up
   623  				if _, ok := n.Init.(*RangeClause); ok {
   624  					p.print(blank, n.Body)
   625  					break
   626  				}
   627  			}
   628  			p.print(_Semi, blank)
   629  			if n.Cond != nil {
   630  				p.print(n.Cond)
   631  			}
   632  			p.print(_Semi, blank)
   633  			if n.Post != nil {
   634  				p.print(n.Post, blank)
   635  			}
   636  		}
   637  		p.print(n.Body)
   638  
   639  	case *ImportDecl:
   640  		if n.Group == nil {
   641  			p.print(_Import, blank)
   642  		}
   643  		if n.LocalPkgName != nil {
   644  			p.print(n.LocalPkgName, blank)
   645  		}
   646  		p.print(n.Path)
   647  
   648  	case *ConstDecl:
   649  		if n.Group == nil {
   650  			p.print(_Const, blank)
   651  		}
   652  		p.printNameList(n.NameList)
   653  		if n.Type != nil {
   654  			p.print(blank, n.Type)
   655  		}
   656  		if n.Values != nil {
   657  			p.print(blank, _Assign, blank, n.Values)
   658  		}
   659  
   660  	case *TypeDecl:
   661  		if n.Group == nil {
   662  			p.print(_Type, blank)
   663  		}
   664  		p.print(n.Name)
   665  		if n.TParamList != nil {
   666  			p.printParameterList(n.TParamList, _Type)
   667  		}
   668  		p.print(blank)
   669  		if n.Alias {
   670  			p.print(_Assign, blank)
   671  		}
   672  		p.print(n.Type)
   673  
   674  	case *VarDecl:
   675  		if n.Group == nil {
   676  			p.print(_Var, blank)
   677  		}
   678  		p.printNameList(n.NameList)
   679  		if n.Type != nil {
   680  			p.print(blank, n.Type)
   681  		}
   682  		if n.Values != nil {
   683  			p.print(blank, _Assign, blank, n.Values)
   684  		}
   685  
   686  	case *FuncDecl:
   687  		p.print(_Func, blank)
   688  		if r := n.Recv; r != nil {
   689  			p.print(_Lparen)
   690  			if r.Name != nil {
   691  				p.print(r.Name, blank)
   692  			}
   693  			p.printNode(r.Type)
   694  			p.print(_Rparen, blank)
   695  		}
   696  		p.print(n.Name)
   697  		if n.TParamList != nil {
   698  			p.printParameterList(n.TParamList, _Func)
   699  		}
   700  		p.printSignature(n.Type)
   701  		if n.Body != nil {
   702  			p.print(blank, n.Body)
   703  		}
   704  
   705  	case *printGroup:
   706  		p.print(n.Tok, blank, _Lparen)
   707  		if len(n.Decls) > 0 {
   708  			p.print(newline, indent)
   709  			for _, d := range n.Decls {
   710  				p.printNode(d)
   711  				p.print(_Semi, newline)
   712  			}
   713  			p.print(outdent)
   714  		}
   715  		p.print(_Rparen)
   716  
   717  	// files
   718  	case *File:
   719  		p.print(_Package, blank, n.PkgName)
   720  		if len(n.DeclList) > 0 {
   721  			p.print(_Semi, newline, newline)
   722  			p.printDeclList(n.DeclList)
   723  		}
   724  
   725  	default:
   726  		panic(fmt.Sprintf("syntax.Iterate: unexpected node type %T", n))
   727  	}
   728  }
   729  
   730  func (p *printer) printFields(fields []*Field, tags []*BasicLit, i, j int) {
   731  	if i+1 == j && fields[i].Name == nil {
   732  		// anonymous field
   733  		p.printNode(fields[i].Type)
   734  	} else {
   735  		for k, f := range fields[i:j] {
   736  			if k > 0 {
   737  				p.print(_Comma, blank)
   738  			}
   739  			p.printNode(f.Name)
   740  		}
   741  		p.print(blank)
   742  		p.printNode(fields[i].Type)
   743  	}
   744  	if i < len(tags) && tags[i] != nil {
   745  		p.print(blank)
   746  		p.printNode(tags[i])
   747  	}
   748  }
   749  
   750  func (p *printer) printFieldList(fields []*Field, tags []*BasicLit, sep token) {
   751  	i0 := 0
   752  	var typ Expr
   753  	for i, f := range fields {
   754  		if f.Name == nil || f.Type != typ {
   755  			if i0 < i {
   756  				p.printFields(fields, tags, i0, i)
   757  				p.print(sep, newline)
   758  				i0 = i
   759  			}
   760  			typ = f.Type
   761  		}
   762  	}
   763  	p.printFields(fields, tags, i0, len(fields))
   764  }
   765  
   766  func (p *printer) printMethodList(methods []*Field) {
   767  	for i, m := range methods {
   768  		if i > 0 {
   769  			p.print(_Semi, newline)
   770  		}
   771  		if m.Name != nil {
   772  			p.printNode(m.Name)
   773  			p.printSignature(m.Type.(*FuncType))
   774  		} else {
   775  			p.printNode(m.Type)
   776  		}
   777  	}
   778  }
   779  
   780  func (p *printer) printNameList(list []*Name) {
   781  	for i, x := range list {
   782  		if i > 0 {
   783  			p.print(_Comma, blank)
   784  		}
   785  		p.printNode(x)
   786  	}
   787  }
   788  
   789  func (p *printer) printExprList(list []Expr) {
   790  	for i, x := range list {
   791  		if i > 0 {
   792  			p.print(_Comma, blank)
   793  		}
   794  		p.printNode(x)
   795  	}
   796  }
   797  
   798  func (p *printer) printExprLines(list []Expr) {
   799  	if len(list) > 0 {
   800  		p.print(newline, indent)
   801  		for _, x := range list {
   802  			p.print(x, _Comma, newline)
   803  		}
   804  		p.print(outdent)
   805  	}
   806  }
   807  
   808  func groupFor(d Decl) (token, *Group) {
   809  	switch d := d.(type) {
   810  	case *ImportDecl:
   811  		return _Import, d.Group
   812  	case *ConstDecl:
   813  		return _Const, d.Group
   814  	case *TypeDecl:
   815  		return _Type, d.Group
   816  	case *VarDecl:
   817  		return _Var, d.Group
   818  	case *FuncDecl:
   819  		return _Func, nil
   820  	default:
   821  		panic("unreachable")
   822  	}
   823  }
   824  
   825  type printGroup struct {
   826  	node
   827  	Tok   token
   828  	Decls []Decl
   829  }
   830  
   831  func (p *printer) printDecl(list []Decl) {
   832  	tok, group := groupFor(list[0])
   833  
   834  	if group == nil {
   835  		if len(list) != 1 {
   836  			panic("unreachable")
   837  		}
   838  		p.printNode(list[0])
   839  		return
   840  	}
   841  
   842  	// if _, ok := list[0].(*EmptyDecl); ok {
   843  	// 	if len(list) != 1 {
   844  	// 		panic("unreachable")
   845  	// 	}
   846  	// 	// TODO(gri) if there are comments inside the empty
   847  	// 	// group, we may need to keep the list non-nil
   848  	// 	list = nil
   849  	// }
   850  
   851  	// printGroup is here for consistent comment handling
   852  	// (this is not yet used)
   853  	var pg printGroup
   854  	// *pg.Comments() = *group.Comments()
   855  	pg.Tok = tok
   856  	pg.Decls = list
   857  	p.printNode(&pg)
   858  }
   859  
   860  func (p *printer) printDeclList(list []Decl) {
   861  	i0 := 0
   862  	var tok token
   863  	var group *Group
   864  	for i, x := range list {
   865  		if s, g := groupFor(x); g == nil || g != group {
   866  			if i0 < i {
   867  				p.printDecl(list[i0:i])
   868  				p.print(_Semi, newline)
   869  				// print empty line between different declaration groups,
   870  				// different kinds of declarations, or between functions
   871  				if g != group || s != tok || s == _Func {
   872  					p.print(newline)
   873  				}
   874  				i0 = i
   875  			}
   876  			tok, group = s, g
   877  		}
   878  	}
   879  	if i0 < len(list) {
   880  		p.printDecl(list[i0:])
   881  	}
   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(f.Type)
   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  		// Note that the parser strips parentheses in these cases
   947  		// (see extractName, parser.typeOrNil) unless keep_parens
   948  		// is set, so we should never reach here.
   949  		// Do the right thing (rather than panic) for testing and
   950  		// in case we change parser behavior.
   951  		// See also go.dev/issues/69206.
   952  		return !isTypeElem(x.X)
   953  	}
   954  	return false
   955  }
   956  
   957  func (p *printer) printStmtList(list []Stmt, braces bool) {
   958  	for i, x := range list {
   959  		p.print(x, _Semi)
   960  		if i+1 < len(list) {
   961  			p.print(newline)
   962  		} else if braces {
   963  			// Print an extra semicolon if the last statement is
   964  			// an empty statement and we are in a braced block
   965  			// because one semicolon is automatically removed.
   966  			if _, ok := x.(*EmptyStmt); ok {
   967  				p.print(x, _Semi)
   968  			}
   969  		}
   970  	}
   971  }
   972  
   973  func (p *printer) printSwitchBody(list []*CaseClause) {
   974  	p.print(_Lbrace)
   975  	if len(list) > 0 {
   976  		p.print(newline)
   977  		for i, c := range list {
   978  			p.printCaseClause(c, i+1 == len(list))
   979  			p.print(newline)
   980  		}
   981  	}
   982  	p.print(_Rbrace)
   983  }
   984  
   985  func (p *printer) printSelectBody(list []*CommClause) {
   986  	p.print(_Lbrace)
   987  	if len(list) > 0 {
   988  		p.print(newline)
   989  		for i, c := range list {
   990  			p.printCommClause(c, i+1 == len(list))
   991  			p.print(newline)
   992  		}
   993  	}
   994  	p.print(_Rbrace)
   995  }
   996  
   997  func (p *printer) printCaseClause(c *CaseClause, braces bool) {
   998  	if c.Cases != nil {
   999  		p.print(_Case, blank, c.Cases)
  1000  	} else {
  1001  		p.print(_Default)
  1002  	}
  1003  	p.print(_Colon)
  1004  	if len(c.Body) > 0 {
  1005  		p.print(newline, indent)
  1006  		p.printStmtList(c.Body, braces)
  1007  		p.print(outdent)
  1008  	}
  1009  }
  1010  
  1011  func (p *printer) printCommClause(c *CommClause, braces bool) {
  1012  	if c.Comm != nil {
  1013  		p.print(_Case, blank)
  1014  		p.print(c.Comm)
  1015  	} else {
  1016  		p.print(_Default)
  1017  	}
  1018  	p.print(_Colon)
  1019  	if len(c.Body) > 0 {
  1020  		p.print(newline, indent)
  1021  		p.printStmtList(c.Body, braces)
  1022  		p.print(outdent)
  1023  	}
  1024  }
  1025  

View as plain text