]> Cypherpunks repositories - gostls13.git/commitdiff
go/printer, gofmt: don't write too many newlines
authorRobert Griesemer <gri@golang.org>
Thu, 15 Dec 2011 21:51:47 +0000 (13:51 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 15 Dec 2011 21:51:47 +0000 (13:51 -0800)
In some rare cases, gofmt would accept more than the maximum
number of empty lines (1) between source code snippets.

The actual change is in printer.go, lines 773-775; the rest
is some minor restructuring.

Applied gofmt -w src misc .

Fixes #2387.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5496047

src/cmd/cgo/godefs.go
src/pkg/bytes/buffer_test.go
src/pkg/go/printer/nodes.go
src/pkg/go/printer/printer.go
src/pkg/go/printer/testdata/statements.golden

index e41812fdecfc270a11c49812dda9af1fdb0eebe2..df3f66ed027c040785fb6be08533a938cd41bff1 100644 (file)
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-
 package main
 
 import (
index 523597003226100e1a1334c7bfcf17f5c60e5b48..adb93302a541ebcea1cc9ea6b7f9df1e055e11cb 100644 (file)
@@ -16,7 +16,6 @@ const N = 10000  // make this bigger for a larger (and slower) test
 var data string  // test data for write tests
 var bytes []byte // test data; same as data but as a slice.
 
-
 func init() {
        bytes = make([]byte, N)
        for i := 0; i < N; i++ {
index b2a48c28a733bbe4d4431927055398b7f320ce37..9e9d5f83df10d7a4ff1df928a0b6e6b97d50cc9e 100644 (file)
@@ -39,7 +39,10 @@ import (
 //            future (not yet interspersed) comments in this function.
 //
 func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
-       n := p.nlines(line-p.pos.Line, min)
+       n := nlimit(line - p.pos.Line)
+       if n < min {
+               n = min
+       }
        if n > 0 {
                p.print(ws)
                if newSection {
index 8538236c2c953f75d60c58156d603b78c82bc424..a0197d87c4df833921c78073184d27a65136ec33 100644 (file)
@@ -18,8 +18,11 @@ import (
        "text/tabwriter"
 )
 
-const debug = false // enable for debugging
-const infinity = 1 << 30
+const (
+       maxNewlines = 2     // max. number of newlines between source text
+       debug       = false // enable for debugging
+       infinity    = 1 << 30
+)
 
 type whiteSpace byte
 
@@ -89,21 +92,7 @@ func (p *printer) internalError(msg ...interface{}) {
        }
 }
 
-// nlines returns the adjusted number of linebreaks given the desired number
-// of breaks n such that min <= result <= max.
-//
-func (p *printer) nlines(n, min int) int {
-       const max = 2 // max. number of newlines
-       switch {
-       case n < min:
-               return min
-       case n > max:
-               return max
-       }
-       return n
-}
-
-// writeByte writes a single byte to p.output and updates p.pos.
+// writeByte writes ch to p.output and updates p.pos.
 func (p *printer) writeByte(ch byte) {
        p.output.WriteByte(ch)
        p.pos.Offset++
@@ -128,13 +117,11 @@ func (p *printer) writeByte(ch byte) {
        }
 }
 
-// writeNewlines writes up to n newlines to p.output and updates p.pos.
-// The actual number of newlines written is limited by nlines.
-// nl must be one of '\n' or '\f'.
-//
-func (p *printer) writeNewlines(n int, nl byte) {
-       for n = p.nlines(n, 0); n > 0; n-- {
-               p.writeByte(nl)
+// writeByteN writes ch n times to p.output and updates p.pos.
+func (p *printer) writeByteN(ch byte, n int) {
+       for n > 0 {
+               p.writeByte(ch)
+               n--
        }
 }
 
@@ -223,8 +210,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
        }
 
        if pos.IsValid() && pos.Filename != p.last.Filename {
-               // comment in a different file - separate with newlines (writeNewlines will limit the number)
-               p.writeNewlines(10, '\f')
+               // comment in a different file - separate with newlines
+               p.writeByteN('\f', maxNewlines)
                return
        }
 
@@ -318,7 +305,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
                        n = 1
                }
                if n > 0 {
-                       p.writeNewlines(n, '\f')
+                       p.writeByteN('\f', nlimit(n))
                }
                p.indent = indent
        }
@@ -550,10 +537,11 @@ func (p *printer) writeComment(comment *ast.Comment) {
 // writeCommentSuffix writes a line break after a comment if indicated
 // and processes any leftover indentation information. If a line break
 // is needed, the kind of break (newline vs formfeed) depends on the
-// pending whitespace. writeCommentSuffix returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// pending whitespace. The writeCommentSuffix result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace
+// buffer.
 //
-func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
+func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, droppedFF bool) {
        for i, ch := range p.wsbuf {
                switch ch {
                case blank, vtab:
@@ -566,6 +554,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
                        // but remember if we dropped any formfeeds
                        if needsLinebreak {
                                needsLinebreak = false
+                               wroteNewline = true
                        } else {
                                if ch == formfeed {
                                        droppedFF = true
@@ -579,6 +568,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
        // make sure we have a line break
        if needsLinebreak {
                p.writeByte('\n')
+               wroteNewline = true
        }
 
        return
@@ -587,10 +577,10 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
 // intersperseComments consumes all comments that appear before the next token
 // tok and prints it together with the buffered whitespace (i.e., the whitespace
 // that needs to be written before the next token). A heuristic is used to mix
-// the comments and whitespace. intersperseComments returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// the comments and whitespace. The intersperseComments result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace buffer.
 //
-func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
        var last *ast.Comment
        for ; p.commentBefore(next); p.cindex++ {
                for _, c := range p.comments[p.cindex].List {
@@ -618,7 +608,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
        // no comment was written - we should never reach here since
        // intersperseComments should not be called in that case
        p.internalError("intersperseComments called without pending comments")
-       return false
+       return
 }
 
 // whiteWhitespace writes the first n whitespace entries.
@@ -671,6 +661,14 @@ func (p *printer) writeWhitespace(n int) {
 // ----------------------------------------------------------------------------
 // Printing interface
 
+// nlines limits n to maxNewlines.
+func nlimit(n int) int {
+       if n > maxNewlines {
+               n = maxNewlines
+       }
+       return n
+}
+
 func mayCombine(prev token.Token, next byte) (b bool) {
        switch prev {
        case token.INT:
@@ -765,17 +763,22 @@ func (p *printer) print(args ...interface{}) {
                p.pos = next
 
                if data != "" {
-                       nl := byte('\n')
-                       if p.flush(next, tok) {
-                               nl = '\f' // dropped formfeed before
-                       }
+                       wroteNewline, droppedFF := p.flush(next, tok)
 
                        // intersperse extra newlines if present in the source
                        // (don't do this in flush as it will cause extra newlines
-                       // at the end of a file) - use formfeeds if we dropped one
-                       // before
-                       if n := next.Line - p.pos.Line; n > 0 {
-                               p.writeNewlines(n, nl)
+                       // at the end of a file)
+                       n := nlimit(next.Line - p.pos.Line)
+                       // don't exceed maxNewlines if we already wrote one
+                       if wroteNewline && n == maxNewlines {
+                               n = maxNewlines - 1
+                       }
+                       if n > 0 {
+                               ch := byte('\n')
+                               if droppedFF {
+                                       ch = '\f' // use formfeed since we dropped one before
+                               }
+                               p.writeByteN(ch, n)
                        }
 
                        p.writeItem(next, data, isLit)
@@ -790,16 +793,15 @@ func (p *printer) commentBefore(next token.Position) bool {
        return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
 }
 
-// Flush prints any pending comments and whitespace occurring
-// textually before the position of the next token tok. Flush
-// returns true if a pending formfeed character was dropped
-// from the whitespace buffer as a result of interspersing
-// comments.
+// Flush prints any pending comments and whitespace occurring textually
+// before the position of the next token tok. The Flush result indicates
+// if a newline was written or if a formfeed was dropped from the whitespace
+// buffer.
 //
-func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) flush(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
        if p.commentBefore(next) {
                // if there are comments before the next item, intersperse them
-               droppedFF = p.intersperseComments(next, tok)
+               wroteNewline, droppedFF = p.intersperseComments(next, tok)
        } else {
                // otherwise, write any leftover whitespace
                p.writeWhitespace(len(p.wsbuf))
index a6d85107f0b307b154d005f591c4f55d495ceaed..90e1743557d382007e8fcfe664e3edd157886f48 100644 (file)
@@ -271,7 +271,6 @@ func _() {
        // Known bug: The first use call may have more than one empty line before
        //            (see go/printer/nodes.go, func linebreak).
 
-
        use(x)
 
        if x < x {
@@ -386,7 +385,6 @@ L:  // A comment on the same line as the label, followed by a single empty line.
        // Known bug: There may be more than one empty line before MoreCode()
        //            (see go/printer/nodes.go, func linebreak).
 
-
        MoreCode()
 }