Commit b1b0ed1e authored by Robert Griesemer's avatar Robert Griesemer

go/printer: replace multiline logic

This CL mostly deletes code.

Using existing position information is
just as good to determine if a new section
is needed; no need to track exact multi-
line information. Eliminates the need to
carry around a multiLine parameter with
practically every function.

Applied gofmt -w src misc resulting in only
a minor change to godoc.go. In return, a couple
of test cases are now formatted better.

Not Go1-required, but nice-to-have as it will
simplify fixes going forward.

R=rsc
CC=golang-dev
https://golang.org/cl/5706055
parent fb270611
......@@ -89,10 +89,9 @@ const (
noIndent // no extra indentation in multi-line lists
)
// Sets multiLine to true if the identifier list spans multiple lines.
// If indent is set, a multi-line identifier list is indented after the
// first linebreak encountered.
func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
func (p *printer) identList(list []*ast.Ident, indent bool) {
// convert into an expression list so we can re-use exprList formatting
xlist := make([]ast.Expr, len(list))
for i, x := range list {
......@@ -102,18 +101,17 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
if !indent {
mode |= noIndent
}
p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
p.exprList(token.NoPos, xlist, 1, mode, token.NoPos)
}
// 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.
// expressions.
//
// 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).
func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, next0 token.Pos) {
if len(list) == 0 {
return
}
......@@ -138,7 +136,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
p.print(blank)
}
p.expr0(x, depth, multiLine)
p.expr0(x, depth)
}
if mode&blankEnd != 0 {
p.print(blank)
......@@ -161,7 +159,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
prevBreak := -1 // index of last expression that was followed by a linebreak
if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
ws = ignore
*multiLine = true
prevBreak = 0
}
......@@ -231,7 +228,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// the same line in which case formfeed is used
if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
ws = ignore
*multiLine = true
prevBreak = i
needsBlank = false // we got a line break instead
}
......@@ -245,11 +241,11 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// we have a key:value expression that fits onto one line and
// is in a list with more then one entry: use a column for the
// key such that consecutive entries can align if possible
p.expr(pair.Key, multiLine)
p.expr(pair.Key)
p.print(pair.Colon, token.COLON, vtab)
p.expr(pair.Value, multiLine)
p.expr(pair.Value)
} else {
p.expr0(x, depth, multiLine)
p.expr0(x, depth)
}
}
......@@ -274,8 +270,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
}
// Sets multiLine to true if the the parameter list spans multiple lines.
func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
func (p *printer) parameters(fields *ast.FieldList) {
p.print(fields.Opening, token.LPAREN)
if len(fields.List) > 0 {
prevLine := p.lineFor(fields.Opening)
......@@ -306,7 +301,6 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) {
// break line if the opening "(" or previous parameter ended on a different line
ws = ignore
*multiLine = true
} else if i > 0 {
p.print(blank)
}
......@@ -318,11 +312,11 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
// again at the end (and still ws == indent). Thus, a subsequent indent
// by a linebreak call after a type, or in the next multi-line identList
// will do the right thing.
p.identList(par.Names, ws == indent, multiLine)
p.identList(par.Names, ws == indent)
p.print(blank)
}
// parameter type
p.expr(par.Type, multiLine)
p.expr(par.Type)
prevLine = parLineEnd
}
// if the closing ")" is on a separate line from the last parameter,
......@@ -339,18 +333,17 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
p.print(fields.Closing, token.RPAREN)
}
// Sets multiLine to true if the signature spans multiple lines.
func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
p.parameters(params, multiLine)
func (p *printer) signature(params, result *ast.FieldList) {
p.parameters(params)
n := result.NumFields()
if n > 0 {
p.print(blank)
if n == 1 && result.List[0].Names == nil {
// single anonymous result; no ()'s
p.expr(result.List[0].Type, multiLine)
p.expr(result.List[0].Type)
return
}
p.parameters(result, multiLine)
p.parameters(result)
}
}
......@@ -389,6 +382,10 @@ func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
}
func (p *printer) isMultiLine(n ast.Node) bool {
return p.lineFor(n.End())-p.lineFor(n.Pos()) > 1
}
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
lbrace := fields.Opening
list := fields.List
......@@ -412,12 +409,12 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
// no comments so no need for comma position
p.print(token.COMMA, blank)
}
p.expr(x, ignoreMultiLine)
p.expr(x)
}
if len(f.Names) > 0 {
p.print(blank)
}
p.expr(f.Type, ignoreMultiLine)
p.expr(f.Type)
p.print(blank, rbrace, token.RBRACE)
return
}
......@@ -435,23 +432,22 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) == 1 {
sep = blank
}
var ml bool
newSection := false
for i, f := range list {
if i > 0 {
p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml)
p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
}
ml = false
extraTabs := 0
p.setComment(f.Doc)
if len(f.Names) > 0 {
// named fields
p.identList(f.Names, false, &ml)
p.identList(f.Names, false)
p.print(sep)
p.expr(f.Type, &ml)
p.expr(f.Type)
extraTabs = 1
} else {
// anonymous field
p.expr(f.Type, &ml)
p.expr(f.Type)
extraTabs = 2
}
if f.Tag != nil {
......@@ -459,7 +455,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
p.print(sep)
}
p.print(sep)
p.expr(f.Tag, &ml)
p.expr(f.Tag)
extraTabs = 0
}
if f.Comment != nil {
......@@ -468,6 +464,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
}
p.setComment(f.Comment)
}
newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
......@@ -479,22 +476,22 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
} else { // interface
var ml bool
newSection := false
for i, f := range list {
if i > 0 {
p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml)
p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
}
ml = false
p.setComment(f.Doc)
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
// method
p.expr(f.Names[0], &ml)
p.signature(ftyp.Params, ftyp.Results, &ml)
p.expr(f.Names[0])
p.signature(ftyp.Params, ftyp.Results)
} else {
// embedded interface
p.expr(f.Type, &ml)
p.expr(f.Type)
}
p.setComment(f.Comment)
newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
......@@ -635,15 +632,14 @@ func reduceDepth(depth int) int {
// cutoff is 6 (always use spaces) in Normal mode
// and 4 (never use spaces) in Compact mode.
//
// Sets multiLine to true if the binary expression spans multiple lines.
func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
prec := x.Op.Precedence()
if prec < prec1 {
// parenthesis needed
// Note: The parser inserts an ast.ParenExpr node; thus this case
// can only occur if the AST is created in a different way.
p.print(token.LPAREN)
p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth
p.expr0(x, reduceDepth(depth)) // parentheses undo one level of depth
p.print(token.RPAREN)
return
}
......@@ -651,7 +647,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
printBlank := prec < cutoff
ws := indent
p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine)
p.expr1(x.X, prec, depth+diffPrec(x.X, prec))
if printBlank {
p.print(blank)
}
......@@ -663,14 +659,13 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
// in the source
if p.linebreak(yline, 1, ws, true) {
ws = ignore
*multiLine = true
printBlank = false // no blank after line break
}
}
if printBlank {
p.print(blank)
}
p.expr1(x.Y, prec+1, depth+1, multiLine)
p.expr1(x.Y, prec+1, depth+1)
if ws == ignore {
p.print(unindent)
}
......@@ -681,8 +676,7 @@ func isBinary(expr ast.Expr) bool {
return ok
}
// Sets multiLine to true if the expression spans multiple lines.
func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
p.print(expr.Pos())
switch x := expr.(type) {
......@@ -697,12 +691,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.internalError("depth < 1:", depth)
depth = 1
}
p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
p.binaryExpr(x, prec1, cutoff(x, depth), depth)
case *ast.KeyValueExpr:
p.expr(x.Key, multiLine)
p.expr(x.Key)
p.print(x.Colon, token.COLON, blank)
p.expr(x.Value, multiLine)
p.expr(x.Value)
case *ast.StarExpr:
const prec = token.UnaryPrec
......@@ -710,12 +704,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
// parenthesis needed
p.print(token.LPAREN)
p.print(token.MUL)
p.expr(x.X, multiLine)
p.expr(x.X)
p.print(token.RPAREN)
} else {
// no parenthesis needed
p.print(token.MUL)
p.expr(x.X, multiLine)
p.expr(x.X)
}
case *ast.UnaryExpr:
......@@ -723,7 +717,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
if prec < prec1 {
// parenthesis needed
p.print(token.LPAREN)
p.expr(x, multiLine)
p.expr(x)
p.print(token.RPAREN)
} else {
// no parenthesis needed
......@@ -732,42 +726,41 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
// TODO(gri) Remove this code if it cannot be reached.
p.print(blank)
}
p.expr1(x.X, prec, depth, multiLine)
p.expr1(x.X, prec, depth)
}
case *ast.BasicLit:
p.print(x)
case *ast.FuncLit:
p.expr(x.Type, multiLine)
p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
p.expr(x.Type)
p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true)
case *ast.ParenExpr:
if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
// don't print parentheses around an already parenthesized expression
// TODO(gri) consider making this more general and incorporate precedence levels
p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
} else {
p.print(token.LPAREN)
p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
p.print(x.Rparen, token.RPAREN)
}
case *ast.SelectorExpr:
p.expr1(x.X, token.HighestPrec, depth, multiLine)
p.expr1(x.X, token.HighestPrec, depth)
p.print(token.PERIOD)
if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
p.print(indent, newline, x.Sel.Pos(), x.Sel, unindent)
*multiLine = true
} else {
p.print(x.Sel.Pos(), x.Sel)
}
case *ast.TypeAssertExpr:
p.expr1(x.X, token.HighestPrec, depth, multiLine)
p.expr1(x.X, token.HighestPrec, depth)
p.print(token.PERIOD, token.LPAREN)
if x.Type != nil {
p.expr(x.Type, multiLine)
p.expr(x.Type)
} else {
p.print(token.TYPE)
}
......@@ -775,17 +768,17 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.IndexExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
p.expr1(x.X, token.HighestPrec, 1, multiLine)
p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK)
p.expr0(x.Index, depth+1, multiLine)
p.expr0(x.Index, depth+1)
p.print(x.Rbrack, token.RBRACK)
case *ast.SliceExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
p.expr1(x.X, token.HighestPrec, 1, multiLine)
p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK)
if x.Low != nil {
p.expr0(x.Low, depth+1, multiLine)
p.expr0(x.Low, depth+1)
}
// blanks around ":" if both sides exist and either side is a binary expression
if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
......@@ -794,7 +787,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(token.COLON)
}
if x.High != nil {
p.expr0(x.High, depth+1, multiLine)
p.expr0(x.High, depth+1)
}
p.print(x.Rbrack, token.RBRACK)
......@@ -802,26 +795,26 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
if len(x.Args) > 1 {
depth++
}
p.expr1(x.Fun, token.HighestPrec, depth, multiLine)
p.expr1(x.Fun, token.HighestPrec, depth)
p.print(x.Lparen, token.LPAREN)
if x.Ellipsis.IsValid() {
p.exprList(x.Lparen, x.Args, depth, commaSep, multiLine, x.Ellipsis)
p.exprList(x.Lparen, x.Args, depth, commaSep, x.Ellipsis)
p.print(x.Ellipsis, token.ELLIPSIS)
if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
p.print(token.COMMA, formfeed)
}
} else {
p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, x.Rparen)
}
p.print(x.Rparen, token.RPAREN)
case *ast.CompositeLit:
// composite literal elements that are composite literals themselves may have the type omitted
if x.Type != nil {
p.expr1(x.Type, token.HighestPrec, depth, multiLine)
p.expr1(x.Type, token.HighestPrec, depth)
}
p.print(x.Lbrace, token.LBRACE)
p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, x.Rbrace)
// do not insert extra line breaks because of comments before
// the closing '}' as it might break the code if there is no
// trailing ','
......@@ -830,16 +823,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.Ellipsis:
p.print(token.ELLIPSIS)
if x.Elt != nil {
p.expr(x.Elt, multiLine)
p.expr(x.Elt)
}
case *ast.ArrayType:
p.print(token.LBRACK)
if x.Len != nil {
p.expr(x.Len, multiLine)
p.expr(x.Len)
}
p.print(token.RBRACK)
p.expr(x.Elt, multiLine)
p.expr(x.Elt)
case *ast.StructType:
p.print(token.STRUCT)
......@@ -847,7 +840,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.FuncType:
p.print(token.FUNC)
p.signature(x.Params, x.Results, multiLine)
p.signature(x.Params, x.Results)
case *ast.InterfaceType:
p.print(token.INTERFACE)
......@@ -855,9 +848,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.MapType:
p.print(token.MAP, token.LBRACK)
p.expr(x.Key, multiLine)
p.expr(x.Key)
p.print(token.RBRACK)
p.expr(x.Value, multiLine)
p.expr(x.Value)
case *ast.ChanType:
switch x.Dir {
......@@ -869,7 +862,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(token.CHAN, token.ARROW)
}
p.print(blank)
p.expr(x.Value, multiLine)
p.expr(x.Value)
default:
panic("unreachable")
......@@ -878,14 +871,13 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
return
}
func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
p.expr1(x, token.LowestPrec, depth, multiLine)
func (p *printer) expr0(x ast.Expr, depth int) {
p.expr1(x, token.LowestPrec, depth)
}
// Sets multiLine to true if the expression spans multiple lines.
func (p *printer) expr(x ast.Expr, multiLine *bool) {
func (p *printer) expr(x ast.Expr) {
const depth = 1
p.expr1(x, token.LowestPrec, depth, multiLine)
p.expr1(x, token.LowestPrec, depth)
}
// ----------------------------------------------------------------------------
......@@ -899,13 +891,13 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
if _indent > 0 {
p.print(indent)
}
var multiLine bool
multiLine := false
for i, s := range list {
// _indent == 0 only for lists of switch/select case clauses;
// in those cases each clause is a new section
p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || _indent == 0 || multiLine)
multiLine = false
p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
p.stmt(s, nextIsRBrace && i == len(list)-1)
multiLine = p.isMultiLine(s)
}
if _indent > 0 {
p.print(unindent)
......@@ -962,25 +954,25 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
if init == nil && post == nil {
// no semicolons required
if expr != nil {
p.expr(stripParens(expr), ignoreMultiLine)
p.expr(stripParens(expr))
needsBlank = true
}
} else {
// all semicolons required
// (they are not separators, print them explicitly)
if init != nil {
p.stmt(init, false, ignoreMultiLine)
p.stmt(init, false)
}
p.print(token.SEMICOLON, blank)
if expr != nil {
p.expr(stripParens(expr), ignoreMultiLine)
p.expr(stripParens(expr))
needsBlank = true
}
if isForStmt {
p.print(token.SEMICOLON, blank)
needsBlank = false
if post != nil {
p.stmt(post, false, ignoreMultiLine)
p.stmt(post, false)
needsBlank = true
}
}
......@@ -990,8 +982,7 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
}
}
// Sets multiLine to true if the statements spans multiple lines.
func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
p.print(stmt.Pos())
switch s := stmt.(type) {
......@@ -999,7 +990,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print("BadStmt")
case *ast.DeclStmt:
p.decl(s.Decl, multiLine)
p.decl(s.Decl)
case *ast.EmptyStmt:
// nothing to do
......@@ -1009,7 +1000,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
// is applied before the line break if there is no comment
// between (see writeWhitespace)
p.print(unindent)
p.expr(s.Label, multiLine)
p.expr(s.Label)
p.print(s.Colon, token.COLON, indent)
if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
if !nextIsRBrace {
......@@ -1019,21 +1010,21 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
} else {
p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
}
p.stmt(s.Stmt, nextIsRBrace, multiLine)
p.stmt(s.Stmt, nextIsRBrace)
case *ast.ExprStmt:
const depth = 1
p.expr0(s.X, depth, multiLine)
p.expr0(s.X, depth)
case *ast.SendStmt:
const depth = 1
p.expr0(s.Chan, depth, multiLine)
p.expr0(s.Chan, depth)
p.print(blank, s.Arrow, token.ARROW, blank)
p.expr0(s.Value, depth, multiLine)
p.expr0(s.Value, depth)
case *ast.IncDecStmt:
const depth = 1
p.expr0(s.X, depth+1, multiLine)
p.expr0(s.X, depth+1)
p.print(s.TokPos, s.Tok)
case *ast.AssignStmt:
......@@ -1041,48 +1032,46 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
depth++
}
p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
p.exprList(s.Pos(), s.Lhs, depth, commaSep, s.TokPos)
p.print(blank, s.TokPos, s.Tok)
p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, token.NoPos)
case *ast.GoStmt:
p.print(token.GO, blank)
p.expr(s.Call, multiLine)
p.expr(s.Call)
case *ast.DeferStmt:
p.print(token.DEFER, blank)
p.expr(s.Call, multiLine)
p.expr(s.Call)
case *ast.ReturnStmt:
p.print(token.RETURN)
if s.Results != nil {
p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, token.NoPos)
}
case *ast.BranchStmt:
p.print(s.Tok)
if s.Label != nil {
p.print(blank)
p.expr(s.Label, multiLine)
p.expr(s.Label)
}
case *ast.BlockStmt:
p.block(s, 1)
*multiLine = true
case *ast.IfStmt:
p.print(token.IF)
p.controlClause(false, s.Init, s.Cond, nil)
p.block(s.Body, 1)
*multiLine = true
if s.Else != nil {
p.print(blank, token.ELSE, blank)
switch s.Else.(type) {
case *ast.BlockStmt, *ast.IfStmt:
p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
p.stmt(s.Else, nextIsRBrace)
default:
p.print(token.LBRACE, indent, formfeed)
p.stmt(s.Else, true, ignoreMultiLine)
p.stmt(s.Else, true)
p.print(unindent, formfeed, token.RBRACE)
}
}
......@@ -1090,7 +1079,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.CaseClause:
if s.List != nil {
p.print(token.CASE)
p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon)
p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, s.Colon)
} else {
p.print(token.DEFAULT)
}
......@@ -1101,25 +1090,23 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print(token.SWITCH)
p.controlClause(false, s.Init, s.Tag, nil)
p.block(s.Body, 0)
*multiLine = true
case *ast.TypeSwitchStmt:
p.print(token.SWITCH)
if s.Init != nil {
p.print(blank)
p.stmt(s.Init, false, ignoreMultiLine)
p.stmt(s.Init, false)
p.print(token.SEMICOLON)
}
p.print(blank)
p.stmt(s.Assign, false, ignoreMultiLine)
p.stmt(s.Assign, false)
p.print(blank)
p.block(s.Body, 0)
*multiLine = true
case *ast.CommClause:
if s.Comm != nil {
p.print(token.CASE, blank)
p.stmt(s.Comm, false, ignoreMultiLine)
p.stmt(s.Comm, false)
} else {
p.print(token.DEFAULT)
}
......@@ -1134,29 +1121,26 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
} else {
p.block(body, 0)
*multiLine = true
}
case *ast.ForStmt:
p.print(token.FOR)
p.controlClause(true, s.Init, s.Cond, s.Post)
p.block(s.Body, 1)
*multiLine = true
case *ast.RangeStmt:
p.print(token.FOR, blank)
p.expr(s.Key, multiLine)
p.expr(s.Key)
if s.Value != nil {
// use position of value following the comma as
// comma position for correct comment placement
p.print(s.Value.Pos(), token.COMMA, blank)
p.expr(s.Value, multiLine)
p.expr(s.Value)
}
p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
p.expr(stripParens(s.X), multiLine)
p.expr(stripParens(s.X))
p.print(blank)
p.block(s.Body, 1)
*multiLine = true
default:
panic("unreachable")
......@@ -1233,20 +1217,20 @@ func keepTypeColumn(specs []ast.Spec) []bool {
return m
}
func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool) {
p.setComment(s.Doc)
p.identList(s.Names, doIndent, multiLine) // always present
p.identList(s.Names, doIndent) // always present
extraTabs := 3
if s.Type != nil || keepType {
p.print(vtab)
extraTabs--
}
if s.Type != nil {
p.expr(s.Type, multiLine)
p.expr(s.Type)
}
if s.Values != nil {
p.print(vtab, token.ASSIGN)
p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, token.NoPos)
extraTabs--
}
if s.Comment != nil {
......@@ -1260,17 +1244,16 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine
// The parameter n is the number of specs in the group. If doIndent is set,
// multi-line identifier lists in the spec are indented when the first
// linebreak is encountered.
// Sets multiLine to true if the spec spans multiple lines.
//
func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
switch s := spec.(type) {
case *ast.ImportSpec:
p.setComment(s.Doc)
if s.Name != nil {
p.expr(s.Name, multiLine)
p.expr(s.Name)
p.print(blank)
}
p.expr(s.Path, multiLine)
p.expr(s.Path)
p.setComment(s.Comment)
p.print(s.EndPos)
......@@ -1279,26 +1262,26 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
p.internalError("expected n = 1; got", n)
}
p.setComment(s.Doc)
p.identList(s.Names, doIndent, multiLine) // always present
p.identList(s.Names, doIndent) // always present
if s.Type != nil {
p.print(blank)
p.expr(s.Type, multiLine)
p.expr(s.Type)
}
if s.Values != nil {
p.print(blank, token.ASSIGN)
p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, token.NoPos)
}
p.setComment(s.Comment)
case *ast.TypeSpec:
p.setComment(s.Doc)
p.expr(s.Name, multiLine)
p.expr(s.Name)
if n == 1 {
p.print(blank)
} else {
p.print(vtab)
}
p.expr(s.Type, multiLine)
p.expr(s.Type)
p.setComment(s.Comment)
default:
......@@ -1306,8 +1289,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
}
}
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
func (p *printer) genDecl(d *ast.GenDecl) {
p.setComment(d.Doc)
p.print(d.Pos(), d.Tok, blank)
......@@ -1320,32 +1302,31 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
// two or more grouped const/var declarations:
// determine if the type column must be kept
keepType := keepTypeColumn(d.Specs)
var ml bool
newSection := false
for i, s := range d.Specs {
if i > 0 {
p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml)
p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
}
ml = false
p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
p.valueSpec(s.(*ast.ValueSpec), keepType[i], false)
newSection = p.isMultiLine(s)
}
} else {
var ml bool
newSection := false
for i, s := range d.Specs {
if i > 0 {
p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml)
p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
}
ml = false
p.spec(s, n, false, &ml)
p.spec(s, n, false)
newSection = p.isMultiLine(s)
}
}
p.print(unindent, formfeed)
*multiLine = true
}
p.print(d.Rparen, token.RPAREN)
} else {
// single declaration
p.spec(d.Specs[0], 1, true, multiLine)
p.spec(d.Specs[0], 1, true)
}
}
......@@ -1409,8 +1390,7 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
return headerSize+bodySize <= maxSize
}
// Sets multiLine to true if the function body spans multiple lines.
func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool) {
if b == nil {
return
}
......@@ -1427,7 +1407,7 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
if i > 0 {
p.print(token.SEMICOLON, blank)
}
p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
p.stmt(s, i == len(b.List)-1)
}
p.print(blank)
}
......@@ -1437,7 +1417,6 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
p.print(blank)
p.block(b, 1)
*multiLine = true
}
// distance returns the column difference between from and to if both
......@@ -1451,28 +1430,26 @@ func (p *printer) distance(from0 token.Pos, to token.Position) int {
return infinity
}
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
func (p *printer) funcDecl(d *ast.FuncDecl) {
p.setComment(d.Doc)
p.print(d.Pos(), token.FUNC, blank)
if d.Recv != nil {
p.parameters(d.Recv, multiLine) // method: print receiver
p.parameters(d.Recv) // method: print receiver
p.print(blank)
}
p.expr(d.Name, multiLine)
p.signature(d.Type.Params, d.Type.Results, multiLine)
p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
p.expr(d.Name)
p.signature(d.Type.Params, d.Type.Results)
p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false)
}
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) decl(decl ast.Decl, multiLine *bool) {
func (p *printer) decl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.BadDecl:
p.print(d.Pos(), "BadDecl")
case *ast.GenDecl:
p.genDecl(d, multiLine)
p.genDecl(d)
case *ast.FuncDecl:
p.funcDecl(d, multiLine)
p.funcDecl(d)
default:
panic("unreachable")
}
......@@ -1495,7 +1472,7 @@ func declToken(decl ast.Decl) (tok token.Token) {
func (p *printer) file(src *ast.File) {
p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank)
p.expr(src.Name, ignoreMultiLine)
p.expr(src.Name)
if len(src.Decls) > 0 {
tok := token.ILLEGAL
......@@ -1514,7 +1491,7 @@ func (p *printer) file(src *ast.File) {
min = 2
}
p.linebreak(p.lineFor(d.Pos()), min, ignore, false)
p.decl(d, ignoreMultiLine)
p.decl(d)
}
}
......
......@@ -34,9 +34,6 @@ const (
unindent = whiteSpace('<')
)
// Use ignoreMultiLine if the multiLine information is not important.
var ignoreMultiLine = new(bool)
// A pmode value represents the current printer mode.
type pmode int
......@@ -1011,18 +1008,18 @@ func (p *printer) printNode(node interface{}) error {
// format node
switch n := node.(type) {
case ast.Expr:
p.expr(n, ignoreMultiLine)
p.expr(n)
case ast.Stmt:
// A labeled statement will un-indent to position the
// label. Set indent to 1 so we don't get indent "underflow".
if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
p.indent = 1
}
p.stmt(n, false, ignoreMultiLine)
p.stmt(n, false)
case ast.Decl:
p.decl(n, ignoreMultiLine)
p.decl(n)
case ast.Spec:
p.spec(n, 1, false, ignoreMultiLine)
p.spec(n, 1, false)
case *ast.File:
p.file(n)
default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment