]> Cypherpunks repositories - gostls13.git/commitdiff
go/printer: use general comment intersperse mechanism everywhere
authorRobert Griesemer <gri@golang.org>
Wed, 24 Feb 2010 19:06:46 +0000 (11:06 -0800)
committerRobert Griesemer <gri@golang.org>
Wed, 24 Feb 2010 19:06:46 +0000 (11:06 -0800)
- 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

src/pkg/go/printer/nodes.go
src/pkg/go/printer/printer.go
src/pkg/go/printer/testdata/comments.golden
src/pkg/go/printer/testdata/comments.input
src/pkg/go/printer/testdata/comments.x

index e2cc24948466090c37d2d618447a3b0ffed2f415..dd6b1db6b23a9de3446b3877270777ded4af2542 100644 (file)
@@ -12,6 +12,7 @@ import (
        "bytes"
        "go/ast"
        "go/token"
+       "strings"
 )
 
 
@@ -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
-//            should be eliminated in favor of reusing the
-//            comment intersperse mechanism above somehow.
-
-// Print a list of individual comments.
-func (p *printer) commentList(list []*ast.Comment) {
-       for i, c := range list {
-               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)
-               }
+// setComment sets g as the next comment if g != nil and if node comments
+// are enabled - this mode is used when printing source code fragments such
+// as exports only. It assumes that there are no other pending comments to
+// intersperse.
+func (p *printer) setComment(g *ast.CommentGroup) {
+       if g == nil || !p.useNodeComments {
+               return
        }
-}
-
-
-// Print a lead comment followed by a newline.
-func (p *printer) leadComment(d *ast.CommentGroup) {
-       // Ignore the comment if we have comments interspersed (p.comment != nil).
-       if p.comments == nil && d != nil {
-               p.commentList(d.List)
-               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)
+       if p.comments == nil {
+               // initialize p.comments lazily
+               p.comments = make([]*ast.CommentGroup, 1)
+       } else if p.cindex < len(p.comments) {
+               // for some reason there are pending comments; this
+               // should never happen - handle gracefully and flush
+               // all comments up to g, ignore anything after that
+               p.flush(g.List[0].Pos(), false)
        }
+       p.comments[0] = g
+       p.cindex = 0
 }
 
 
@@ -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) {
        if !isIncomplete && !p.commentBefore(rbrace) {
                // possibly a one-line struct/interface
@@ -350,7 +338,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
                        }
                        ml = false
                        extraTabs := 0
-                       p.leadComment(f.Doc)
+                       p.setComment(f.Doc)
                        if len(f.Names) > 0 {
                                // named fields
                                p.identList(f.Names, &ml)
@@ -372,17 +360,17 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
                        }
                        if f.Comment != nil {
                                for ; extraTabs > 0; extraTabs-- {
-                                       p.print(vtab)
+                                       p.print(sep)
                                }
-                               p.lineComment(f.Comment)
+                               p.setComment(f.Comment)
                        }
                }
                if isIncomplete {
                        if len(list) > 0 {
                                p.print(formfeed)
                        }
-                       // TODO(gri): this needs to be styled like normal comments
-                       p.print("// contains unexported fields")
+                       p.flush(rbrace, false) // make sure we don't loose the last line comment
+                       p.setLineComment("// contains unexported fields")
                }
 
        } else { // interface
@@ -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)
                        }
                        ml = false
-                       p.leadComment(f.Doc)
+                       p.setComment(f.Doc)
                        if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
                                // method
                                p.expr(f.Names[0], &ml)
@@ -402,14 +390,14 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
                                // embedded interface
                                p.expr(f.Type, &ml)
                        }
-                       p.lineComment(f.Comment)
+                       p.setComment(f.Comment)
                }
                if isIncomplete {
                        if len(list) > 0 {
                                p.print(formfeed)
                        }
-                       // TODO(gri): this needs to be styled like normal comments
-                       p.print("// contains unexported methods")
+                       p.flush(rbrace, false) // make sure we don't loose the last line comment
+                       p.setLineComment("// contains unexported methods")
                }
 
        }
@@ -1052,7 +1040,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
 
        switch s := spec.(type) {
        case *ast.ImportSpec:
-               p.leadComment(s.Doc)
+               p.setComment(s.Doc)
                if s.Name != nil {
                        p.expr(s.Name, multiLine)
                        p.print(blank)
@@ -1061,7 +1049,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
                comment = s.Comment
 
        case *ast.ValueSpec:
-               p.leadComment(s.Doc)
+               p.setComment(s.Doc)
                p.identList(s.Names, multiLine) // always present
                if n == 1 {
                        if s.Type != nil {
@@ -1091,7 +1079,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
                comment = s.Comment
 
        case *ast.TypeSpec:
-               p.leadComment(s.Doc)
+               p.setComment(s.Doc)
                p.expr(s.Name, multiLine)
                if n == 1 {
                        p.print(blank)
@@ -1109,14 +1097,14 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
                for ; extraTabs > 0; extraTabs-- {
                        p.print(vtab)
                }
-               p.lineComment(comment)
+               p.setComment(comment)
        }
 }
 
 
 // Sets multiLine to true if the declaration spans multiple lines.
 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)
 
        if d.Lparen.IsValid() {
@@ -1225,7 +1213,7 @@ func distance(from, to token.Position) int {
 
 // Sets multiLine to true if the declaration spans multiple lines.
 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
-       p.leadComment(d.Doc)
+       p.setComment(d.Doc)
        p.print(d.Pos(), token.FUNC, blank)
        if recv := d.Recv; recv != nil {
                // method: print receiver
@@ -1276,7 +1264,7 @@ func declToken(decl ast.Decl) (tok token.Token) {
 
 
 func (p *printer) file(src *ast.File) {
-       p.leadComment(src.Doc)
+       p.setComment(src.Doc)
        p.print(src.Pos(), token.PACKAGE, blank)
        p.expr(src.Name, ignoreMultiLine)
 
index 7321c0da1fd2ed757f4c57febbfd42cdeec8c100..95f0058c7f110b6520605f8db615164b3247055c 100644 (file)
@@ -89,8 +89,9 @@ type printer struct {
        lastTaggedLine int // last line for which a line tag was written
 
        // The list of all source comments, in order of appearance.
-       comments []*ast.CommentGroup // may be nil
-       cindex   int                 // current comment index
+       comments        []*ast.CommentGroup // may be nil
+       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) {
 // immediately following the data.
 //
 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 {
                // do not update p.pos - use write0
                p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)))
@@ -734,14 +738,6 @@ func (p *printer) print(args ...) {
                        }
                        p.buffer = p.buffer[0 : i+1]
                        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:
                        if p.Styler != nil {
                                data, tag = p.Styler.Ident(x)
@@ -976,13 +972,17 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
        go func() {
                switch n := node.(type) {
                case ast.Expr:
+                       p.useNodeComments = true
                        p.expr(n, ignoreMultiLine)
                case ast.Stmt:
+                       p.useNodeComments = true
                        p.stmt(n, ignoreMultiLine)
                case ast.Decl:
+                       p.useNodeComments = true
                        p.decl(n, atTop, ignoreMultiLine)
                case *ast.File:
                        p.comments = n.Comments
+                       p.useNodeComments = n.Comments == nil
                        p.file(n)
                default:
                        p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))
index 18a407478ecb8363e669d4f806bc9e096d45627e..2d4f434442f04f06e14e175818ee9c4b2d1a3593 100644 (file)
@@ -59,6 +59,15 @@ type I2 interface {
        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
 // with a newline from the next comment
 // group.
index 8cba7e5a2cd4090bb132477e6ffcbb39011165e5..eec88bf95b90e71109dd2fae01293094110f7d9e 100644 (file)
@@ -59,6 +59,15 @@ type I2 interface {
        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
 // with a newline from the next comment
 // group.
index 19fa017bcf8aace3423bc4e333970b9267387af7..4d7a928ae096ebf5a2ab96d6d48007a117964959 100644 (file)
@@ -6,13 +6,11 @@ package main
 // The SZ struct; it is empty.
 type SZ struct{}
 
-
 // The S0 struct; no field is exported.
 type S0 struct {
        // contains unexported fields
 }
 
-
 // The S1 struct; some fields are not exported.
 type S1 struct {
        S0
@@ -21,24 +19,20 @@ type S1 struct {
        // contains unexported fields
 }
 
-
 // The S2 struct; all fields are exported.
 type S2 struct {
        S1
        A, B, C float   // 3 exported fields
 }
 
-
 // The IZ interface; it is empty.
 type SZ interface{}
 
-
 // The I0 interface; no method is exported.
 type I0 interface {
        // contains unexported methods
 }
 
-
 // The I1 interface; some methods are not exported.
 type I1 interface {
        I0
@@ -46,10 +40,18 @@ type I1 interface {
        // contains unexported methods
 }
 
-
 // The I2 interface; all methods are exported.
 type I2 interface {
        I0
        F(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
+}