cue/ast: print StructLit in regular mode by default

Change-Id: I2e75ec87cf2770e6639b058fac3100ab2a8bef35
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5741
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast/ast.go b/cue/ast/ast.go
index b33204d..c0dcc1c 100644
--- a/cue/ast/ast.go
+++ b/cue/ast/ast.go
@@ -489,7 +489,10 @@
 // It will panic if a values not matching these patterns are given. Useful for
 // ASTs generated by code other than the CUE parser.
 func NewStruct(fields ...interface{}) *StructLit {
-	s := &StructLit{}
+	s := &StructLit{
+		// Set default positions so that comment attachment is as expected.
+		Lbrace: token.NoSpace.Pos(),
+	}
 	for i := 0; i < len(fields); i++ {
 		var (
 			label    Label
diff --git a/cue/export.go b/cue/export.go
index 3279d2a..b666f0f 100644
--- a/cue/export.go
+++ b/cue/export.go
@@ -541,7 +541,7 @@
 		// opUnifyUnchecked: represented as embedding. The two arguments must
 		// be structs.
 		if x.op == opUnifyUnchecked {
-			s := &ast.StructLit{}
+			s := ast.NewStruct()
 			return p.closeOrOpen(s, p.embedding(s, x))
 		}
 		return ast.NewBinExpr(opMap[x.op], p.expr(x.left), p.expr(x.right))
@@ -767,7 +767,7 @@
 }
 
 func (p *exporter) optionalsExpr(x *optionals, isClosed bool) ast.Expr {
-	st := &ast.StructLit{}
+	st := ast.NewStruct()
 	// An empty struct has meaning in case of closed structs, where they
 	// indicate no other fields may be added. Non-closed empty structs should
 	// have been optimized away. In case they are not, it is just a no-op.
@@ -828,7 +828,7 @@
 }
 
 func (p *exporter) structure(x *structLit, addTempl bool) (ret *ast.StructLit, err *bottom) {
-	obj := &ast.StructLit{}
+	obj := ast.NewStruct()
 	if doEval(p.mode) {
 		x, err = x.expandFields(p.ctx)
 		if err != nil {
diff --git a/cue/format/format_test.go b/cue/format/format_test.go
index e4e9be6..c596c36 100644
--- a/cue/format/format_test.go
+++ b/cue/format/format_test.go
@@ -29,6 +29,7 @@
 	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/cue/parser"
 	"cuelang.org/go/cue/token"
+	"cuelang.org/go/internal"
 )
 
 var (
@@ -253,10 +254,24 @@
 			Value: ast.NewIdent("goo"),
 		},
 		out: `"foo\nbar": goo`,
+	}, {
+		name: "foo",
+		in: func() ast.Node {
+			st := ast.NewStruct("version", ast.NewString("foo"))
+			st = ast.NewStruct("info", st)
+			ast.AddComment(st.Elts[0], internal.NewComment(true, "FOO"))
+			return st
+		}(),
+		out: `{
+	// FOO
+	info: {
+		version: "foo"
+	}
+}`,
 	}}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := Node(tc.in)
+			b, err := Node(tc.in, Simplify())
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -461,6 +476,7 @@
 func TestX(t *testing.T) {
 	t.Skip()
 	const src = `
+
 `
 	b, err := format([]byte(src), simplify)
 	if err != nil {
diff --git a/cue/format/node_test.go b/cue/format/node_test.go
index 855ae3c..a7ca3a4 100644
--- a/cue/format/node_test.go
+++ b/cue/format/node_test.go
@@ -38,7 +38,9 @@
 			ident("bar"), token.ISA, &ast.StructLit{},
 		)},
 		// Force a new struct.
-		out: `foo: bar :: {}`,
+		out: `foo: {
+	bar :: {}
+}`,
 	}, {
 		desc: "label with invalid identifier",
 		node: &ast.Field{Label: &ast.Ident{}, Value: ast.NewString("foo")},