summaryrefslogtreecommitdiff
path: root/src/pkg/go/printer/printer.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/go/printer/printer.go')
-rw-r--r--src/pkg/go/printer/printer.go125
1 files changed, 93 insertions, 32 deletions
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index e06d2edfb..280c697a0 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -39,9 +39,17 @@ const (
type pmode int
const (
- noExtraLinebreak pmode = 1 << iota
+ noExtraBlank pmode = 1 << iota // disables extra blank after /*-style comment
+ noExtraLinebreak // disables extra line break after /*-style comment
)
+type commentInfo struct {
+ cindex int // current comment index
+ comment *ast.CommentGroup // = printer.comments[cindex]; or nil
+ commentOffset int // = printer.posFor(printer.comments[cindex].List[0].Pos()).Offset; or infinity
+ commentNewline bool // true if the comment group contains newlines
+}
+
type printer struct {
// Configuration (does not change after initialization)
Config
@@ -52,7 +60,8 @@ type printer struct {
indent int // current indentation
mode pmode // current printer mode
impliedSemi bool // if set, a linebreak implies a semicolon
- lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
+ lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace)
+ prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL
wsbuf []whiteSpace // delayed white space
// Positions
@@ -61,19 +70,17 @@ type printer struct {
// white space). If there's a difference and SourcePos is set in
// ConfigMode, //line comments are used in the output to restore
// original source positions for a reader.
- pos token.Position // current position in AST (source) space
- out token.Position // current position in output space
- last token.Position // value of pos after calling writeString
+ pos token.Position // current position in AST (source) space
+ out token.Position // current position in output space
+ last token.Position // value of pos after calling writeString
+ linePtr *int // if set, record out.Line for the next token in *linePtr
// The list of all source comments, in order of appearance.
comments []*ast.CommentGroup // may be nil
- cindex int // current comment index
useNodeComments bool // if not set, ignore lead and line comments of nodes
// Information about p.comments[p.cindex]; set up by nextComment.
- comment *ast.CommentGroup // = p.comments[p.cindex]; or nil
- commentOffset int // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity
- commentNewline bool // true if the comment group contains newlines
+ commentInfo
// Cache of already computed node sizes.
nodeSizes map[ast.Node]int
@@ -93,6 +100,14 @@ func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]
p.cachedPos = -1
}
+func (p *printer) internalError(msg ...interface{}) {
+ if debug {
+ fmt.Print(p.pos.String() + ": ")
+ fmt.Println(msg...)
+ panic("go/printer")
+ }
+}
+
// commentsHaveNewline reports whether a list of comments belonging to
// an *ast.CommentGroup contains newlines. Because the position information
// may only be partially correct, we also have to read the comment text.
@@ -129,12 +144,49 @@ func (p *printer) nextComment() {
p.commentOffset = infinity
}
-func (p *printer) internalError(msg ...interface{}) {
- if debug {
- fmt.Print(p.pos.String() + ": ")
- fmt.Println(msg...)
- panic("go/printer")
+// commentBefore returns true iff the current comment group occurs
+// before the next position in the source code and printing it does
+// not introduce implicit semicolons.
+//
+func (p *printer) commentBefore(next token.Position) bool {
+ return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
+}
+
+// commentSizeBefore returns the estimated size of the
+// comments on the same line before the next position.
+//
+func (p *printer) commentSizeBefore(next token.Position) int {
+ // save/restore current p.commentInfo (p.nextComment() modifies it)
+ defer func(info commentInfo) {
+ p.commentInfo = info
+ }(p.commentInfo)
+
+ size := 0
+ for p.commentBefore(next) {
+ for _, c := range p.comment.List {
+ size += len(c.Text)
+ }
+ p.nextComment()
}
+ return size
+}
+
+// recordLine records the output line number for the next non-whitespace
+// token in *linePtr. It is used to compute an accurate line number for a
+// formatted construct, independent of pending (not yet emitted) whitespace
+// or comments.
+//
+func (p *printer) recordLine(linePtr *int) {
+ p.linePtr = linePtr
+}
+
+// linesFrom returns the number of output lines between the current
+// output line and the line argument, ignoring any pending (not yet
+// emitted) whitespace or comments. It is used to compute an accurate
+// size (in number of lines) for a formatted construct.
+//
+func (p *printer) linesFrom(line int) int {
+ return p.out.Line - line
}
func (p *printer) posFor(pos token.Pos) token.Position {
@@ -675,10 +727,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
if last != nil {
// if the last comment is a /*-style comment and the next item
- // follows on the same line but is not a comma or a "closing"
- // token, add an extra blank for separation
- if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA &&
- tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE {
+ // follows on the same line but is not a comma, and not a "closing"
+ // token immediately following its corresponding "opening" token,
+ // add an extra blank for separation unless explicitly disabled
+ if p.mode&noExtraBlank == 0 &&
+ last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
+ tok != token.COMMA &&
+ (tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
+ (tok != token.RBRACK || p.prevOpen == token.LBRACK) {
p.writeByte(' ', 1)
}
// ensure that there is a line break after a //-style comment,
@@ -735,12 +791,8 @@ func (p *printer) writeWhitespace(n int) {
}
// shift remaining entries down
- i := 0
- for ; n < len(p.wsbuf); n++ {
- p.wsbuf[i] = p.wsbuf[n]
- i++
- }
- p.wsbuf = p.wsbuf[0:i]
+ l := copy(p.wsbuf, p.wsbuf[n:])
+ p.wsbuf = p.wsbuf[:l]
}
// ----------------------------------------------------------------------------
@@ -790,6 +842,17 @@ func (p *printer) print(args ...interface{}) {
var isLit bool
var impliedSemi bool // value for p.impliedSemi after this arg
+ // record previous opening token, if any
+ switch p.lastTok {
+ case token.ILLEGAL:
+ // ignore (white space)
+ case token.LPAREN, token.LBRACK:
+ p.prevOpen = p.lastTok
+ default:
+ // other tokens followed any opening token
+ p.prevOpen = token.ILLEGAL
+ }
+
switch x := arg.(type) {
case pmode:
// toggle printer mode
@@ -899,19 +962,17 @@ func (p *printer) print(args ...interface{}) {
}
}
+ // the next token starts now - record its line number if requested
+ if p.linePtr != nil {
+ *p.linePtr = p.out.Line
+ p.linePtr = nil
+ }
+
p.writeString(next, data, isLit)
p.impliedSemi = impliedSemi
}
}
-// commentBefore returns true iff the current comment group occurs
-// before the next position in the source code and printing it does
-// not introduce implicit semicolons.
-//
-func (p *printer) commentBefore(next token.Position) (result bool) {
- return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
-}
-
// 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