From 228903c5da29fd4d65d244475348e85dab5e8841 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 24 Feb 2010 11:06:46 -0800 Subject: [PATCH] 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 --- src/pkg/go/printer/nodes.go | 90 +++++++++------------ src/pkg/go/printer/printer.go | 22 ++--- src/pkg/go/printer/testdata/comments.golden | 9 +++ src/pkg/go/printer/testdata/comments.input | 9 +++ src/pkg/go/printer/testdata/comments.x | 16 ++-- 5 files changed, 77 insertions(+), 69 deletions(-) diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go index e2cc2494846..dd6b1db6b23 100644 --- a/src/pkg/go/printer/nodes.go +++ b/src/pkg/go/printer/nodes.go @@ -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) diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go index 7321c0da1fd..95f0058c7f1 100644 --- a/src/pkg/go/printer/printer.go +++ b/src/pkg/go/printer/printer.go @@ -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)) diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden index 18a407478ec..2d4f434442f 100644 --- a/src/pkg/go/printer/testdata/comments.golden +++ b/src/pkg/go/printer/testdata/comments.golden @@ -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. diff --git a/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input index 8cba7e5a2cd..eec88bf95b9 100644 --- a/src/pkg/go/printer/testdata/comments.input +++ b/src/pkg/go/printer/testdata/comments.input @@ -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. diff --git a/src/pkg/go/printer/testdata/comments.x b/src/pkg/go/printer/testdata/comments.x index 19fa017bcf8..4d7a928ae09 100644 --- a/src/pkg/go/printer/testdata/comments.x +++ b/src/pkg/go/printer/testdata/comments.x @@ -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 +}