github.com/goplus/gop@v1.2.6/printer/nodes.go (about)

     1  /*
     2   * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  // This file implements printing of AST nodes; specifically
    18  // expressions, statements, declarations, and files. It uses
    19  // the print functionality implemented in printer.go.
    20  
    21  package printer
    22  
    23  import (
    24  	"bytes"
    25  	"log"
    26  	"math"
    27  	"strconv"
    28  	"strings"
    29  	"unicode"
    30  	"unicode/utf8"
    31  
    32  	"github.com/goplus/gop/ast"
    33  	"github.com/goplus/gop/token"
    34  )
    35  
    36  const (
    37  	DbgFlagAll = 1
    38  )
    39  
    40  var (
    41  	debugFormat bool
    42  )
    43  
    44  func SetDebug(flags int) {
    45  	if flags != 0 {
    46  		debugFormat = true
    47  	}
    48  }
    49  
    50  // Formatting issues:
    51  // - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
    52  //   when the comment spans multiple lines; if such a comment is just two lines, formatting is
    53  //   not idempotent
    54  // - formatting of expression lists
    55  // - should use blank instead of tab to separate one-line function bodies from
    56  //   the function header unless there is a group of consecutive one-liners
    57  
    58  // ----------------------------------------------------------------------------
    59  // Common AST nodes.
    60  
    61  // Print as many newlines as necessary (but at least min newlines) to get to
    62  // the current line. ws is printed before the first line break. If newSection
    63  // is set, the first line break is printed as formfeed. Returns 0 if no line
    64  // breaks were printed, returns 1 if there was exactly one newline printed,
    65  // and returns a value > 1 if there was a formfeed or more than one newline
    66  // printed.
    67  //
    68  // TODO(gri): linebreak may add too many lines if the next statement at "line"
    69  //
    70  //	is preceded by comments because the computation of n assumes
    71  //	the current position before the comment and the target position
    72  //	after the comment. Thus, after interspersing such comments, the
    73  //	space taken up by them is not considered to reduce the number of
    74  //	linebreaks. At the moment there is no easy way to know about
    75  //	future (not yet interspersed) comments in this function.
    76  func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (nbreaks int) {
    77  	n := nlimit(line - p.pos.Line)
    78  	if n < min {
    79  		n = min
    80  	}
    81  	if n > 0 {
    82  		p.print(ws)
    83  		if newSection {
    84  			p.print(formfeed)
    85  			n--
    86  			nbreaks = 2
    87  		}
    88  		nbreaks += n
    89  		for ; n > 0; n-- {
    90  			p.print(newline)
    91  		}
    92  	}
    93  	return
    94  }
    95  
    96  // setComment sets g as the next comment if g != nil and if node comments
    97  // are enabled - this mode is used when printing source code fragments such
    98  // as exports only. It assumes that there is no pending comment in p.comments
    99  // and at most one pending comment in the p.comment cache.
   100  func (p *printer) setComment(g *ast.CommentGroup) {
   101  	if g == nil || !p.useNodeComments {
   102  		return
   103  	}
   104  	if p.comments == nil {
   105  		// initialize p.comments lazily
   106  		p.comments = make([]*ast.CommentGroup, 1)
   107  	} else if p.cindex < len(p.comments) {
   108  		// for some reason there are pending comments; this
   109  		// should never happen - handle gracefully and flush
   110  		// all comments up to g, ignore anything after that
   111  		p.flush(p.posFor(g.List[0].Pos()), token.ILLEGAL)
   112  		p.comments = p.comments[0:1]
   113  		// in debug mode, report error
   114  		p.internalError("setComment found pending comments")
   115  	}
   116  	p.comments[0] = g
   117  	p.cindex = 0
   118  	// don't overwrite any pending comment in the p.comment cache
   119  	// (there may be a pending comment when a line comment is
   120  	// immediately followed by a lead comment with no other
   121  	// tokens between)
   122  	if p.commentOffset == infinity {
   123  		p.nextComment() // get comment ready for use
   124  	}
   125  }
   126  
   127  type exprListMode uint
   128  
   129  const (
   130  	commaTerm exprListMode = 1 << iota // list is optionally terminated by a comma
   131  	noIndent                           // no extra indentation in multi-line lists
   132  )
   133  
   134  // If indent is set, a multi-line identifier list is indented after the
   135  // first linebreak encountered.
   136  func (p *printer) identList(list []*ast.Ident, indent bool) {
   137  	// convert into an expression list so we can re-use exprList formatting
   138  	xlist := make([]ast.Expr, len(list))
   139  	for i, x := range list {
   140  		xlist[i] = x
   141  	}
   142  	var mode exprListMode
   143  	if !indent {
   144  		mode = noIndent
   145  	}
   146  	p.exprList(token.NoPos, xlist, 1, mode, token.NoPos, false)
   147  }
   148  
   149  const filteredMsg = "contains filtered or unexported fields"
   150  
   151  // Print a list of expressions. If the list spans multiple
   152  // source lines, the original line breaks are respected between
   153  // expressions.
   154  //
   155  // TODO(gri) Consider rewriting this to be independent of []ast.Expr
   156  //
   157  //	so that we can use the algorithm for any kind of list
   158  //	(e.g., pass list via a channel over which to range).
   159  func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, next0 token.Pos, isIncomplete bool) {
   160  	if len(list) == 0 {
   161  		if isIncomplete {
   162  			prev := p.posFor(prev0)
   163  			next := p.posFor(next0)
   164  			if prev.IsValid() && prev.Line == next.Line {
   165  				p.print("/* " + filteredMsg + " */")
   166  			} else {
   167  				p.print(newline)
   168  				p.print(indent, "// "+filteredMsg, unindent, newline)
   169  			}
   170  		}
   171  		return
   172  	}
   173  
   174  	prev := p.posFor(prev0)
   175  	next := p.posFor(next0)
   176  	line := p.lineFor(list[0].Pos())
   177  	endLine := p.lineFor(list[len(list)-1].End())
   178  
   179  	if prev.IsValid() && prev.Line == line && line == endLine {
   180  		// all list entries on a single line
   181  		for i, x := range list {
   182  			if i > 0 {
   183  				// use position of expression following the comma as
   184  				// comma position for correct comment placement
   185  				p.print(x.Pos(), token.COMMA, blank)
   186  			}
   187  			p.expr0(x, depth)
   188  		}
   189  		if isIncomplete {
   190  			p.print(token.COMMA, blank, "/* "+filteredMsg+" */")
   191  		}
   192  		return
   193  	}
   194  
   195  	// list entries span multiple lines;
   196  	// use source code positions to guide line breaks
   197  
   198  	// Don't add extra indentation if noIndent is set;
   199  	// i.e., pretend that the first line is already indented.
   200  	ws := ignore
   201  	if mode&noIndent == 0 {
   202  		ws = indent
   203  	}
   204  
   205  	// The first linebreak is always a formfeed since this section must not
   206  	// depend on any previous formatting.
   207  	prevBreak := -1 // index of last expression that was followed by a linebreak
   208  	if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) > 0 {
   209  		ws = ignore
   210  		prevBreak = 0
   211  	}
   212  
   213  	// initialize expression/key size: a zero value indicates expr/key doesn't fit on a single line
   214  	size := 0
   215  
   216  	// We use the ratio between the geometric mean of the previous key sizes and
   217  	// the current size to determine if there should be a break in the alignment.
   218  	// To compute the geometric mean we accumulate the ln(size) values (lnsum)
   219  	// and the number of sizes included (count).
   220  	lnsum := 0.0
   221  	count := 0
   222  
   223  	// print all list elements
   224  	prevLine := prev.Line
   225  	for i, x := range list {
   226  		line = p.lineFor(x.Pos())
   227  
   228  		// Determine if the next linebreak, if any, needs to use formfeed:
   229  		// in general, use the entire node size to make the decision; for
   230  		// key:value expressions, use the key size.
   231  		// TODO(gri) for a better result, should probably incorporate both
   232  		//           the key and the node size into the decision process
   233  		useFF := true
   234  
   235  		// Determine element size: All bets are off if we don't have
   236  		// position information for the previous and next token (likely
   237  		// generated code - simply ignore the size in this case by setting
   238  		// it to 0).
   239  		prevSize := size
   240  		const infinity = 1e6 // larger than any source line
   241  		size = p.nodeSize(x, infinity)
   242  		pair, isPair := x.(*ast.KeyValueExpr)
   243  		if size <= infinity && prev.IsValid() && next.IsValid() {
   244  			// x fits on a single line
   245  			if isPair {
   246  				size = p.nodeSize(pair.Key, infinity) // size <= infinity
   247  			}
   248  		} else {
   249  			// size too large or we don't have good layout information
   250  			size = 0
   251  		}
   252  
   253  		// If the previous line and the current line had single-
   254  		// line-expressions and the key sizes are small or the
   255  		// ratio between the current key and the geometric mean
   256  		// if the previous key sizes does not exceed a threshold,
   257  		// align columns and do not use formfeed.
   258  		if prevSize > 0 && size > 0 {
   259  			const smallSize = 40
   260  			if count == 0 || prevSize <= smallSize && size <= smallSize {
   261  				useFF = false
   262  			} else {
   263  				const r = 2.5                               // threshold
   264  				geomean := math.Exp(lnsum / float64(count)) // count > 0
   265  				ratio := float64(size) / geomean
   266  				useFF = r*ratio <= 1 || r <= ratio
   267  			}
   268  		}
   269  
   270  		needsLinebreak := 0 < prevLine && prevLine < line
   271  		if i > 0 {
   272  			// Use position of expression following the comma as
   273  			// comma position for correct comment placement, but
   274  			// only if the expression is on the same line.
   275  			if !needsLinebreak {
   276  				p.print(x.Pos())
   277  			}
   278  			p.print(token.COMMA)
   279  			needsBlank := true
   280  			if needsLinebreak {
   281  				// Lines are broken using newlines so comments remain aligned
   282  				// unless useFF is set or there are multiple expressions on
   283  				// the same line in which case formfeed is used.
   284  				nbreaks := p.linebreak(line, 0, ws, useFF || prevBreak+1 < i)
   285  				if nbreaks > 0 {
   286  					ws = ignore
   287  					prevBreak = i
   288  					needsBlank = false // we got a line break instead
   289  				}
   290  				// If there was a new section or more than one new line
   291  				// (which means that the tabwriter will implicitly break
   292  				// the section), reset the geomean variables since we are
   293  				// starting a new group of elements with the next element.
   294  				if nbreaks > 1 {
   295  					lnsum = 0
   296  					count = 0
   297  				}
   298  			}
   299  			if needsBlank {
   300  				p.print(blank)
   301  			}
   302  		}
   303  
   304  		if len(list) > 1 && isPair && size > 0 && needsLinebreak {
   305  			// We have a key:value expression that fits onto one line
   306  			// and it's not on the same line as the prior expression:
   307  			// Use a column for the key such that consecutive entries
   308  			// can align if possible.
   309  			// (needsLinebreak is set if we started a new line before)
   310  			p.expr(pair.Key)
   311  			p.print(pair.Colon, token.COLON, vtab)
   312  			p.expr(pair.Value)
   313  		} else {
   314  			p.expr0(x, depth)
   315  		}
   316  
   317  		if size > 0 {
   318  			lnsum += math.Log(float64(size))
   319  			count++
   320  		}
   321  
   322  		prevLine = line
   323  	}
   324  
   325  	if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
   326  		// Print a terminating comma if the next token is on a new line.
   327  		p.print(token.COMMA)
   328  		if isIncomplete {
   329  			p.print(newline)
   330  			p.print("// " + filteredMsg)
   331  		}
   332  		if ws == ignore && mode&noIndent == 0 {
   333  			// unindent if we indented
   334  			p.print(unindent)
   335  		}
   336  		p.print(formfeed) // terminating comma needs a line break to look good
   337  		return
   338  	}
   339  
   340  	if isIncomplete {
   341  		p.print(token.COMMA, newline)
   342  		p.print("// "+filteredMsg, newline)
   343  	}
   344  
   345  	if ws == ignore && mode&noIndent == 0 {
   346  		// unindent if we indented
   347  		p.print(unindent)
   348  	}
   349  }
   350  
   351  func (p *printer) parameters(fields *ast.FieldList) {
   352  	p.print(fields.Opening, token.LPAREN)
   353  	if len(fields.List) > 0 {
   354  		prevLine := p.lineFor(fields.Opening)
   355  		ws := indent
   356  		for i, par := range fields.List {
   357  			// determine par begin and end line (may be different
   358  			// if there are multiple parameter names for this par
   359  			// or the type is on a separate line)
   360  			var parLineBeg int
   361  			if len(par.Names) > 0 {
   362  				parLineBeg = p.lineFor(par.Names[0].Pos())
   363  			} else {
   364  				parLineBeg = p.lineFor(par.Type.Pos())
   365  			}
   366  			var parLineEnd = p.lineFor(par.Type.End())
   367  			// separating "," if needed
   368  			needsLinebreak := 0 < prevLine && prevLine < parLineBeg
   369  			if i > 0 {
   370  				// use position of parameter following the comma as
   371  				// comma position for correct comma placement, but
   372  				// only if the next parameter is on the same line
   373  				if !needsLinebreak {
   374  					p.print(par.Pos())
   375  				}
   376  				p.print(token.COMMA)
   377  			}
   378  			// separator if needed (linebreak or blank)
   379  			if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) > 0 {
   380  				// break line if the opening "(" or previous parameter ended on a different line
   381  				ws = ignore
   382  			} else if i > 0 {
   383  				p.print(blank)
   384  			}
   385  			// parameter names
   386  			if len(par.Names) > 0 {
   387  				// Very subtle: If we indented before (ws == ignore), identList
   388  				// won't indent again. If we didn't (ws == indent), identList will
   389  				// indent if the identList spans multiple lines, and it will outdent
   390  				// again at the end (and still ws == indent). Thus, a subsequent indent
   391  				// by a linebreak call after a type, or in the next multi-line identList
   392  				// will do the right thing.
   393  				p.identList(par.Names, ws == indent)
   394  				p.print(blank)
   395  			}
   396  			// parameter type
   397  			p.expr(stripParensAlways(par.Type))
   398  			prevLine = parLineEnd
   399  		}
   400  		// if the closing ")" is on a separate line from the last parameter,
   401  		// print an additional "," and line break
   402  		if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
   403  			p.print(token.COMMA)
   404  			p.linebreak(closing, 0, ignore, true)
   405  		}
   406  		// unindent if we indented
   407  		if ws == ignore {
   408  			p.print(unindent)
   409  		}
   410  	}
   411  	p.print(fields.Closing, token.RPAREN)
   412  }
   413  
   414  func (p *printer) signature(params, result *ast.FieldList) {
   415  	if params != nil {
   416  		p.parameters(params)
   417  	} else {
   418  		p.print(token.LPAREN, token.RPAREN)
   419  	}
   420  	n := result.NumFields()
   421  	if n > 0 {
   422  		// result != nil
   423  		p.print(blank)
   424  		if n == 1 && result.List[0].Names == nil {
   425  			// single anonymous result; no ()'s
   426  			p.expr(stripParensAlways(result.List[0].Type))
   427  			return
   428  		}
   429  		p.parameters(result)
   430  	}
   431  }
   432  
   433  func identListSize(list []*ast.Ident, maxSize int) (size int) {
   434  	for i, x := range list {
   435  		if i > 0 {
   436  			size += len(", ")
   437  		}
   438  		size += utf8.RuneCountInString(x.Name)
   439  		if size >= maxSize {
   440  			break
   441  		}
   442  	}
   443  	return
   444  }
   445  
   446  func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
   447  	if len(list) != 1 {
   448  		return false // allow only one field
   449  	}
   450  	f := list[0]
   451  	if f.Tag != nil || f.Comment != nil {
   452  		return false // don't allow tags or comments
   453  	}
   454  	// only name(s) and type
   455  	const maxSize = 30 // adjust as appropriate, this is an approximate value
   456  	namesSize := identListSize(f.Names, maxSize)
   457  	if namesSize > 0 {
   458  		namesSize = 1 // blank between names and types
   459  	}
   460  	typeSize := p.nodeSize(f.Type, maxSize)
   461  	return namesSize+typeSize <= maxSize
   462  }
   463  
   464  func (p *printer) setLineComment(text string) {
   465  	p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
   466  }
   467  
   468  func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
   469  	lbrace := fields.Opening
   470  	list := fields.List
   471  	rbrace := fields.Closing
   472  	hasComments := isIncomplete || p.commentBefore(p.posFor(rbrace))
   473  	srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.lineFor(lbrace) == p.lineFor(rbrace)
   474  
   475  	if !hasComments && srcIsOneLine {
   476  		// possibly a one-line struct/interface
   477  		if len(list) == 0 {
   478  			// no blank between keyword and {} in this case
   479  			p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
   480  			return
   481  		} else if p.isOneLineFieldList(list) {
   482  			// small enough - print on one line
   483  			// (don't use identList and ignore source line breaks)
   484  			p.print(lbrace, token.LBRACE, blank)
   485  			f := list[0]
   486  			if isStruct {
   487  				for i, x := range f.Names {
   488  					if i > 0 {
   489  						// no comments so no need for comma position
   490  						p.print(token.COMMA, blank)
   491  					}
   492  					p.expr(x)
   493  				}
   494  				if len(f.Names) > 0 {
   495  					p.print(blank)
   496  				}
   497  				p.expr(f.Type)
   498  			} else { // interface
   499  				if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
   500  					// method
   501  					p.expr(f.Names[0])
   502  					p.signature(ftyp.Params, ftyp.Results)
   503  				} else {
   504  					// embedded interface
   505  					p.expr(f.Type)
   506  				}
   507  			}
   508  			p.print(blank, rbrace, token.RBRACE)
   509  			return
   510  		}
   511  	}
   512  	// hasComments || !srcIsOneLine
   513  
   514  	p.print(blank, lbrace, token.LBRACE, indent)
   515  	if hasComments || len(list) > 0 {
   516  		p.print(formfeed)
   517  	}
   518  
   519  	if isStruct {
   520  
   521  		sep := vtab
   522  		if len(list) == 1 {
   523  			sep = blank
   524  		}
   525  		var line int
   526  		for i, f := range list {
   527  			if i > 0 {
   528  				p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
   529  			}
   530  			extraTabs := 0
   531  			p.setComment(f.Doc)
   532  			p.recordLine(&line)
   533  			if len(f.Names) > 0 {
   534  				// named fields
   535  				p.identList(f.Names, false)
   536  				p.print(sep)
   537  				p.expr(f.Type)
   538  				extraTabs = 1
   539  			} else {
   540  				// anonymous field
   541  				p.expr(f.Type)
   542  				extraTabs = 2
   543  			}
   544  			if f.Tag != nil {
   545  				if len(f.Names) > 0 && sep == vtab {
   546  					p.print(sep)
   547  				}
   548  				p.print(sep)
   549  				p.expr(f.Tag)
   550  				extraTabs = 0
   551  			}
   552  			if f.Comment != nil {
   553  				for ; extraTabs > 0; extraTabs-- {
   554  					p.print(sep)
   555  				}
   556  				p.setComment(f.Comment)
   557  			}
   558  		}
   559  		if isIncomplete {
   560  			if len(list) > 0 {
   561  				p.print(formfeed)
   562  			}
   563  			p.flush(p.posFor(rbrace), token.RBRACE) // make sure we don't lose the last line comment
   564  			p.setLineComment("// " + filteredMsg)
   565  		}
   566  
   567  	} else { // interface
   568  
   569  		var line int
   570  		for i, f := range list {
   571  			if i > 0 {
   572  				p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
   573  			}
   574  			p.setComment(f.Doc)
   575  			p.recordLine(&line)
   576  			if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
   577  				// method
   578  				p.expr(f.Names[0])
   579  				p.signature(ftyp.Params, ftyp.Results)
   580  			} else {
   581  				// embedded interface
   582  				p.expr(f.Type)
   583  			}
   584  			p.setComment(f.Comment)
   585  		}
   586  		if isIncomplete {
   587  			if len(list) > 0 {
   588  				p.print(formfeed)
   589  			}
   590  			p.flush(p.posFor(rbrace), token.RBRACE) // make sure we don't lose the last line comment
   591  			p.setLineComment("// contains filtered or unexported methods")
   592  		}
   593  
   594  	}
   595  	p.print(unindent, formfeed, rbrace, token.RBRACE)
   596  }
   597  
   598  // ----------------------------------------------------------------------------
   599  // Expressions
   600  
   601  func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
   602  	switch e.Op.Precedence() {
   603  	case 4:
   604  		has4 = true
   605  	case 5:
   606  		has5 = true
   607  	}
   608  
   609  	switch l := e.X.(type) {
   610  	case *ast.BinaryExpr:
   611  		if l.Op.Precedence() < e.Op.Precedence() {
   612  			// parens will be inserted.
   613  			// pretend this is an *ast.ParenExpr and do nothing.
   614  			break
   615  		}
   616  		h4, h5, mp := walkBinary(l)
   617  		has4 = has4 || h4
   618  		has5 = has5 || h5
   619  		if maxProblem < mp {
   620  			maxProblem = mp
   621  		}
   622  	}
   623  
   624  	switch r := e.Y.(type) {
   625  	case *ast.BinaryExpr:
   626  		if r.Op.Precedence() <= e.Op.Precedence() {
   627  			// parens will be inserted.
   628  			// pretend this is an *ast.ParenExpr and do nothing.
   629  			break
   630  		}
   631  		h4, h5, mp := walkBinary(r)
   632  		has4 = has4 || h4
   633  		has5 = has5 || h5
   634  		if maxProblem < mp {
   635  			maxProblem = mp
   636  		}
   637  
   638  	case *ast.StarExpr:
   639  		if e.Op == token.QUO { // `*/`
   640  			maxProblem = 5
   641  		}
   642  
   643  	case *ast.UnaryExpr:
   644  		switch e.Op.String() + r.Op.String() {
   645  		case "/*", "&&", "&^":
   646  			maxProblem = 5
   647  		case "++", "--":
   648  			if maxProblem < 4 {
   649  				maxProblem = 4
   650  			}
   651  		}
   652  	}
   653  	return
   654  }
   655  
   656  func cutoff(e *ast.BinaryExpr, depth int) int {
   657  	has4, has5, maxProblem := walkBinary(e)
   658  	if maxProblem > 0 {
   659  		return maxProblem + 1
   660  	}
   661  	if has4 && has5 {
   662  		if depth == 1 {
   663  			return 5
   664  		}
   665  		return 4
   666  	}
   667  	if depth == 1 {
   668  		return 6
   669  	}
   670  	return 4
   671  }
   672  
   673  func diffPrec(expr ast.Expr, prec int) int {
   674  	x, ok := expr.(*ast.BinaryExpr)
   675  	if !ok || prec != x.Op.Precedence() {
   676  		return 1
   677  	}
   678  	return 0
   679  }
   680  
   681  func reduceDepth(depth int) int {
   682  	depth--
   683  	if depth < 1 {
   684  		depth = 1
   685  	}
   686  	return depth
   687  }
   688  
   689  // Format the binary expression: decide the cutoff and then format.
   690  // Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
   691  // (Algorithm suggestion by Russ Cox.)
   692  //
   693  // The precedences are:
   694  //
   695  //	5             *  /  %  <<  >>  &  &^
   696  //	4             +  -  |  ^
   697  //	3             ==  !=  <  <=  >  >=
   698  //	2             &&
   699  //	1             ||
   700  //
   701  // The only decision is whether there will be spaces around levels 4 and 5.
   702  // There are never spaces at level 6 (unary), and always spaces at levels 3 and below.
   703  //
   704  // To choose the cutoff, look at the whole expression but excluding primary
   705  // expressions (function calls, parenthesized exprs), and apply these rules:
   706  //
   707  //  1. If there is a binary operator with a right side unary operand
   708  //     that would clash without a space, the cutoff must be (in order):
   709  //
   710  //     /*	6
   711  //     &&	6
   712  //     &^	6
   713  //     ++	5
   714  //     --	5
   715  //
   716  //     (Comparison operators always have spaces around them.)
   717  //
   718  //  2. If there is a mix of level 5 and level 4 operators, then the cutoff
   719  //     is 5 (use spaces to distinguish precedence) in Normal mode
   720  //     and 4 (never use spaces) in Compact mode.
   721  //
   722  //  3. If there are no level 4 operators or no level 5 operators, then the
   723  //     cutoff is 6 (always use spaces) in Normal mode
   724  //     and 4 (never use spaces) in Compact mode.
   725  func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
   726  	prec := x.Op.Precedence()
   727  	if prec < prec1 {
   728  		// parenthesis needed
   729  		// Note: The parser inserts an ast.ParenExpr node; thus this case
   730  		//       can only occur if the AST is created in a different way.
   731  		p.print(token.LPAREN)
   732  		p.expr0(x, reduceDepth(depth)) // parentheses undo one level of depth
   733  		p.print(token.RPAREN)
   734  		return
   735  	}
   736  
   737  	printBlank := prec < cutoff
   738  
   739  	ws := indent
   740  	p.expr1(x.X, prec, depth+diffPrec(x.X, prec))
   741  	if printBlank {
   742  		p.print(blank)
   743  	}
   744  	xline := p.pos.Line // before the operator (it may be on the next line!)
   745  	yline := p.lineFor(x.Y.Pos())
   746  	p.print(x.OpPos, x.Op)
   747  	if xline != yline && xline > 0 && yline > 0 {
   748  		// at least one line break, but respect an extra empty line
   749  		// in the source
   750  		if p.linebreak(yline, 1, ws, true) > 0 {
   751  			ws = ignore
   752  			printBlank = false // no blank after line break
   753  		}
   754  	}
   755  	if printBlank {
   756  		p.print(blank)
   757  	}
   758  	p.expr1(x.Y, prec+1, depth+1)
   759  	if ws == ignore {
   760  		p.print(unindent)
   761  	}
   762  }
   763  
   764  func isBinary(expr ast.Expr) bool {
   765  	_, ok := expr.(*ast.BinaryExpr)
   766  	return ok
   767  }
   768  
   769  func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
   770  	p.print(expr.Pos())
   771  
   772  	switch x := expr.(type) {
   773  	case *ast.BadExpr:
   774  		p.print("BadExpr")
   775  
   776  	case *ast.Ident:
   777  		p.print(x)
   778  
   779  	case *ast.BinaryExpr:
   780  		if depth < 1 {
   781  			p.internalError("depth < 1:", depth)
   782  			depth = 1
   783  		}
   784  		if v, ok := x.Y.(*ast.BasicLit); ok && v.Kind == token.RAT {
   785  			depth++
   786  		}
   787  		p.binaryExpr(x, prec1, cutoff(x, depth), depth)
   788  
   789  	case *ast.KeyValueExpr:
   790  		p.expr(x.Key)
   791  		p.print(x.Colon, token.COLON, blank)
   792  		p.expr(x.Value)
   793  
   794  	case *ast.StarExpr:
   795  		const prec = token.UnaryPrec
   796  		if prec < prec1 {
   797  			// parenthesis needed
   798  			p.print(token.LPAREN)
   799  			p.print(token.MUL)
   800  			p.expr(x.X)
   801  			p.print(token.RPAREN)
   802  		} else {
   803  			// no parenthesis needed
   804  			p.print(token.MUL)
   805  			p.expr(x.X)
   806  		}
   807  
   808  	case *ast.UnaryExpr:
   809  		const prec = token.UnaryPrec
   810  		if prec < prec1 {
   811  			// parenthesis needed
   812  			p.print(token.LPAREN)
   813  			p.expr(x)
   814  			p.print(token.RPAREN)
   815  		} else {
   816  			// no parenthesis needed
   817  			p.print(x.Op)
   818  			if x.Op == token.RANGE {
   819  				// TODO(gri) Remove this code if it cannot be reached.
   820  				p.print(blank)
   821  			}
   822  			p.expr1(x.X, prec, depth)
   823  		}
   824  
   825  	case *ast.BasicLit:
   826  		p.print(x)
   827  
   828  	case *ast.FuncLit:
   829  		p.print(x.Type.Pos(), token.FUNC)
   830  		// See the comment in funcDecl about how the header size is computed.
   831  		startCol := p.out.Column - len("func")
   832  		p.signature(x.Type.Params, x.Type.Results)
   833  		p.funcBody(p.distanceFrom(x.Type.Pos(), startCol), blank, x.Body)
   834  
   835  	case *ast.ParenExpr:
   836  		if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
   837  			// don't print parentheses around an already parenthesized expression
   838  			// TODO(gri) consider making this more general and incorporate precedence levels
   839  			p.expr0(x.X, depth)
   840  		} else {
   841  			p.print(token.LPAREN)
   842  			p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
   843  			p.print(x.Rparen, token.RPAREN)
   844  		}
   845  
   846  	case *ast.SelectorExpr:
   847  		p.selectorExpr(x, depth, false)
   848  
   849  	case *ast.TypeAssertExpr:
   850  		p.expr1(x.X, token.HighestPrec, depth)
   851  		p.print(token.PERIOD, x.Lparen, token.LPAREN)
   852  		if x.Type != nil {
   853  			p.expr(x.Type)
   854  		} else {
   855  			p.print(token.TYPE)
   856  		}
   857  		p.print(x.Rparen, token.RPAREN)
   858  
   859  	case *ast.IndexExpr:
   860  		// TODO(gri): should treat[] like parentheses and undo one level of depth
   861  		p.expr1(x.X, token.HighestPrec, 1)
   862  		p.print(x.Lbrack, token.LBRACK)
   863  		p.expr0(x.Index, depth+1)
   864  		p.print(x.Rbrack, token.RBRACK)
   865  
   866  	case *ast.IndexListExpr:
   867  		// TODO(gri): should treat[] like parentheses and undo one level of depth
   868  		p.expr1(x.X, token.HighestPrec, 1)
   869  		p.print(x.Lbrack, token.LBRACK)
   870  		p.exprList(x.Lbrack, x.Indices, depth+1, commaTerm, x.Rbrack, false)
   871  		p.print(x.Rbrack, token.RBRACK)
   872  
   873  	case *ast.SliceExpr:
   874  		// TODO(gri): should treat[] like parentheses and undo one level of depth
   875  		p.expr1(x.X, token.HighestPrec, 1)
   876  		p.print(x.Lbrack, token.LBRACK)
   877  		indices := []ast.Expr{x.Low, x.High}
   878  		if x.Max != nil {
   879  			indices = append(indices, x.Max)
   880  		}
   881  		// determine if we need extra blanks around ':'
   882  		var needsBlanks bool
   883  		if depth <= 1 {
   884  			var indexCount int
   885  			var hasBinaries bool
   886  			for _, x := range indices {
   887  				if x != nil {
   888  					indexCount++
   889  					if isBinary(x) {
   890  						hasBinaries = true
   891  					}
   892  				}
   893  			}
   894  			if indexCount > 1 && hasBinaries {
   895  				needsBlanks = true
   896  			}
   897  		}
   898  		for i, x := range indices {
   899  			if i > 0 {
   900  				if indices[i-1] != nil && needsBlanks {
   901  					p.print(blank)
   902  				}
   903  				p.print(token.COLON)
   904  				if x != nil && needsBlanks {
   905  					p.print(blank)
   906  				}
   907  			}
   908  			if x != nil {
   909  				p.expr0(x, depth+1)
   910  			}
   911  		}
   912  		p.print(x.Rbrack, token.RBRACK)
   913  
   914  	case *ast.CallExpr:
   915  		if len(x.Args) > 1 {
   916  			depth++
   917  		}
   918  		var wasIndented bool
   919  		if _, ok := x.Fun.(*ast.FuncType); ok {
   920  			// conversions to literal function types require parentheses around the type
   921  			p.print(token.LPAREN)
   922  			wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
   923  			p.print(token.RPAREN)
   924  		} else {
   925  			wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
   926  		}
   927  		if x.NoParenEnd != token.NoPos {
   928  			p.print(blank)
   929  			depth++
   930  		} else {
   931  			p.print(x.Lparen, token.LPAREN)
   932  		}
   933  		if x.Ellipsis.IsValid() {
   934  			p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
   935  			p.print(x.Ellipsis, token.ELLIPSIS)
   936  			if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
   937  				p.print(token.COMMA, formfeed)
   938  			}
   939  		} else {
   940  			p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
   941  		}
   942  		if x.NoParenEnd == token.NoPos {
   943  			p.print(x.Rparen, token.RPAREN)
   944  		}
   945  		if wasIndented {
   946  			p.print(unindent)
   947  		}
   948  
   949  	case *ast.CompositeLit:
   950  		// composite literal elements that are composite literals themselves may have the type omitted
   951  		if x.Type != nil {
   952  			p.expr1(x.Type, token.HighestPrec, depth)
   953  		}
   954  		p.level++
   955  		p.print(x.Lbrace, token.LBRACE)
   956  		p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace, x.Incomplete)
   957  		// do not insert extra line break following a /*-style comment
   958  		// before the closing '}' as it might break the code if there
   959  		// is no trailing ','
   960  		mode := noExtraLinebreak
   961  		// do not insert extra blank following a /*-style comment
   962  		// before the closing '}' unless the literal is empty
   963  		if len(x.Elts) > 0 {
   964  			mode |= noExtraBlank
   965  		}
   966  		// need the initial indent to print lone comments with
   967  		// the proper level of indentation
   968  		p.print(indent, unindent, mode, x.Rbrace, token.RBRACE, mode)
   969  		p.level--
   970  
   971  	case *ast.MatrixLit:
   972  		p.level++
   973  		p.print(x.Lbrack, token.LBRACK, newline, indent)
   974  		var last = len(x.Elts) - 1
   975  		var incomplete bool
   976  		for i, elts := range x.Elts {
   977  			if i == last {
   978  				incomplete = x.Incomplete
   979  			}
   980  			p.exprList(elts[0].Pos(), elts, 1, 0, elts[len(elts)-1].End(), incomplete)
   981  			p.print(newline)
   982  		}
   983  		mode := noExtraLinebreak | noExtraBlank
   984  		// need the initial indent to print lone comments with
   985  		// the proper level of indentation
   986  		p.print(unindent, mode, x.Rbrack, token.RBRACK, mode)
   987  		p.level--
   988  
   989  	case *ast.Ellipsis:
   990  		p.print(token.ELLIPSIS)
   991  		if x.Elt != nil {
   992  			p.expr(x.Elt)
   993  		}
   994  
   995  	case *ast.ArrayType:
   996  		p.print(token.LBRACK)
   997  		if x.Len != nil {
   998  			p.expr(x.Len)
   999  		}
  1000  		p.print(token.RBRACK)
  1001  		p.expr(x.Elt)
  1002  
  1003  	case *ast.StructType:
  1004  		p.print(token.STRUCT)
  1005  		p.fieldList(x.Fields, true, x.Incomplete)
  1006  
  1007  	case *ast.FuncType:
  1008  		p.print(token.FUNC)
  1009  		p.signature(x.Params, x.Results)
  1010  
  1011  	case *ast.InterfaceType:
  1012  		p.print(token.INTERFACE)
  1013  		p.fieldList(x.Methods, false, x.Incomplete)
  1014  
  1015  	case *ast.MapType:
  1016  		p.print(token.MAP, token.LBRACK)
  1017  		p.expr(x.Key)
  1018  		p.print(token.RBRACK)
  1019  		p.expr(x.Value)
  1020  
  1021  	case *ast.ChanType:
  1022  		switch x.Dir {
  1023  		case ast.SEND | ast.RECV:
  1024  			p.print(token.CHAN)
  1025  		case ast.RECV:
  1026  			p.print(token.ARROW, token.CHAN) // x.Arrow and x.Pos() are the same
  1027  		case ast.SEND:
  1028  			p.print(token.CHAN, x.Arrow, token.ARROW)
  1029  		}
  1030  		p.print(blank)
  1031  		p.expr(x.Value)
  1032  		/*	case *ast.TernaryExpr:
  1033  			p.expr1(x.X, token.HighestPrec, 1)
  1034  			p.expr0(x.Cond, 1)
  1035  			p.print(x.Question, token.QUESTION)
  1036  			p.expr0(x.Y, depth+1)
  1037  			p.print(x.Colon, token.COLON)
  1038  			p.expr0(x.Y, depth+1)
  1039  		*/
  1040  	case *ast.SliceLit:
  1041  		p.print(token.LBRACK)
  1042  		p.exprList(x.Lbrack, x.Elts, depth+1, commaTerm, x.Rbrack, x.Incomplete)
  1043  		mode := noExtraLinebreak
  1044  		if len(x.Elts) > 0 {
  1045  			mode |= noExtraBlank
  1046  		}
  1047  		p.print(mode, x.Rbrack, token.RBRACK, mode)
  1048  
  1049  	case *ast.ComprehensionExpr:
  1050  		switch x.Tok {
  1051  		case token.LBRACK: // [...]
  1052  			p.print(token.LBRACK)
  1053  			p.expr0(x.Elt, depth+1)
  1054  			p.print(blank)
  1055  			p.listForPhrase(x.Fors)
  1056  			p.print(token.RBRACK)
  1057  		default: // {...}
  1058  			p.print(token.LBRACE)
  1059  			if x.Elt != nil {
  1060  				if elt, ok := x.Elt.(*ast.KeyValueExpr); ok {
  1061  					p.expr0(elt.Key, depth+1)
  1062  					p.print(elt.Colon, token.COLON, blank)
  1063  					p.expr0(elt.Value, depth+1)
  1064  				} else {
  1065  					p.expr0(x.Elt, depth+1)
  1066  				}
  1067  				p.print(blank)
  1068  			}
  1069  			p.listForPhrase(x.Fors)
  1070  			p.print(token.RBRACE)
  1071  		}
  1072  	case *ast.ErrWrapExpr:
  1073  		p.expr(x.X)
  1074  		p.print(x.Tok)
  1075  		if x.Default != nil {
  1076  			p.print(token.COLON)
  1077  			p.expr(x.Default)
  1078  		}
  1079  	case *ast.LambdaExpr:
  1080  		if x.LhsHasParen {
  1081  			p.print(token.LPAREN)
  1082  			p.identList(x.Lhs, false)
  1083  			p.print(token.RPAREN, blank)
  1084  		} else if x.Lhs != nil {
  1085  			p.expr(x.Lhs[0])
  1086  			p.print(blank)
  1087  		}
  1088  		p.print(token.DRARROW, blank)
  1089  		if x.RhsHasParen {
  1090  			p.print(token.LPAREN)
  1091  			p.exprList(token.NoPos, x.Rhs, 1, noIndent, token.NoPos, false)
  1092  			p.print(token.RPAREN)
  1093  		} else {
  1094  			p.expr(x.Rhs[0])
  1095  		}
  1096  
  1097  	case *ast.LambdaExpr2:
  1098  		if x.LhsHasParen {
  1099  			p.print(token.LPAREN)
  1100  			p.identList(x.Lhs, false)
  1101  			p.print(token.RPAREN, blank)
  1102  		} else if x.Lhs != nil {
  1103  			p.expr(x.Lhs[0])
  1104  			p.print(blank)
  1105  		}
  1106  		p.print(token.DRARROW, blank)
  1107  		p.block(x.Body, 1)
  1108  
  1109  	case *ast.RangeExpr:
  1110  		if x.First != nil {
  1111  			p.expr(x.First)
  1112  		}
  1113  		p.print(token.COLON)
  1114  		if x.Last != nil {
  1115  			p.expr(x.Last)
  1116  		}
  1117  		if x.Expr3 != nil {
  1118  			p.print(token.COLON)
  1119  			p.expr(x.Expr3)
  1120  		}
  1121  
  1122  	case *ast.EnvExpr:
  1123  		p.print(token.ENV)
  1124  		if x.HasBrace() {
  1125  			p.print(token.LBRACE, x.Name, token.RBRACE)
  1126  		} else {
  1127  			p.print(x.Name)
  1128  		}
  1129  
  1130  	case *ast.ElemEllipsis:
  1131  		p.expr(x.Elt)
  1132  		p.print(token.ELLIPSIS)
  1133  
  1134  	default:
  1135  		log.Fatalf("unreachable %T\n", x)
  1136  	}
  1137  }
  1138  
  1139  func (p *printer) listForPhrase(list []*ast.ForPhrase) {
  1140  	for i, x := range list {
  1141  		if i > 0 {
  1142  			p.print(blank)
  1143  		}
  1144  		p.print(token.FOR, blank)
  1145  		if x.Key != nil {
  1146  			p.expr(x.Key)
  1147  			p.print(token.COMMA, blank)
  1148  		}
  1149  		p.print(x.Value, blank)
  1150  		p.print(x.TokPos, token.ARROW, blank)
  1151  		p.expr(x.X)
  1152  		if x.Cond != nil {
  1153  			p.print(blank, x.Cond.Pos(), token.IF, blank)
  1154  			if x.Init != nil {
  1155  				p.stmt(x.Init, false)
  1156  				p.print(token.SEMICOLON, blank)
  1157  			}
  1158  			p.expr(x.Cond)
  1159  		}
  1160  	}
  1161  }
  1162  
  1163  func (p *printer) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool {
  1164  	if x, ok := expr.(*ast.SelectorExpr); ok {
  1165  		return p.selectorExpr(x, depth, true)
  1166  	}
  1167  	p.expr1(expr, prec1, depth)
  1168  	return false
  1169  }
  1170  
  1171  // selectorExpr handles an *ast.SelectorExpr node and reports whether x spans
  1172  // multiple lines.
  1173  func (p *printer) selectorExpr(x *ast.SelectorExpr, depth int, isMethod bool) bool {
  1174  	p.expr1(x.X, token.HighestPrec, depth)
  1175  	p.print(token.PERIOD)
  1176  	if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
  1177  		p.print(indent, newline, x.Sel.Pos(), x.Sel)
  1178  		if !isMethod {
  1179  			p.print(unindent)
  1180  		}
  1181  		return true
  1182  	}
  1183  	p.print(x.Sel.Pos(), x.Sel)
  1184  	return false
  1185  }
  1186  
  1187  func (p *printer) expr0(x ast.Expr, depth int) {
  1188  	p.expr1(x, token.LowestPrec, depth)
  1189  }
  1190  
  1191  func (p *printer) expr(x ast.Expr) {
  1192  	const depth = 1
  1193  	p.expr1(x, token.LowestPrec, depth)
  1194  }
  1195  
  1196  // ----------------------------------------------------------------------------
  1197  // Statements
  1198  
  1199  // Print the statement list indented, but without a newline after the last statement.
  1200  // Extra line breaks between statements in the source are respected but at most one
  1201  // empty line is printed between statements.
  1202  func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
  1203  	if nindent > 0 {
  1204  		p.print(indent)
  1205  	}
  1206  	var line int
  1207  	i := 0
  1208  	for _, s := range list {
  1209  		// ignore empty statements (was issue 3466)
  1210  		if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
  1211  			// nindent == 0 only for lists of switch/select case clauses;
  1212  			// in those cases each clause is a new section
  1213  			if len(p.output) > 0 {
  1214  				// only print line break if we are not at the beginning of the output
  1215  				// (i.e., we are not printing only a partial program)
  1216  				p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0)
  1217  			}
  1218  			p.recordLine(&line)
  1219  			p.stmt(s, nextIsRBrace && i == len(list)-1)
  1220  			// labeled statements put labels on a separate line, but here
  1221  			// we only care about the start line of the actual statement
  1222  			// without label - correct line for each label
  1223  			for t := s; ; {
  1224  				lt, _ := t.(*ast.LabeledStmt)
  1225  				if lt == nil {
  1226  					break
  1227  				}
  1228  				line++
  1229  				t = lt.Stmt
  1230  			}
  1231  			i++
  1232  		}
  1233  	}
  1234  	if nindent > 0 {
  1235  		p.print(unindent)
  1236  	}
  1237  }
  1238  
  1239  // block prints an *ast.BlockStmt; it always spans at least two lines.
  1240  func (p *printer) block(b *ast.BlockStmt, nindent int) {
  1241  	p.print(b.Lbrace, token.LBRACE)
  1242  	p.stmtList(b.List, nindent, true)
  1243  	p.linebreak(p.lineFor(b.Rbrace), 1, ignore, true)
  1244  	p.print(b.Rbrace, token.RBRACE)
  1245  }
  1246  
  1247  func isTypeName(x ast.Expr) bool {
  1248  	switch t := x.(type) {
  1249  	case *ast.Ident:
  1250  		return true
  1251  	case *ast.SelectorExpr:
  1252  		return isTypeName(t.X)
  1253  	}
  1254  	return false
  1255  }
  1256  
  1257  func stripParens(x ast.Expr) ast.Expr {
  1258  	if px, strip := x.(*ast.ParenExpr); strip {
  1259  		// parentheses must not be stripped if there are any
  1260  		// unparenthesized composite literals starting with
  1261  		// a type name
  1262  		ast.Inspect(px.X, func(node ast.Node) bool {
  1263  			switch x := node.(type) {
  1264  			case *ast.ParenExpr:
  1265  				// parentheses protect enclosed composite literals
  1266  				return false
  1267  			case *ast.CompositeLit:
  1268  				if isTypeName(x.Type) {
  1269  					strip = false // do not strip parentheses
  1270  				}
  1271  				return false
  1272  			}
  1273  			// in all other cases, keep inspecting
  1274  			return true
  1275  		})
  1276  		if strip {
  1277  			return stripParens(px.X)
  1278  		}
  1279  	}
  1280  	return x
  1281  }
  1282  
  1283  func stripParensAlways(x ast.Expr) ast.Expr {
  1284  	if x, ok := x.(*ast.ParenExpr); ok {
  1285  		return stripParensAlways(x.X)
  1286  	}
  1287  	return x
  1288  }
  1289  
  1290  func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
  1291  	p.print(blank)
  1292  	needsBlank := false
  1293  	if init == nil && post == nil {
  1294  		// no semicolons required
  1295  		if expr != nil {
  1296  			p.expr(stripParens(expr))
  1297  			needsBlank = true
  1298  		}
  1299  	} else {
  1300  		// all semicolons required
  1301  		// (they are not separators, print them explicitly)
  1302  		if init != nil {
  1303  			p.stmt(init, false)
  1304  		}
  1305  		p.print(token.SEMICOLON, blank)
  1306  		if expr != nil {
  1307  			p.expr(stripParens(expr))
  1308  			needsBlank = true
  1309  		}
  1310  		if isForStmt {
  1311  			p.print(token.SEMICOLON, blank)
  1312  			needsBlank = false
  1313  			if post != nil {
  1314  				p.stmt(post, false)
  1315  				needsBlank = true
  1316  			}
  1317  		}
  1318  	}
  1319  	if needsBlank {
  1320  		p.print(blank)
  1321  	}
  1322  }
  1323  
  1324  // indentList reports whether an expression list would look better if it
  1325  // were indented wholesale (starting with the very first element, rather
  1326  // than starting at the first line break).
  1327  func (p *printer) indentList(list []ast.Expr) bool {
  1328  	// Heuristic: indentList reports whether there are more than one multi-
  1329  	// line element in the list, or if there is any element that is not
  1330  	// starting on the same line as the previous one ends.
  1331  	if len(list) >= 2 {
  1332  		var b = p.lineFor(list[0].Pos())
  1333  		var e = p.lineFor(list[len(list)-1].End())
  1334  		if 0 < b && b < e {
  1335  			// list spans multiple lines
  1336  			n := 0 // multi-line element count
  1337  			line := b
  1338  			for _, x := range list {
  1339  				xb := p.lineFor(x.Pos())
  1340  				xe := p.lineFor(x.End())
  1341  				if line < xb {
  1342  					// x is not starting on the same
  1343  					// line as the previous one ended
  1344  					return true
  1345  				}
  1346  				if xb < xe {
  1347  					// x is a multi-line element
  1348  					n++
  1349  				}
  1350  				line = xe
  1351  			}
  1352  			return n > 1
  1353  		}
  1354  	}
  1355  	return false
  1356  }
  1357  
  1358  func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
  1359  	p.print(stmt.Pos())
  1360  
  1361  	switch s := stmt.(type) {
  1362  	case *ast.BadStmt:
  1363  		p.print("BadStmt")
  1364  
  1365  	case *ast.DeclStmt:
  1366  		p.decl(s.Decl)
  1367  
  1368  	case *ast.EmptyStmt:
  1369  		// nothing to do
  1370  
  1371  	case *ast.LabeledStmt:
  1372  		// a "correcting" unindent immediately following a line break
  1373  		// is applied before the line break if there is no comment
  1374  		// between (see writeWhitespace)
  1375  		p.print(unindent)
  1376  		p.expr(s.Label)
  1377  		p.print(s.Colon, token.COLON, indent)
  1378  		if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
  1379  			if !nextIsRBrace {
  1380  				p.print(newline, e.Pos(), token.SEMICOLON)
  1381  				break
  1382  			}
  1383  		} else {
  1384  			p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
  1385  		}
  1386  		p.stmt(s.Stmt, nextIsRBrace)
  1387  
  1388  	case *ast.ExprStmt:
  1389  		if debugFormat {
  1390  			if e, ok := s.X.(*ast.CallExpr); ok {
  1391  				log.Println("==> ExprStmt", e.Fun)
  1392  			}
  1393  		}
  1394  		const depth = 1
  1395  		p.expr0(s.X, depth)
  1396  
  1397  	case *ast.SendStmt:
  1398  		const depth = 1
  1399  		p.expr0(s.Chan, depth)
  1400  		p.print(blank, s.Arrow, token.ARROW, blank)
  1401  		p.expr0(s.Value, depth)
  1402  
  1403  	case *ast.IncDecStmt:
  1404  		const depth = 1
  1405  		p.expr0(s.X, depth+1)
  1406  		p.print(s.TokPos, s.Tok)
  1407  
  1408  	case *ast.AssignStmt:
  1409  		if debugFormat {
  1410  			log.Println("==> AssignStmt", s.Lhs)
  1411  		}
  1412  		var depth = 1
  1413  		if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
  1414  			depth++
  1415  		}
  1416  		p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos, false)
  1417  		p.print(blank, s.TokPos, s.Tok, blank)
  1418  		p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos, false)
  1419  
  1420  	case *ast.GoStmt:
  1421  		p.print(token.GO, blank)
  1422  		p.expr(s.Call)
  1423  
  1424  	case *ast.DeferStmt:
  1425  		p.print(token.DEFER, blank)
  1426  		p.expr(s.Call)
  1427  
  1428  	case *ast.ReturnStmt:
  1429  		p.print(token.RETURN)
  1430  		if s.Results != nil {
  1431  			p.print(blank)
  1432  			// Use indentList heuristic to make corner cases look
  1433  			// better (issue 1207). A more systematic approach would
  1434  			// always indent, but this would cause significant
  1435  			// reformatting of the code base and not necessarily
  1436  			// lead to more nicely formatted code in general.
  1437  			if p.indentList(s.Results) {
  1438  				p.print(indent)
  1439  				// Use NoPos so that a newline never goes before
  1440  				// the results (see issue #32854).
  1441  				p.exprList(token.NoPos, s.Results, 1, noIndent, token.NoPos, false)
  1442  				p.print(unindent)
  1443  			} else {
  1444  				p.exprList(token.NoPos, s.Results, 1, 0, token.NoPos, false)
  1445  			}
  1446  		}
  1447  
  1448  	case *ast.BranchStmt:
  1449  		p.print(s.Tok)
  1450  		if s.Label != nil {
  1451  			p.print(blank)
  1452  			p.expr(s.Label)
  1453  		}
  1454  
  1455  	case *ast.BlockStmt:
  1456  		p.block(s, 1)
  1457  
  1458  	case *ast.IfStmt:
  1459  		p.print(token.IF)
  1460  		p.controlClause(false, s.Init, s.Cond, nil)
  1461  		p.block(s.Body, 1)
  1462  		if s.Else != nil {
  1463  			p.print(blank, token.ELSE, blank)
  1464  			switch s.Else.(type) {
  1465  			case *ast.BlockStmt, *ast.IfStmt:
  1466  				p.stmt(s.Else, nextIsRBrace)
  1467  			default:
  1468  				// This can only happen with an incorrectly
  1469  				// constructed AST. Permit it but print so
  1470  				// that it can be parsed without errors.
  1471  				p.print(token.LBRACE, indent, formfeed)
  1472  				p.stmt(s.Else, true)
  1473  				p.print(unindent, formfeed, token.RBRACE)
  1474  			}
  1475  		}
  1476  
  1477  	case *ast.CaseClause:
  1478  		if s.List != nil {
  1479  			p.print(token.CASE, blank)
  1480  			p.exprList(s.Pos(), s.List, 1, 0, s.Colon, false)
  1481  		} else {
  1482  			p.print(token.DEFAULT)
  1483  		}
  1484  		p.print(s.Colon, token.COLON)
  1485  		p.stmtList(s.Body, 1, nextIsRBrace)
  1486  
  1487  	case *ast.SwitchStmt:
  1488  		p.print(token.SWITCH)
  1489  		p.controlClause(false, s.Init, s.Tag, nil)
  1490  		p.block(s.Body, 0)
  1491  
  1492  	case *ast.TypeSwitchStmt:
  1493  		p.print(token.SWITCH)
  1494  		if s.Init != nil {
  1495  			p.print(blank)
  1496  			p.stmt(s.Init, false)
  1497  			p.print(token.SEMICOLON)
  1498  		}
  1499  		p.print(blank)
  1500  		p.stmt(s.Assign, false)
  1501  		p.print(blank)
  1502  		p.block(s.Body, 0)
  1503  
  1504  	case *ast.CommClause:
  1505  		if s.Comm != nil {
  1506  			p.print(token.CASE, blank)
  1507  			p.stmt(s.Comm, false)
  1508  		} else {
  1509  			p.print(token.DEFAULT)
  1510  		}
  1511  		p.print(s.Colon, token.COLON)
  1512  		p.stmtList(s.Body, 1, nextIsRBrace)
  1513  
  1514  	case *ast.SelectStmt:
  1515  		p.print(token.SELECT, blank)
  1516  		body := s.Body
  1517  		if len(body.List) == 0 && !p.commentBefore(p.posFor(body.Rbrace)) {
  1518  			// print empty select statement w/o comments on one line
  1519  			p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
  1520  		} else {
  1521  			p.block(body, 0)
  1522  		}
  1523  
  1524  	case *ast.ForStmt:
  1525  		p.print(token.FOR)
  1526  		p.controlClause(true, s.Init, s.Cond, s.Post)
  1527  		p.block(s.Body, 1)
  1528  
  1529  	case *ast.RangeStmt:
  1530  		p.print(token.FOR, blank)
  1531  		if s.Key != nil {
  1532  			p.expr(s.Key)
  1533  			if s.Value != nil {
  1534  				// use position of value following the comma as
  1535  				// comma position for correct comment placement
  1536  				p.print(s.Value.Pos(), token.COMMA, blank)
  1537  				p.expr(s.Value)
  1538  			}
  1539  			p.print(blank, s.TokPos, s.Tok, blank)
  1540  		}
  1541  		if !s.NoRangeOp {
  1542  			p.print(token.RANGE, blank)
  1543  		}
  1544  		p.expr(stripParens(s.X))
  1545  		p.print(blank)
  1546  		p.block(s.Body, 1)
  1547  	case *ast.ForPhraseStmt:
  1548  		p.print(token.FOR, blank)
  1549  		if s.Key != nil {
  1550  			p.expr(s.Key)
  1551  			p.print(token.COMMA, blank)
  1552  		}
  1553  		p.expr(s.Value)
  1554  		p.print(blank, s.TokPos, token.ARROW, blank)
  1555  		p.expr(s.X)
  1556  		if s.Cond != nil {
  1557  			p.print(blank, s.Cond.Pos(), token.IF, blank)
  1558  			p.expr(s.Cond)
  1559  		}
  1560  		p.print(blank)
  1561  		p.block(s.Body, 1)
  1562  	case *NewlineStmt:
  1563  		p.print(ignore)
  1564  	default:
  1565  		log.Printf("unreachable %T\n", s)
  1566  	}
  1567  }
  1568  
  1569  // NewlineStmt represents a statement that formats as a newline
  1570  type NewlineStmt struct {
  1571  	ast.EmptyStmt
  1572  }
  1573  
  1574  // ----------------------------------------------------------------------------
  1575  // Declarations
  1576  
  1577  // The keepTypeColumn function determines if the type column of a series of
  1578  // consecutive const or var declarations must be kept, or if initialization
  1579  // values (V) can be placed in the type column (T) instead. The i'th entry
  1580  // in the result slice is true if the type column in spec[i] must be kept.
  1581  //
  1582  // For example, the declaration:
  1583  //
  1584  //		const (
  1585  //			foobar int = 42 // comment
  1586  //			x          = 7  // comment
  1587  //			foo
  1588  //	             bar = 991
  1589  //		)
  1590  //
  1591  // leads to the type/values matrix below. A run of value columns (V) can
  1592  // be moved into the type column if there is no type for any of the values
  1593  // in that column (we only move entire columns so that they align properly).
  1594  //
  1595  //		matrix        formatted     result
  1596  //	                   matrix
  1597  //		T  V    ->    T  V     ->   true      there is a T and so the type
  1598  //		-  V          -  V          true      column must be kept
  1599  //		-  -          -  -          false
  1600  //		-  V          V  -          false     V is moved into T column
  1601  func keepTypeColumn(specs []ast.Spec) []bool {
  1602  	m := make([]bool, len(specs))
  1603  
  1604  	populate := func(i, j int, keepType bool) {
  1605  		if keepType {
  1606  			for ; i < j; i++ {
  1607  				m[i] = true
  1608  			}
  1609  		}
  1610  	}
  1611  
  1612  	i0 := -1 // if i0 >= 0 we are in a run and i0 is the start of the run
  1613  	var keepType bool
  1614  	for i, s := range specs {
  1615  		t := s.(*ast.ValueSpec)
  1616  		if t.Values != nil {
  1617  			if i0 < 0 {
  1618  				// start of a run of ValueSpecs with non-nil Values
  1619  				i0 = i
  1620  				keepType = false
  1621  			}
  1622  		} else {
  1623  			if i0 >= 0 {
  1624  				// end of a run
  1625  				populate(i0, i, keepType)
  1626  				i0 = -1
  1627  			}
  1628  		}
  1629  		if t.Type != nil {
  1630  			keepType = true
  1631  		}
  1632  	}
  1633  	if i0 >= 0 {
  1634  		// end of a run
  1635  		populate(i0, len(specs), keepType)
  1636  	}
  1637  
  1638  	return m
  1639  }
  1640  
  1641  func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
  1642  	p.setComment(s.Doc)
  1643  	p.identList(s.Names, false) // always present
  1644  	extraTabs := 3
  1645  	if s.Type != nil || keepType {
  1646  		if len(s.Names) > 0 {
  1647  			p.print(vtab)
  1648  		}
  1649  		extraTabs--
  1650  	}
  1651  	if s.Type != nil {
  1652  		p.expr(s.Type)
  1653  	}
  1654  	if s.Tag != nil {
  1655  		if len(s.Names) > 0 {
  1656  			p.print(vtab)
  1657  		}
  1658  		p.print(vtab)
  1659  		p.expr(s.Tag)
  1660  		extraTabs--
  1661  	}
  1662  	if s.Values != nil {
  1663  		p.print(vtab, token.ASSIGN, blank)
  1664  		p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
  1665  		extraTabs--
  1666  	}
  1667  	if s.Comment != nil {
  1668  		for ; extraTabs > 0; extraTabs-- {
  1669  			p.print(vtab)
  1670  		}
  1671  		p.setComment(s.Comment)
  1672  	}
  1673  }
  1674  
  1675  func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
  1676  	// Note: An unmodified AST generated by go/parser will already
  1677  	// contain a backward- or double-quoted path string that does
  1678  	// not contain any invalid characters, and most of the work
  1679  	// here is not needed. However, a modified or generated AST
  1680  	// may possibly contain non-canonical paths. Do the work in
  1681  	// all cases since it's not too hard and not speed-critical.
  1682  
  1683  	// if we don't have a proper string, be conservative and return whatever we have
  1684  	if lit.Kind != token.STRING {
  1685  		return lit
  1686  	}
  1687  	s, err := strconv.Unquote(lit.Value)
  1688  	if err != nil {
  1689  		return lit
  1690  	}
  1691  
  1692  	// if the string is an invalid path, return whatever we have
  1693  	//
  1694  	// spec: "Implementation restriction: A compiler may restrict
  1695  	// ImportPaths to non-empty strings using only characters belonging
  1696  	// to Unicode's L, M, N, P, and S general categories (the Graphic
  1697  	// characters without spaces) and may also exclude the characters
  1698  	// !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character
  1699  	// U+FFFD."
  1700  	if s == "" {
  1701  		return lit
  1702  	}
  1703  	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
  1704  	for _, r := range s {
  1705  		if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
  1706  			return lit
  1707  		}
  1708  	}
  1709  
  1710  	// otherwise, return the double-quoted path
  1711  	s = strconv.Quote(s)
  1712  	if s == lit.Value {
  1713  		return lit // nothing wrong with lit
  1714  	}
  1715  	return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
  1716  }
  1717  
  1718  // The parameter n is the number of specs in the group. If doIndent is set,
  1719  // multi-line identifier lists in the spec are indented when the first
  1720  // linebreak is encountered.
  1721  func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
  1722  	switch s := spec.(type) {
  1723  	case *ast.ImportSpec:
  1724  		p.setComment(s.Doc)
  1725  		if s.Name != nil {
  1726  			p.expr(s.Name)
  1727  			p.print(blank)
  1728  		}
  1729  		p.expr(sanitizeImportPath(s.Path))
  1730  		p.setComment(s.Comment)
  1731  		p.print(s.EndPos)
  1732  
  1733  	case *ast.ValueSpec:
  1734  		if n != 1 {
  1735  			p.internalError("expected n = 1; got", n)
  1736  		}
  1737  		p.setComment(s.Doc)
  1738  		p.identList(s.Names, doIndent) // always present
  1739  		if s.Type != nil {
  1740  			if len(s.Names) > 0 {
  1741  				p.print(blank)
  1742  			}
  1743  			p.expr(s.Type)
  1744  		}
  1745  		if s.Values != nil {
  1746  			p.print(blank, token.ASSIGN, blank)
  1747  			p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
  1748  		}
  1749  		p.setComment(s.Comment)
  1750  
  1751  	case *ast.TypeSpec:
  1752  		p.setComment(s.Doc)
  1753  		p.expr(s.Name)
  1754  		if n == 1 {
  1755  			p.print(blank)
  1756  		} else {
  1757  			p.print(vtab)
  1758  		}
  1759  		if s.Assign.IsValid() {
  1760  			p.print(token.ASSIGN, blank)
  1761  		}
  1762  		p.expr(s.Type)
  1763  		p.setComment(s.Comment)
  1764  
  1765  	default:
  1766  		panic("unreachable")
  1767  	}
  1768  }
  1769  
  1770  func (p *printer) genDecl(d *ast.GenDecl) {
  1771  	p.setComment(d.Doc)
  1772  	p.setPos(d.Pos())
  1773  	p.print(d.Tok, blank)
  1774  
  1775  	if d.Lparen.IsValid() || len(d.Specs) > 1 {
  1776  		// group of parenthesized declarations
  1777  		p.setPos(d.Lparen)
  1778  		p.print(token.LPAREN)
  1779  		if n := len(d.Specs); n > 0 {
  1780  			p.print(indent, formfeed)
  1781  			if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
  1782  				// two or more grouped const/var declarations:
  1783  				// determine if the type column must be kept
  1784  				keepType := keepTypeColumn(d.Specs)
  1785  				var line int
  1786  				for i, s := range d.Specs {
  1787  					if i > 0 {
  1788  						p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
  1789  					}
  1790  					p.recordLine(&line)
  1791  					p.valueSpec(s.(*ast.ValueSpec), keepType[i])
  1792  				}
  1793  			} else {
  1794  				var line int
  1795  				for i, s := range d.Specs {
  1796  					if i > 0 {
  1797  						p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
  1798  					}
  1799  					p.recordLine(&line)
  1800  					p.spec(s, n, false)
  1801  				}
  1802  			}
  1803  			p.print(unindent, formfeed)
  1804  		}
  1805  		p.setPos(d.Rparen)
  1806  		p.print(token.RPAREN)
  1807  
  1808  	} else if len(d.Specs) > 0 {
  1809  		// single declaration
  1810  		p.spec(d.Specs[0], 1, true)
  1811  	}
  1812  }
  1813  
  1814  // nodeSize determines the size of n in chars after formatting.
  1815  // The result is <= maxSize if the node fits on one line with at
  1816  // most maxSize chars and the formatted output doesn't contain
  1817  // any control chars. Otherwise, the result is > maxSize.
  1818  func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
  1819  	// nodeSize invokes the printer, which may invoke nodeSize
  1820  	// recursively. For deep composite literal nests, this can
  1821  	// lead to an exponential algorithm. Remember previous
  1822  	// results to prune the recursion (was issue 1628).
  1823  	if size, found := p.nodeSizes[n]; found {
  1824  		return size
  1825  	}
  1826  
  1827  	size = maxSize + 1 // assume n doesn't fit
  1828  	p.nodeSizes[n] = size
  1829  
  1830  	// nodeSize computation must be independent of particular
  1831  	// style so that we always get the same decision; print
  1832  	// in RawFormat
  1833  	cfg := Config{Mode: RawFormat}
  1834  	var buf bytes.Buffer
  1835  	if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
  1836  		return
  1837  	}
  1838  	if buf.Len() <= maxSize {
  1839  		for _, ch := range buf.Bytes() {
  1840  			if ch < ' ' {
  1841  				return
  1842  			}
  1843  		}
  1844  		size = buf.Len() // n fits
  1845  		p.nodeSizes[n] = size
  1846  	}
  1847  	return
  1848  }
  1849  
  1850  // numLines returns the number of lines spanned by node n in the original source.
  1851  func (p *printer) numLines(n ast.Node) int {
  1852  	if from := n.Pos(); from.IsValid() {
  1853  		if to := n.End(); to.IsValid() {
  1854  			return p.lineFor(to) - p.lineFor(from) + 1
  1855  		}
  1856  	}
  1857  	return infinity
  1858  }
  1859  
  1860  // bodySize is like nodeSize but it is specialized for *ast.BlockStmt's.
  1861  func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
  1862  	pos1 := b.Pos()
  1863  	pos2 := b.Rbrace
  1864  	if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
  1865  		// opening and closing brace are on different lines - don't make it a one-liner
  1866  		return maxSize + 1
  1867  	}
  1868  	if len(b.List) > 5 {
  1869  		// too many statements - don't make it a one-liner
  1870  		return maxSize + 1
  1871  	}
  1872  	// otherwise, estimate body size
  1873  	bodySize := p.commentSizeBefore(p.posFor(pos2))
  1874  	for i, s := range b.List {
  1875  		if bodySize > maxSize {
  1876  			break // no need to continue
  1877  		}
  1878  		if i > 0 {
  1879  			bodySize += 2 // space for a semicolon and blank
  1880  		}
  1881  		bodySize += p.nodeSize(s, maxSize)
  1882  	}
  1883  	return bodySize
  1884  }
  1885  
  1886  // funcBody prints a function body following a function header of given headerSize.
  1887  // If the header's and block's size are "small enough" and the block is "simple enough",
  1888  // the block is printed on the current line, without line breaks, spaced from the header
  1889  // by sep. Otherwise the block's opening "{" is printed on the current line, followed by
  1890  // lines for the block's statements and its closing "}".
  1891  func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
  1892  	if b == nil {
  1893  		return
  1894  	}
  1895  
  1896  	// save/restore composite literal nesting level
  1897  	defer func(level int) {
  1898  		p.level = level
  1899  	}(p.level)
  1900  	p.level = 0
  1901  
  1902  	const maxSize = 100
  1903  	if headerSize+p.bodySize(b, maxSize) <= maxSize {
  1904  		p.print(sep, b.Lbrace, token.LBRACE)
  1905  		if len(b.List) > 0 {
  1906  			p.print(blank)
  1907  			for i, s := range b.List {
  1908  				if i > 0 {
  1909  					p.print(token.SEMICOLON, blank)
  1910  				}
  1911  				p.stmt(s, i == len(b.List)-1)
  1912  			}
  1913  			p.print(blank)
  1914  		}
  1915  		p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
  1916  		return
  1917  	}
  1918  
  1919  	if sep != ignore {
  1920  		p.print(blank) // always use blank
  1921  	}
  1922  	p.block(b, 1)
  1923  }
  1924  
  1925  // funcBodyUnnamed prints a function body following a function header of given headerSize.
  1926  // If the header's and block's size are "small enough" and the block is "simple enough",
  1927  // the block is printed on the current line, without line breaks, spaced from the header
  1928  // by sep. Otherwise the block's opening "{" is printed on the current line, followed by
  1929  // lines for the block's statements and its closing "}".
  1930  func (p *printer) funcBodyUnnamed(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
  1931  	_, _ = headerSize, sep
  1932  	if b == nil {
  1933  		return
  1934  	}
  1935  
  1936  	// save/restore composite literal nesting level
  1937  	defer func(level int) {
  1938  		p.level = level
  1939  	}(p.level)
  1940  	p.level = 0
  1941  
  1942  	// const maxSize = 100
  1943  	// if headerSize+p.bodySize(b, maxSize) <= maxSize {
  1944  	// 	if len(b.List) > 0 {
  1945  	// 		p.print(blank)
  1946  	// 		for i, s := range b.List {
  1947  	// 			if i > 0 {
  1948  	// 				p.print(token.SEMICOLON, blank)
  1949  	// 			}
  1950  	// 			p.stmt(s, i == len(b.List)-1)
  1951  	// 		}
  1952  	// 		p.print(blank)
  1953  	// 	}
  1954  	// 	return
  1955  	// }
  1956  
  1957  	/*	if sep != ignore {
  1958  			//	p.print(blank) // always use blank
  1959  		}
  1960  	*/
  1961  	var line int
  1962  	i := 0
  1963  	for _, s := range b.List {
  1964  		// ignore empty statements (was issue 3466)
  1965  		if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
  1966  			// nindent == 0 only for lists of switch/select case clauses;
  1967  			// in those cases each clause is a new section
  1968  			if len(p.output) > 0 && i > 0 {
  1969  				// only print line break if we are not at the beginning of the output
  1970  				// (i.e., we are not printing only a partial program)
  1971  				p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
  1972  			}
  1973  			p.recordLine(&line)
  1974  			p.stmt(s, true && i == len(b.List)-1)
  1975  			// labeled statements put labels on a separate line, but here
  1976  			// we only care about the start line of the actual statement
  1977  			// without label - correct line for each label
  1978  			for t := s; ; {
  1979  				lt, _ := t.(*ast.LabeledStmt)
  1980  				if lt == nil {
  1981  					break
  1982  				}
  1983  				line++
  1984  				t = lt.Stmt
  1985  			}
  1986  			i++
  1987  		}
  1988  	}
  1989  }
  1990  
  1991  // distanceFrom returns the column difference between p.out (the current output
  1992  // position) and startOutCol. If the start position is on a different line from
  1993  // the current position (or either is unknown), the result is infinity.
  1994  func (p *printer) distanceFrom(startPos token.Pos, startOutCol int) int {
  1995  	if startPos.IsValid() && p.pos.IsValid() && p.posFor(startPos).Line == p.pos.Line {
  1996  		return p.out.Column - startOutCol
  1997  	}
  1998  	return infinity
  1999  }
  2000  
  2001  func (p *printer) funcDecl(d *ast.FuncDecl) {
  2002  	if debugFormat {
  2003  		log.Println("==> Format Func", d.Name.Name)
  2004  	}
  2005  	p.setComment(d.Doc)
  2006  
  2007  	if p.shadowEntry == d {
  2008  		p.funcBodyUnnamed(0, vtab, d.Body)
  2009  		return
  2010  	}
  2011  
  2012  	pos := d.Pos()
  2013  	p.print(pos, token.FUNC, blank)
  2014  	// We have to save startCol only after emitting FUNC; otherwise it can be on a
  2015  	// different line (all whitespace preceding the FUNC is emitted only when the
  2016  	// FUNC is emitted).
  2017  	startCol := p.out.Column - len("func ")
  2018  	if d.Recv != nil {
  2019  		if d.Static { // static method
  2020  			if !d.IsClass {
  2021  				if list := d.Recv.List; len(list) > 0 {
  2022  					p.expr(list[0].Type)
  2023  				}
  2024  			}
  2025  			p.print(token.PERIOD)
  2026  		} else if !d.IsClass {
  2027  			p.parameters(d.Recv) // method: print receiver
  2028  			p.print(blank)
  2029  		}
  2030  	}
  2031  	p.expr(d.Name)
  2032  	if d.Operator && d.Recv != nil {
  2033  		p.print(blank)
  2034  	}
  2035  	p.signature(d.Type.Params, d.Type.Results)
  2036  	p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
  2037  }
  2038  
  2039  func (p *printer) overloadFuncDecl(d *ast.OverloadFuncDecl) {
  2040  	if debugFormat {
  2041  		log.Println("==> Format OverloadFunc", d.Name.Name)
  2042  	}
  2043  	p.setComment(d.Doc)
  2044  
  2045  	pos := d.Pos()
  2046  	p.print(pos, token.FUNC, blank)
  2047  	if d.Recv != nil && !d.IsClass {
  2048  		p.parameters(d.Recv) // method: print receiver
  2049  		p.print(token.PERIOD)
  2050  	}
  2051  	p.expr(d.Name)
  2052  	p.print(blank, token.ASSIGN, blank, token.LPAREN, newline)
  2053  	for _, fn := range d.Funcs {
  2054  		p.print(indent)
  2055  		p.expr1(fn, token.LowestPrec, 1)
  2056  		p.print(unindent, newline)
  2057  	}
  2058  	p.print(token.RPAREN)
  2059  }
  2060  
  2061  func (p *printer) decl(decl ast.Decl) {
  2062  	switch d := decl.(type) {
  2063  	case *ast.BadDecl:
  2064  		p.print(d.Pos(), "BadDecl")
  2065  	case *ast.GenDecl:
  2066  		p.genDecl(d)
  2067  	case *ast.FuncDecl:
  2068  		p.funcDecl(d)
  2069  	case *ast.OverloadFuncDecl:
  2070  		p.overloadFuncDecl(d)
  2071  	default:
  2072  		panic("unreachable")
  2073  	}
  2074  }
  2075  
  2076  // ----------------------------------------------------------------------------
  2077  // Files
  2078  
  2079  func declToken(decl ast.Decl) (tok token.Token) {
  2080  	tok = token.ILLEGAL
  2081  	switch d := decl.(type) {
  2082  	case *ast.GenDecl:
  2083  		tok = d.Tok
  2084  	case *ast.FuncDecl:
  2085  		tok = token.FUNC
  2086  	}
  2087  	return
  2088  }
  2089  
  2090  func (p *printer) declList(list []ast.Decl) {
  2091  	tok := token.ILLEGAL
  2092  	for _, d := range list {
  2093  		// skip no entry shadow
  2094  		if decl, ok := d.(*ast.FuncDecl); ok && decl.Shadow && decl != p.shadowEntry {
  2095  			continue
  2096  		}
  2097  		prev := tok
  2098  		tok = declToken(d)
  2099  		// If the declaration token changed (e.g., from CONST to TYPE)
  2100  		// or the next declaration has documentation associated with it,
  2101  		// print an empty line between top-level declarations.
  2102  		// (because p.linebreak is called with the position of d, which
  2103  		// is past any documentation, the minimum requirement is satisfied
  2104  		// even w/o the extra getDoc(d) nil-check - leave it in case the
  2105  		// linebreak logic improves - there's already a TODO).
  2106  		if len(p.output) > 0 {
  2107  			// only print line break if we are not at the beginning of the output
  2108  			// (i.e., we are not printing only a partial program)
  2109  			min := 1
  2110  			if tok == token.FUNC || tok == token.TYPE || prev != tok || getDoc(d) != nil {
  2111  				min = 2
  2112  			}
  2113  			// start a new section if the next declaration is a function
  2114  			// that spans multiple lines (see also issue #19544)
  2115  			p.linebreak(p.lineFor(d.Pos()), min, ignore, tok == token.FUNC && p.numLines(d) > 1)
  2116  		}
  2117  		p.decl(d)
  2118  	}
  2119  }
  2120  
  2121  func (p *printer) file(src *ast.File) {
  2122  	p.shadowEntry = src.ShadowEntry
  2123  	p.setComment(src.Doc)
  2124  	if !src.NoPkgDecl {
  2125  		p.print(src.Pos(), token.PACKAGE, blank)
  2126  		p.expr(src.Name)
  2127  	}
  2128  	p.declList(src.Decls)
  2129  	p.print(newline)
  2130  }