cue/ast: allow CommentGroup as declaration
This simplifies the construction of ASTs with
free-floating comments.
Also consecutive comment groups are now always
printed with a newline in between. To not do so,
one will have to merge two consecutive comment
groups manually. This more closely matches the
typical intention of comment groups.
Change-Id: Id4a601bd6d255aa6c6489f43df52534ac5303af9
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2000
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/ast.go b/cue/ast.go
index 1db9ad8..1485a2a 100644
--- a/cue/ast.go
+++ b/cue/ast.go
@@ -512,6 +512,9 @@
}
}
+ case *ast.CommentGroup:
+ // Nothing to do for a free-floating comment group.
+
// nothing to do
// case *syntax.EmitDecl:
default:
diff --git a/cue/ast/ast.go b/cue/ast/ast.go
index cc2e7eb..bd71220 100644
--- a/cue/ast/ast.go
+++ b/cue/ast/ast.go
@@ -85,6 +85,7 @@
func (*BadDecl) declNode() {}
func (*EmitDecl) declNode() {}
func (*Alias) declNode() {}
+func (*CommentGroup) declNode() {}
// A Label is any prduction that can be used as a LHS label.
type Label interface {
@@ -177,7 +178,7 @@
// A CommentGroup represents a sequence of comments
// with no other tokens and no empty lines between.
type CommentGroup struct {
- // TODO: remove and use the token position of the first commment.
+ // TODO: remove and use the token position of the first comment.
Doc bool
Line bool // true if it is on the same line as the node's end pos.
@@ -630,6 +631,9 @@
if d.Rparen.IsValid() {
return d.Rparen.Add(1)
}
+ if len(d.Specs) == 0 {
+ return token.NoPos
+ }
return d.Specs[0].End()
}
func (d *EmitDecl) End() token.Pos { return d.Expr.End() }
@@ -647,9 +651,10 @@
comments
Package token.Pos // position of "package" pseudo-keyword
Name *Ident // package names
+ Decls []Decl // top-level declarations; or nil
+
// TODO: Change Expr to Decl?
Imports []*ImportSpec // imports in this file
- Decls []Decl // top-level declarations; or nil
Unresolved []*Ident // unresolved identifiers in this file
}
@@ -662,6 +667,7 @@
}
return token.NoPos
}
+
func (f *File) End() token.Pos {
if n := len(f.Decls); n > 0 {
return f.Decls[n-1].End()
diff --git a/cue/ast/walk.go b/cue/ast/walk.go
index ce697ce..f11d06f 100644
--- a/cue/ast/walk.go
+++ b/cue/ast/walk.go
@@ -100,9 +100,7 @@
}
case *StructLit:
- for _, f := range n.Elts {
- walk(v, f)
- }
+ walkDeclList(v, n.Elts)
// Expressions
case *BottomLit, *BadExpr, *Ident, *BasicLit:
@@ -187,9 +185,6 @@
walk(v, n.Name)
}
walkDeclList(v, n.Decls)
- // don't walk n.Comments - they have been
- // visited already through the individual
- // nodes
case *ListComprehension:
walk(v, n.Expr)
diff --git a/cue/format/format.go b/cue/format/format.go
index 30df812..5b72b23 100644
--- a/cue/format/format.go
+++ b/cue/format/format.go
@@ -299,28 +299,37 @@
func (f *formatter) visitComments(until int8) {
c := &f.current
+ printed := false
for ; len(c.cg) > 0 && c.cg[0].Position <= until; c.cg = c.cg[1:] {
- f.Print(c.cg[0])
-
- printBlank := false
- if c.cg[0].Doc {
- f.Print(newline)
- printBlank = true
+ if printed {
+ f.Print(newsection)
}
- for _, c := range c.cg[0].List {
- isEnd := strings.HasPrefix(c.Text, "//")
- if !printBlank {
- if isEnd {
- f.Print(vtab)
- } else {
- f.Print(blank)
- }
- }
- f.Print(c.Slash)
- f.Print(c)
+ printed = true
+ f.printComment(c.cg[0])
+ }
+}
+
+func (f *formatter) printComment(cg *ast.CommentGroup) {
+ f.Print(cg)
+
+ printBlank := false
+ if cg.Doc {
+ f.Print(newline)
+ printBlank = true
+ }
+ for _, c := range cg.List {
+ isEnd := strings.HasPrefix(c.Text, "//")
+ if !printBlank {
if isEnd {
- f.Print(newline)
+ f.Print(vtab)
+ } else {
+ f.Print(blank)
}
}
+ f.Print(c.Slash)
+ f.Print(c)
+ if isEnd {
+ f.Print(newline)
+ }
}
}
diff --git a/cue/format/node.go b/cue/format/node.go
index a683890..527c92e 100644
--- a/cue/format/node.go
+++ b/cue/format/node.go
@@ -207,6 +207,7 @@
f.print(n.Import, "import")
if len(n.Specs) == 0 {
f.print(blank, n.Lparen, token.LPAREN, n.Rparen, token.RPAREN, newline)
+ break
}
switch {
case len(n.Specs) == 1:
@@ -232,6 +233,11 @@
f.print(blank, n.Equal, token.BIND, blank)
f.expr(n.Expr)
f.print(declcomma, newline) // implied
+
+ case *ast.CommentGroup:
+ f.print(newsection)
+ f.printComment(n)
+ f.print(newsection)
}
after:
f.after(decl)
diff --git a/cue/parser/walk.go b/cue/parser/walk.go
index 01a8220..f952f50 100644
--- a/cue/parser/walk.go
+++ b/cue/parser/walk.go
@@ -181,9 +181,6 @@
walk(v, n.Name)
}
walkDeclList(v, n.Decls)
- // don't walk n.Comments - they have been
- // visited already through the individual
- // nodes
case *ast.ListComprehension:
walk(v, n.Expr)