//
type CommentGroup struct {
List []*Comment
- Next *CommentGroup // next comment group in source order
}
// A File node represents a Go source file.
//
+// The Comments list contains all comments in the source file in order of
+// appearance, including the comments that are pointed to from other nodes
+// via Doc and Comment fields.
+//
type File struct {
- Doc *CommentGroup // associated documentation; or nil
- token.Position // position of "package" keyword
- Name *Ident // package name
- Decls []Decl // top-level declarations
- Comments *CommentGroup // list of all comments in the source file
+ Doc *CommentGroup // associated documentation; or nil
+ token.Position // position of "package" keyword
+ Name *Ident // package name
+ Decls []Decl // top-level declarations
+ Comments []*CommentGroup // list of all comments in the source file
}
return true
}
case *TypeSpec:
- // TODO(gri) consider stripping forward declarations
- // of structs, interfaces, functions, and methods
if s.Name.IsExported() {
filterType(s.Type)
return true
d.Specs = filterSpecList(d.Specs)
return len(d.Specs) > 0
case *FuncDecl:
- // TODO consider removing function declaration altogether if
- // forward declaration (i.e., if d.Body == nil) because
- // in that case the actual declaration will come later.
d.Body = nil // strip body
return d.Name.IsExported()
}
}
}
}
- doc = &CommentGroup{list, nil}
+ doc = &CommentGroup{list}
}
// Collect declarations from all package files.
}
}
- // TODO(gri) Should collect comments as well. For that the comment
- // list should be changed back into a []*CommentGroup,
- // otherwise need to modify the existing linked list.
+ // TODO(gri) Should collect comments as well.
return &File{doc, noPos, NewIdent(pkg.Name), decls, nil}
}
for _, c := range n.List {
Walk(v, c)
}
- // TODO(gri): Keep comments in a list/vector instead
- // of linking them via Next. Following next will lead
- // to multiple visits and potentially n^2 behavior
- // since Doc and Comments fields point into the global
- // comments list.
case *Field:
walkCommentGroup(v, n.Doc)
walkCommentGroup(v, n.Doc)
walkIdent(v, n.Name)
Walk(v, n.Decls)
- walkCommentGroup(v, n.Comments)
+ for _, g := range n.Comments {
+ Walk(v, g)
+ }
case *Package:
for _, f := range n.Files {
}
// collect BUG(...) comments
- for c := src.Comments; c != nil; c = c.Next {
+ for _, c := range src.Comments {
text := c.List[0].Text
cstr := string(text)
if m := bug_markers.ExecuteString(cstr); len(m) > 0 {
// non-empty BUG comment; collect comment without BUG prefix
list := copyCommentList(c.List)
list[0].Text = text[m[1]:]
- doc.bugs.Push(&ast.CommentGroup{list, nil})
+ doc.bugs.Push(&ast.CommentGroup{list})
}
}
}
indent uint // indentation used for tracing output
// Comments
- comments *ast.CommentGroup // list of collected comments
+ comments vector.Vector // list of *CommentGroup
lastComment *ast.CommentGroup // last comment in the comments list
leadComment *ast.CommentGroup // the last lead comment
lineComment *ast.CommentGroup // the last line comment
}
// add comment group to the comments list
- g := &ast.CommentGroup{group, nil}
- if p.lastComment != nil {
- p.lastComment.Next = g
- } else {
- p.comments = g
- }
+ g := &ast.CommentGroup{group}
+ p.comments.Push(g)
p.lastComment = g
return endline
}
}
- return &ast.File{doc, pos, ident, decls, p.comments}
+ // convert comments list
+ comments := make([]*ast.CommentGroup, len(p.comments))
+ for i, x := range p.comments {
+ comments[i] = x.(*ast.CommentGroup)
+ }
+
+ return &ast.File{doc, pos, ident, decls, comments}
}
// 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.comment == nil && d != nil {
+ if p.comments == nil && d != nil {
p.commentList(d.List)
p.print(newline)
}
// 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.comment == nil && d != nil {
+ if p.comments == nil && d != nil {
p.print(vtab)
p.commentList(d.List)
}
// Remove this after transitioning to new semicolon syntax and
// some reasonable grace period (12/11/09).
func (p *printer) beforeComment(pos token.Position) token.Position {
- if p.comment != nil {
- p := p.comment.List[0].Position
+ if p.cindex < len(p.comments) {
+ p := p.comments[p.cindex].List[0].Position
if !pos.IsValid() || pos.Offset > p.Offset {
return p
}
// Remove this after transitioning to new semicolon
// syntax and some reasonable grace period (12/11/09).
if p.commentBefore(pos) {
- p.comment.List[0].Position = pos
+ p.comments[p.cindex].List[0].Position = pos
}
}
// HTML support
lastTaggedLine int // last line for which a line tag was written
- // The list of comments; or nil.
- comment *ast.CommentGroup
+ // The list of all source comments, in order of appearance.
+ comments []*ast.CommentGroup // may be nil
+ cindex int // current comment index
}
isFirst := true
needsLinebreak := false
var last *ast.Comment
- for ; p.commentBefore(next); p.comment = p.comment.Next {
- for _, c := range p.comment.List {
+ for ; p.commentBefore(next); p.cindex++ {
+ for _, c := range p.comments[p.cindex].List {
p.writeCommentPrefix(c.Pos(), next, isFirst, isKeyword)
isFirst = false
p.writeComment(c)
// before the next position in the source code.
//
func (p *printer) commentBefore(next token.Position) bool {
- return p.comment != nil && p.comment.List[0].Pos().Offset < next.Offset
+ return p.cindex < len(p.comments) && p.comments[p.cindex].List[0].Pos().Offset < next.Offset
}
case ast.Decl:
p.decl(n, atTop, ignoreMultiLine)
case *ast.File:
- p.comment = n.Comments
+ p.comments = n.Comments
p.file(n)
default:
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))