func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
	if len(list) == 0 {
		return
	}
	if mode&blankStart != 0 {
		p.print(blank)
	}
	prev := p.fset.Position(prev0)
	next := p.fset.Position(next0)
	line := p.fset.Position(list[0].Pos()).Line
	endLine := p.fset.Position(list[len(list)-1].End()).Line
	if prev.IsValid() && prev.Line == line && line == endLine {
		for i, x := range list {
			if i > 0 {
				if mode&commaSep != 0 {
					p.print(token.COMMA)
				}
				p.print(blank)
			}
			p.expr0(x, depth, multiLine)
		}
		if mode&blankEnd != 0 {
			p.print(blank)
		}
		return
	}
	ws := ignore
	if mode&noIndent == 0 {
		ws = indent
	}
	prevBreak := -1  
	if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
		ws = ignore
		*multiLine = true
		prevBreak = 0
	}
	size := 0
	for i, x := range list {
		prevLine := line
		line = p.fset.Position(x.Pos()).Line
		useFF := true
		prevSize := size
		const infinity = 1e6  
		size = p.nodeSize(x, infinity)
		pair, isPair := x.(*ast.KeyValueExpr)
		if size <= infinity && prev.IsValid() && next.IsValid() {
			if isPair {
				size = p.nodeSize(pair.Key, infinity)  
			}
		} else {
			size = 0
		}
		if prevSize > 0 && size > 0 {
			const smallSize = 20
			if prevSize <= smallSize && size <= smallSize {
				useFF = false
			} else {
				const r = 4  
				ratio := float64(size) / float64(prevSize)
				useFF = ratio <= 1/r || r <= ratio
			}
		}
		if i > 0 {
			switch {
			case mode&commaSep != 0:
				p.print(token.COMMA)
			case mode&periodSep != 0:
				p.print(token.PERIOD)
			}
			needsBlank := mode&periodSep == 0  
			if prevLine < line && prevLine > 0 && line > 0 {
				if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
					ws = ignore
					*multiLine = true
					prevBreak = i
					needsBlank = false  
				}
			}
			if needsBlank {
				p.print(blank)
			}
		}
		if isPair && size > 0 && len(list) > 1 {
			p.expr(pair.Key, multiLine)
			p.print(pair.Colon, token.COLON, vtab)
			p.expr(pair.Value, multiLine)
		} else {
			p.expr0(x, depth, multiLine)
		}
	}
	if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
		p.print(token.COMMA)
		if ws == ignore && mode&noIndent == 0 {
			p.print(unindent)
		}
		p.print(formfeed)  
		return
	}
	if mode&blankEnd != 0 {
		p.print(blank)
	}
	if ws == ignore && mode&noIndent == 0 {
		p.print(unindent)
	}
}
Print a list of expressions. If the list spans multiple
source lines, the original line breaks are respected between
expressions. Sets multiLine to true if the list spans multiple
lines.

TODO(gri) Consider rewriting this to be independent of []ast.Expr
so that we can use the algorithm for any kind of list
(e.g., pass list via a channel over which to range).
package printer
import (
	"bytes"
	"github.com/rogpeppe/godef/go/ast"
	"github.com/rogpeppe/godef/go/token"
)
func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
	n := p.nlines(line-p.pos.Line, min)
	if n > 0 {
		p.print(ws)
		if newSection {
			p.print(formfeed)
			n--
		}
		for ; n > 0; n-- {
			p.print(newline)
		}
		printedBreak = true
	}
	return
}
func (p *printer) setComment(g *ast.CommentGroup) {
	if g == nil || !p.useNodeComments {
		return
	}
	if p.comments == nil {
		p.comments = make([]*ast.CommentGroup, 1)
	} else if p.cindex < len(p.comments) {
		p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL)
	}
	p.comments[0] = g
	p.cindex = 0
}
type exprListMode uint
const (
	blankStart exprListMode = 1 << iota  
	blankEnd                             
	commaSep                             
	commaTerm                            
	noIndent                             
	periodSep                            
)
func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
	xlist := make([]ast.Expr, len(list))
	for i, x := range list {
		xlist[i] = x
	}
	mode := commaSep
	if !indent {
		mode |= noIndent
	}
	p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
}