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

View as plain text