Commit 228903c5 authored by Robert Griesemer's avatar Robert Griesemer

go/printer: use general comment intersperse mechanism everywhere

- remove several TODOs
- as a side-effect, comment stylers are now used always and comments
  will be properly colored in godoc pkg documentation pages (and not
  only when looking at source text)

R=rsc
CC=golang-dev
https://golang.org/cl/222041
parent 16192c2d
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"bytes" "bytes"
"go/ast" "go/ast"
"go/token" "go/token"
"strings"
) )
...@@ -59,43 +60,25 @@ func (p *printer) linebreak(line, min, max int, ws whiteSpace, newSection bool) ...@@ -59,43 +60,25 @@ func (p *printer) linebreak(line, min, max int, ws whiteSpace, newSection bool)
} }
// TODO(gri): The code for printing lead and line comments // setComment sets g as the next comment if g != nil and if node comments
// should be eliminated in favor of reusing the // are enabled - this mode is used when printing source code fragments such
// comment intersperse mechanism above somehow. // as exports only. It assumes that there are no other pending comments to
// intersperse.
// Print a list of individual comments. func (p *printer) setComment(g *ast.CommentGroup) {
func (p *printer) commentList(list []*ast.Comment) { if g == nil || !p.useNodeComments {
for i, c := range list { return
t := c.Text
// TODO(gri): this needs to be styled like normal comments
p.print(c.Pos(), t)
if t[1] == '/' && i+1 < len(list) {
//-style comment which is not at the end; print a newline
p.print(newline)
}
} }
} if p.comments == nil {
// initialize p.comments lazily
p.comments = make([]*ast.CommentGroup, 1)
// Print a lead comment followed by a newline. } else if p.cindex < len(p.comments) {
func (p *printer) leadComment(d *ast.CommentGroup) { // for some reason there are pending comments; this
// Ignore the comment if we have comments interspersed (p.comment != nil). // should never happen - handle gracefully and flush
if p.comments == nil && d != nil { // all comments up to g, ignore anything after that
p.commentList(d.List) p.flush(g.List[0].Pos(), false)
p.print(newline)
}
}
// Print a tab followed by a line comment.
// A newline must be printed afterwards since
// the comment may be a //-style comment.
func (p *printer) lineComment(d *ast.CommentGroup) {
// Ignore the comment if we have comments interspersed (p.comment != nil).
if p.comments == nil && d != nil {
p.print(vtab)
p.commentList(d.List)
} }
p.comments[0] = g
p.cindex = 0
} }
...@@ -307,6 +290,11 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool { ...@@ -307,6 +290,11 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
} }
func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{noPos, strings.Bytes(text)}}})
}
func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete bool, ctxt exprContext) { func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete bool, ctxt exprContext) {
if !isIncomplete && !p.commentBefore(rbrace) { if !isIncomplete && !p.commentBefore(rbrace) {
// possibly a one-line struct/interface // possibly a one-line struct/interface
...@@ -350,7 +338,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok ...@@ -350,7 +338,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
} }
ml = false ml = false
extraTabs := 0 extraTabs := 0
p.leadComment(f.Doc) p.setComment(f.Doc)
if len(f.Names) > 0 { if len(f.Names) > 0 {
// named fields // named fields
p.identList(f.Names, &ml) p.identList(f.Names, &ml)
...@@ -372,17 +360,17 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok ...@@ -372,17 +360,17 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
} }
if f.Comment != nil { if f.Comment != nil {
for ; extraTabs > 0; extraTabs-- { for ; extraTabs > 0; extraTabs-- {
p.print(vtab) p.print(sep)
} }
p.lineComment(f.Comment) p.setComment(f.Comment)
} }
} }
if isIncomplete { if isIncomplete {
if len(list) > 0 { if len(list) > 0 {
p.print(formfeed) p.print(formfeed)
} }
// TODO(gri): this needs to be styled like normal comments p.flush(rbrace, false) // make sure we don't loose the last line comment
p.print("// contains unexported fields") p.setLineComment("// contains unexported fields")
} }
} else { // interface } else { // interface
...@@ -393,7 +381,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok ...@@ -393,7 +381,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
p.linebreak(f.Pos().Line, 1, 2, ignore, ml) p.linebreak(f.Pos().Line, 1, 2, ignore, ml)
} }
ml = false ml = false
p.leadComment(f.Doc) p.setComment(f.Doc)
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
// method // method
p.expr(f.Names[0], &ml) p.expr(f.Names[0], &ml)
...@@ -402,14 +390,14 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok ...@@ -402,14 +390,14 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
// embedded interface // embedded interface
p.expr(f.Type, &ml) p.expr(f.Type, &ml)
} }
p.lineComment(f.Comment) p.setComment(f.Comment)
} }
if isIncomplete { if isIncomplete {
if len(list) > 0 { if len(list) > 0 {
p.print(formfeed) p.print(formfeed)
} }
// TODO(gri): this needs to be styled like normal comments p.flush(rbrace, false) // make sure we don't loose the last line comment
p.print("// contains unexported methods") p.setLineComment("// contains unexported methods")
} }
} }
...@@ -1052,7 +1040,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo ...@@ -1052,7 +1040,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
switch s := spec.(type) { switch s := spec.(type) {
case *ast.ImportSpec: case *ast.ImportSpec:
p.leadComment(s.Doc) p.setComment(s.Doc)
if s.Name != nil { if s.Name != nil {
p.expr(s.Name, multiLine) p.expr(s.Name, multiLine)
p.print(blank) p.print(blank)
...@@ -1061,7 +1049,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo ...@@ -1061,7 +1049,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
comment = s.Comment comment = s.Comment
case *ast.ValueSpec: case *ast.ValueSpec:
p.leadComment(s.Doc) p.setComment(s.Doc)
p.identList(s.Names, multiLine) // always present p.identList(s.Names, multiLine) // always present
if n == 1 { if n == 1 {
if s.Type != nil { if s.Type != nil {
...@@ -1091,7 +1079,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo ...@@ -1091,7 +1079,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
comment = s.Comment comment = s.Comment
case *ast.TypeSpec: case *ast.TypeSpec:
p.leadComment(s.Doc) p.setComment(s.Doc)
p.expr(s.Name, multiLine) p.expr(s.Name, multiLine)
if n == 1 { if n == 1 {
p.print(blank) p.print(blank)
...@@ -1109,14 +1097,14 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo ...@@ -1109,14 +1097,14 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
for ; extraTabs > 0; extraTabs-- { for ; extraTabs > 0; extraTabs-- {
p.print(vtab) p.print(vtab)
} }
p.lineComment(comment) p.setComment(comment)
} }
} }
// Sets multiLine to true if the declaration spans multiple lines. // Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) genDecl(d *ast.GenDecl, context declContext, multiLine *bool) { func (p *printer) genDecl(d *ast.GenDecl, context declContext, multiLine *bool) {
p.leadComment(d.Doc) p.setComment(d.Doc)
p.print(d.Pos(), d.Tok, blank) p.print(d.Pos(), d.Tok, blank)
if d.Lparen.IsValid() { if d.Lparen.IsValid() {
...@@ -1225,7 +1213,7 @@ func distance(from, to token.Position) int { ...@@ -1225,7 +1213,7 @@ func distance(from, to token.Position) int {
// Sets multiLine to true if the declaration spans multiple lines. // 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, multiLine *bool) {
p.leadComment(d.Doc) p.setComment(d.Doc)
p.print(d.Pos(), token.FUNC, blank) p.print(d.Pos(), token.FUNC, blank)
if recv := d.Recv; recv != nil { if recv := d.Recv; recv != nil {
// method: print receiver // method: print receiver
...@@ -1276,7 +1264,7 @@ func declToken(decl ast.Decl) (tok token.Token) { ...@@ -1276,7 +1264,7 @@ func declToken(decl ast.Decl) (tok token.Token) {
func (p *printer) file(src *ast.File) { func (p *printer) file(src *ast.File) {
p.leadComment(src.Doc) p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank) p.print(src.Pos(), token.PACKAGE, blank)
p.expr(src.Name, ignoreMultiLine) p.expr(src.Name, ignoreMultiLine)
......
...@@ -89,8 +89,9 @@ type printer struct { ...@@ -89,8 +89,9 @@ type printer struct {
lastTaggedLine int // last line for which a line tag was written lastTaggedLine int // last line for which a line tag was written
// The list of all source comments, in order of appearance. // The list of all source comments, in order of appearance.
comments []*ast.CommentGroup // may be nil comments []*ast.CommentGroup // may be nil
cindex int // current comment index cindex int // current comment index
useNodeComments bool // if not set, ignore lead and line comments of nodes
} }
...@@ -246,7 +247,10 @@ func (p *printer) writeTaggedItem(data []byte, tag HTMLTag) { ...@@ -246,7 +247,10 @@ func (p *printer) writeTaggedItem(data []byte, tag HTMLTag) {
// immediately following the data. // immediately following the data.
// //
func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) { func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
p.pos = pos if pos.IsValid() {
// continue with previous position if we don't have a valid pos
p.pos = pos
}
if debug { if debug {
// do not update p.pos - use write0 // do not update p.pos - use write0
p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column))) p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)))
...@@ -734,14 +738,6 @@ func (p *printer) print(args ...) { ...@@ -734,14 +738,6 @@ func (p *printer) print(args ...) {
} }
p.buffer = p.buffer[0 : i+1] p.buffer = p.buffer[0 : i+1]
p.buffer[i] = x p.buffer[i] = x
case []byte:
// TODO(gri): remove this case once commentList
// handles comments correctly
data = x
case string:
// TODO(gri): remove this case once fieldList
// handles comments correctly
data = strings.Bytes(x)
case *ast.Ident: case *ast.Ident:
if p.Styler != nil { if p.Styler != nil {
data, tag = p.Styler.Ident(x) data, tag = p.Styler.Ident(x)
...@@ -976,13 +972,17 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) { ...@@ -976,13 +972,17 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
go func() { go func() {
switch n := node.(type) { switch n := node.(type) {
case ast.Expr: case ast.Expr:
p.useNodeComments = true
p.expr(n, ignoreMultiLine) p.expr(n, ignoreMultiLine)
case ast.Stmt: case ast.Stmt:
p.useNodeComments = true
p.stmt(n, ignoreMultiLine) p.stmt(n, ignoreMultiLine)
case ast.Decl: case ast.Decl:
p.useNodeComments = true
p.decl(n, atTop, ignoreMultiLine) p.decl(n, atTop, ignoreMultiLine)
case *ast.File: case *ast.File:
p.comments = n.Comments p.comments = n.Comments
p.useNodeComments = n.Comments == nil
p.file(n) p.file(n)
default: default:
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n)) p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))
......
...@@ -59,6 +59,15 @@ type I2 interface { ...@@ -59,6 +59,15 @@ type I2 interface {
G(x float) float // exported method G(x float) float // exported method
} }
// The S3 struct; all comments except for the last one must appear in the export.
type S3 struct {
// lead comment for F1
F1 int // line comment for F1
// lead comment for F2
F2 int // line comment for F2
f3 int // f3 is not exported
}
// This comment group should be separated // This comment group should be separated
// with a newline from the next comment // with a newline from the next comment
// group. // group.
......
...@@ -59,6 +59,15 @@ type I2 interface { ...@@ -59,6 +59,15 @@ type I2 interface {
G(x float) float // exported method G(x float) float // exported method
} }
// The S3 struct; all comments except for the last one must appear in the export.
type S3 struct {
// lead comment for F1
F1 int // line comment for F1
// lead comment for F2
F2 int // line comment for F2
f3 int // f3 is not exported
}
// This comment group should be separated // This comment group should be separated
// with a newline from the next comment // with a newline from the next comment
// group. // group.
......
...@@ -6,13 +6,11 @@ package main ...@@ -6,13 +6,11 @@ package main
// The SZ struct; it is empty. // The SZ struct; it is empty.
type SZ struct{} type SZ struct{}
// The S0 struct; no field is exported. // The S0 struct; no field is exported.
type S0 struct { type S0 struct {
// contains unexported fields // contains unexported fields
} }
// The S1 struct; some fields are not exported. // The S1 struct; some fields are not exported.
type S1 struct { type S1 struct {
S0 S0
...@@ -21,24 +19,20 @@ type S1 struct { ...@@ -21,24 +19,20 @@ type S1 struct {
// contains unexported fields // contains unexported fields
} }
// The S2 struct; all fields are exported. // The S2 struct; all fields are exported.
type S2 struct { type S2 struct {
S1 S1
A, B, C float // 3 exported fields A, B, C float // 3 exported fields
} }
// The IZ interface; it is empty. // The IZ interface; it is empty.
type SZ interface{} type SZ interface{}
// The I0 interface; no method is exported. // The I0 interface; no method is exported.
type I0 interface { type I0 interface {
// contains unexported methods // contains unexported methods
} }
// The I1 interface; some methods are not exported. // The I1 interface; some methods are not exported.
type I1 interface { type I1 interface {
I0 I0
...@@ -46,10 +40,18 @@ type I1 interface { ...@@ -46,10 +40,18 @@ type I1 interface {
// contains unexported methods // contains unexported methods
} }
// The I2 interface; all methods are exported. // The I2 interface; all methods are exported.
type I2 interface { type I2 interface {
I0 I0
F(x float) float // exported method F(x float) float // exported method
G(x float) float // exported method G(x float) float // exported method
} }
// The S3 struct; all comments except for the last one must appear in the export.
type S3 struct {
// lead comment for F1
F1 int // line comment for F1
// lead comment for F2
F2 int // line comment for F2
// contains unexported fields
}
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