Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/compile/internal/syntax

     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 functions 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  		// separate type list and method list
   498  		var types []Expr
   499  		var methods []*Field
   500  		for _, f := range n.MethodList {
   501  			if f.Name != nil && f.Name.Value == "type" {
   502  				types = append(types, f.Type)
   503  			} else {
   504  				// method or embedded interface
   505  				methods = append(methods, f)
   506  			}
   507  		}
   508  
   509  		multiLine := len(n.MethodList) > 0 && p.linebreaks
   510  		p.print(_Interface)
   511  		if multiLine {
   512  			p.print(blank)
   513  		}
   514  		p.print(_Lbrace)
   515  		if multiLine {
   516  			p.print(newline, indent)
   517  		}
   518  		if len(types) > 0 {
   519  			p.print(_Type, blank)
   520  			p.printExprList(types)
   521  			if len(methods) > 0 {
   522  				p.print(_Semi, blank)
   523  			}
   524  		}
   525  		if len(methods) > 0 {
   526  			p.printMethodList(methods)
   527  		}
   528  		if multiLine {
   529  			p.print(outdent, newline)
   530  		}
   531  		p.print(_Rbrace)
   532  
   533  	case *MapType:
   534  		p.print(_Map, _Lbrack, n.Key, _Rbrack, n.Value)
   535  
   536  	case *ChanType:
   537  		if n.Dir == RecvOnly {
   538  			p.print(_Arrow)
   539  		}
   540  		p.print(_Chan)
   541  		if n.Dir == SendOnly {
   542  			p.print(_Arrow)
   543  		}
   544  		p.print(blank)
   545  		if e, _ := n.Elem.(*ChanType); n.Dir == 0 && e != nil && e.Dir == RecvOnly {
   546  			// don't print chan (<-chan T) as chan <-chan T
   547  			p.print(_Lparen)
   548  			p.print(n.Elem)
   549  			p.print(_Rparen)
   550  		} else {
   551  			p.print(n.Elem)
   552  		}
   553  
   554  	// statements
   555  	case *DeclStmt:
   556  		p.printDecl(n.DeclList)
   557  
   558  	case *EmptyStmt:
   559  		// nothing to print
   560  
   561  	case *LabeledStmt:
   562  		p.print(outdent, n.Label, _Colon, indent, newline, n.Stmt)
   563  
   564  	case *ExprStmt:
   565  		p.print(n.X)
   566  
   567  	case *SendStmt:
   568  		p.print(n.Chan, blank, _Arrow, blank, n.Value)
   569  
   570  	case *AssignStmt:
   571  		p.print(n.Lhs)
   572  		if n.Rhs == nil {
   573  			// TODO(gri) This is going to break the mayCombine
   574  			//           check once we enable that again.
   575  			p.print(n.Op, n.Op) // ++ or --
   576  		} else {
   577  			p.print(blank, n.Op, _Assign, blank)
   578  			p.print(n.Rhs)
   579  		}
   580  
   581  	case *CallStmt:
   582  		p.print(n.Tok, blank, n.Call)
   583  
   584  	case *ReturnStmt:
   585  		p.print(_Return)
   586  		if n.Results != nil {
   587  			p.print(blank, n.Results)
   588  		}
   589  
   590  	case *BranchStmt:
   591  		p.print(n.Tok)
   592  		if n.Label != nil {
   593  			p.print(blank, n.Label)
   594  		}
   595  
   596  	case *BlockStmt:
   597  		p.print(_Lbrace)
   598  		if len(n.List) > 0 {
   599  			p.print(newline, indent)
   600  			p.printStmtList(n.List, true)
   601  			p.print(outdent, newline)
   602  		}
   603  		p.print(_Rbrace)
   604  
   605  	case *IfStmt:
   606  		p.print(_If, blank)
   607  		if n.Init != nil {
   608  			p.print(n.Init, _Semi, blank)
   609  		}
   610  		p.print(n.Cond, blank, n.Then)
   611  		if n.Else != nil {
   612  			p.print(blank, _Else, blank, n.Else)
   613  		}
   614  
   615  	case *SwitchStmt:
   616  		p.print(_Switch, blank)
   617  		if n.Init != nil {
   618  			p.print(n.Init, _Semi, blank)
   619  		}
   620  		if n.Tag != nil {
   621  			p.print(n.Tag, blank)
   622  		}
   623  		p.printSwitchBody(n.Body)
   624  
   625  	case *SelectStmt:
   626  		p.print(_Select, blank) // for now
   627  		p.printSelectBody(n.Body)
   628  
   629  	case *RangeClause:
   630  		if n.Lhs != nil {
   631  			tok := _Assign
   632  			if n.Def {
   633  				tok = _Define
   634  			}
   635  			p.print(n.Lhs, blank, tok, blank)
   636  		}
   637  		p.print(_Range, blank, n.X)
   638  
   639  	case *ForStmt:
   640  		p.print(_For, blank)
   641  		if n.Init == nil && n.Post == nil {
   642  			if n.Cond != nil {
   643  				p.print(n.Cond, blank)
   644  			}
   645  		} else {
   646  			if n.Init != nil {
   647  				p.print(n.Init)
   648  				// TODO(gri) clean this up
   649  				if _, ok := n.Init.(*RangeClause); ok {
   650  					p.print(blank, n.Body)
   651  					break
   652  				}
   653  			}
   654  			p.print(_Semi, blank)
   655  			if n.Cond != nil {
   656  				p.print(n.Cond)
   657  			}
   658  			p.print(_Semi, blank)
   659  			if n.Post != nil {
   660  				p.print(n.Post, blank)
   661  			}
   662  		}
   663  		p.print(n.Body)
   664  
   665  	case *ImportDecl:
   666  		if n.Group == nil {
   667  			p.print(_Import, blank)
   668  		}
   669  		if n.LocalPkgName != nil {
   670  			p.print(n.LocalPkgName, blank)
   671  		}
   672  		p.print(n.Path)
   673  
   674  	case *ConstDecl:
   675  		if n.Group == nil {
   676  			p.print(_Const, 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 *TypeDecl:
   687  		if n.Group == nil {
   688  			p.print(_Type, blank)
   689  		}
   690  		p.print(n.Name)
   691  		if n.TParamList != nil {
   692  			p.print(_Lbrack)
   693  			p.printFieldList(n.TParamList, nil, _Comma)
   694  			p.print(_Rbrack)
   695  		}
   696  		p.print(blank)
   697  		if n.Alias {
   698  			p.print(_Assign, blank)
   699  		}
   700  		p.print(n.Type)
   701  
   702  	case *VarDecl:
   703  		if n.Group == nil {
   704  			p.print(_Var, blank)
   705  		}
   706  		p.printNameList(n.NameList)
   707  		if n.Type != nil {
   708  			p.print(blank, n.Type)
   709  		}
   710  		if n.Values != nil {
   711  			p.print(blank, _Assign, blank, n.Values)
   712  		}
   713  
   714  	case *FuncDecl:
   715  		p.print(_Func, blank)
   716  		if r := n.Recv; r != nil {
   717  			p.print(_Lparen)
   718  			if r.Name != nil {
   719  				p.print(r.Name, blank)
   720  			}
   721  			p.printNode(r.Type)
   722  			p.print(_Rparen, blank)
   723  		}
   724  		p.print(n.Name)
   725  		if n.TParamList != nil {
   726  			p.print(_Lbrack)
   727  			p.printFieldList(n.TParamList, nil, _Comma)
   728  			p.print(_Rbrack)
   729  		}
   730  		p.printSignature(n.Type)
   731  		if n.Body != nil {
   732  			p.print(blank, n.Body)
   733  		}
   734  
   735  	case *printGroup:
   736  		p.print(n.Tok, blank, _Lparen)
   737  		if len(n.Decls) > 0 {
   738  			p.print(newline, indent)
   739  			for _, d := range n.Decls {
   740  				p.printNode(d)
   741  				p.print(_Semi, newline)
   742  			}
   743  			p.print(outdent)
   744  		}
   745  		p.print(_Rparen)
   746  
   747  	// files
   748  	case *File:
   749  		p.print(_Package, blank, n.PkgName)
   750  		if len(n.DeclList) > 0 {
   751  			p.print(_Semi, newline, newline)
   752  			p.printDeclList(n.DeclList)
   753  		}
   754  
   755  	default:
   756  		panic(fmt.Sprintf("syntax.Iterate: unexpected node type %T", n))
   757  	}
   758  }
   759  
   760  func (p *printer) printFields(fields []*Field, tags []*BasicLit, i, j int) {
   761  	if i+1 == j && fields[i].Name == nil {
   762  		// anonymous field
   763  		p.printNode(fields[i].Type)
   764  	} else {
   765  		for k, f := range fields[i:j] {
   766  			if k > 0 {
   767  				p.print(_Comma, blank)
   768  			}
   769  			p.printNode(f.Name)
   770  		}
   771  		p.print(blank)
   772  		p.printNode(fields[i].Type)
   773  	}
   774  	if i < len(tags) && tags[i] != nil {
   775  		p.print(blank)
   776  		p.printNode(tags[i])
   777  	}
   778  }
   779  
   780  func (p *printer) printFieldList(fields []*Field, tags []*BasicLit, sep token) {
   781  	i0 := 0
   782  	var typ Expr
   783  	for i, f := range fields {
   784  		if f.Name == nil || f.Type != typ {
   785  			if i0 < i {
   786  				p.printFields(fields, tags, i0, i)
   787  				p.print(sep, newline)
   788  				i0 = i
   789  			}
   790  			typ = f.Type
   791  		}
   792  	}
   793  	p.printFields(fields, tags, i0, len(fields))
   794  }
   795  
   796  func (p *printer) printMethodList(methods []*Field) {
   797  	for i, m := range methods {
   798  		if i > 0 {
   799  			p.print(_Semi, newline)
   800  		}
   801  		if m.Name != nil {
   802  			p.printNode(m.Name)
   803  			p.printSignature(m.Type.(*FuncType))
   804  		} else {
   805  			p.printNode(m.Type)
   806  		}
   807  	}
   808  }
   809  
   810  func (p *printer) printNameList(list []*Name) {
   811  	for i, x := range list {
   812  		if i > 0 {
   813  			p.print(_Comma, blank)
   814  		}
   815  		p.printNode(x)
   816  	}
   817  }
   818  
   819  func (p *printer) printExprList(list []Expr) {
   820  	for i, x := range list {
   821  		if i > 0 {
   822  			p.print(_Comma, blank)
   823  		}
   824  		p.printNode(x)
   825  	}
   826  }
   827  
   828  func (p *printer) printExprLines(list []Expr) {
   829  	if len(list) > 0 {
   830  		p.print(newline, indent)
   831  		for _, x := range list {
   832  			p.print(x, _Comma, newline)
   833  		}
   834  		p.print(outdent)
   835  	}
   836  }
   837  
   838  func groupFor(d Decl) (token, *Group) {
   839  	switch d := d.(type) {
   840  	case *ImportDecl:
   841  		return _Import, d.Group
   842  	case *ConstDecl:
   843  		return _Const, d.Group
   844  	case *TypeDecl:
   845  		return _Type, d.Group
   846  	case *VarDecl:
   847  		return _Var, d.Group
   848  	case *FuncDecl:
   849  		return _Func, nil
   850  	default:
   851  		panic("unreachable")
   852  	}
   853  }
   854  
   855  type printGroup struct {
   856  	node
   857  	Tok   token
   858  	Decls []Decl
   859  }
   860  
   861  func (p *printer) printDecl(list []Decl) {
   862  	tok, group := groupFor(list[0])
   863  
   864  	if group == nil {
   865  		if len(list) != 1 {
   866  			panic("unreachable")
   867  		}
   868  		p.printNode(list[0])
   869  		return
   870  	}
   871  
   872  	// if _, ok := list[0].(*EmptyDecl); ok {
   873  	// 	if len(list) != 1 {
   874  	// 		panic("unreachable")
   875  	// 	}
   876  	// 	// TODO(gri) if there are comments inside the empty
   877  	// 	// group, we may need to keep the list non-nil
   878  	// 	list = nil
   879  	// }
   880  
   881  	// printGroup is here for consistent comment handling
   882  	// (this is not yet used)
   883  	var pg printGroup
   884  	// *pg.Comments() = *group.Comments()
   885  	pg.Tok = tok
   886  	pg.Decls = list
   887  	p.printNode(&pg)
   888  }
   889  
   890  func (p *printer) printDeclList(list []Decl) {
   891  	i0 := 0
   892  	var tok token
   893  	var group *Group
   894  	for i, x := range list {
   895  		if s, g := groupFor(x); g == nil || g != group {
   896  			if i0 < i {
   897  				p.printDecl(list[i0:i])
   898  				p.print(_Semi, newline)
   899  				// print empty line between different declaration groups,
   900  				// different kinds of declarations, or between functions
   901  				if g != group || s != tok || s == _Func {
   902  					p.print(newline)
   903  				}
   904  				i0 = i
   905  			}
   906  			tok, group = s, g
   907  		}
   908  	}
   909  	p.printDecl(list[i0:])
   910  }
   911  
   912  func (p *printer) printSignature(sig *FuncType) {
   913  	p.printParameterList(sig.ParamList)
   914  	if list := sig.ResultList; list != nil {
   915  		p.print(blank)
   916  		if len(list) == 1 && list[0].Name == nil {
   917  			p.printNode(list[0].Type)
   918  		} else {
   919  			p.printParameterList(list)
   920  		}
   921  	}
   922  }
   923  
   924  func (p *printer) printParameterList(list []*Field) {
   925  	p.print(_Lparen)
   926  	if len(list) > 0 {
   927  		for i, f := range list {
   928  			if i > 0 {
   929  				p.print(_Comma, blank)
   930  			}
   931  			if f.Name != nil {
   932  				p.printNode(f.Name)
   933  				if i+1 < len(list) {
   934  					f1 := list[i+1]
   935  					if f1.Name != nil && f1.Type == f.Type {
   936  						continue // no need to print type
   937  					}
   938  				}
   939  				p.print(blank)
   940  			}
   941  			p.printNode(f.Type)
   942  		}
   943  	}
   944  	p.print(_Rparen)
   945  }
   946  
   947  func (p *printer) printStmtList(list []Stmt, braces bool) {
   948  	for i, x := range list {
   949  		p.print(x, _Semi)
   950  		if i+1 < len(list) {
   951  			p.print(newline)
   952  		} else if braces {
   953  			// Print an extra semicolon if the last statement is
   954  			// an empty statement and we are in a braced block
   955  			// because one semicolon is automatically removed.
   956  			if _, ok := x.(*EmptyStmt); ok {
   957  				p.print(x, _Semi)
   958  			}
   959  		}
   960  	}
   961  }
   962  
   963  func (p *printer) printSwitchBody(list []*CaseClause) {
   964  	p.print(_Lbrace)
   965  	if len(list) > 0 {
   966  		p.print(newline)
   967  		for i, c := range list {
   968  			p.printCaseClause(c, i+1 == len(list))
   969  			p.print(newline)
   970  		}
   971  	}
   972  	p.print(_Rbrace)
   973  }
   974  
   975  func (p *printer) printSelectBody(list []*CommClause) {
   976  	p.print(_Lbrace)
   977  	if len(list) > 0 {
   978  		p.print(newline)
   979  		for i, c := range list {
   980  			p.printCommClause(c, i+1 == len(list))
   981  			p.print(newline)
   982  		}
   983  	}
   984  	p.print(_Rbrace)
   985  }
   986  
   987  func (p *printer) printCaseClause(c *CaseClause, braces bool) {
   988  	if c.Cases != nil {
   989  		p.print(_Case, blank, c.Cases)
   990  	} else {
   991  		p.print(_Default)
   992  	}
   993  	p.print(_Colon)
   994  	if len(c.Body) > 0 {
   995  		p.print(newline, indent)
   996  		p.printStmtList(c.Body, braces)
   997  		p.print(outdent)
   998  	}
   999  }
  1000  
  1001  func (p *printer) printCommClause(c *CommClause, braces bool) {
  1002  	if c.Comm != nil {
  1003  		p.print(_Case, blank)
  1004  		p.print(c.Comm)
  1005  	} else {
  1006  		p.print(_Default)
  1007  	}
  1008  	p.print(_Colon)
  1009  	if len(c.Body) > 0 {
  1010  		p.print(newline, indent)
  1011  		p.printStmtList(c.Body, braces)
  1012  		p.print(outdent)
  1013  	}
  1014  }
  1015  

View as plain text