cue/format: only format valid identifiers
Change-Id: Ic71bdacc4168671b34cdf61f0713b9012f0a0b38
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4722
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast/ident.go b/cue/ast/ident.go
index bbd4aea..a37c572 100644
--- a/cue/ast/ident.go
+++ b/cue/ast/ident.go
@@ -34,6 +34,9 @@
// IsValidIdent reports whether str is a valid identifier.
func IsValidIdent(ident string) bool {
+ if ident == "" {
+ return false
+ }
for i, r := range ident {
if isLetter(r) || r == '_' || r == '$' {
continue
diff --git a/cue/format/node.go b/cue/format/node.go
index 734a2a7..86309f4 100644
--- a/cue/format/node.go
+++ b/cue/format/node.go
@@ -59,7 +59,7 @@
goto unsupported
}
- return nil
+ return s.errs
unsupported:
return fmt.Errorf("cue/format: unsupported node type %T", node)
@@ -404,8 +404,8 @@
case *ast.Ident:
// Escape an identifier that has invalid characters. This may happen,
// if the AST is not generated by the parser.
- name, err := ast.QuoteIdent(n.Name)
- if err != nil {
+ name := n.Name
+ if !ast.IsValidIdent(name) {
name = strconv.Quote(n.Name)
}
f.print(n.NamePos, name)
diff --git a/cue/format/node_test.go b/cue/format/node_test.go
index dde17d9..b544f3b 100644
--- a/cue/format/node_test.go
+++ b/cue/format/node_test.go
@@ -15,6 +15,7 @@
package format
import (
+ "strings"
"testing"
"cuelang.org/go/cue/ast"
@@ -43,6 +44,11 @@
// Force a new struct.
out: `foo: bar :: {
}`,
+ }, {
+ desc: "label with invalid identifier",
+ node: &ast.Field{Label: &ast.Ident{}, Value: ast.NewString("foo")},
+ // Force a new struct.
+ out: `"": "foo"`,
}}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
@@ -58,3 +64,27 @@
})
}
}
+
+func TestErrors(t *testing.T) {
+ testCases := []struct {
+ desc string
+ node ast.Node
+ err string
+ }{{
+ desc: "empty identifier",
+ node: ast.NewIdent(""),
+ err: "invalid identifier",
+ }}
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ b, err := Node(tc.node)
+ if err == nil {
+ t.Fatalf("expected error, found %q", b)
+ }
+ got := err.Error()
+ if !strings.Contains(got, tc.err) {
+ t.Errorf("\ngot %v;\nwant %v", got, tc.err)
+ }
+ })
+ }
+}
diff --git a/cue/format/printer.go b/cue/format/printer.go
index 5258638..c9f43a3 100644
--- a/cue/format/printer.go
+++ b/cue/format/printer.go
@@ -21,6 +21,7 @@
"text/tabwriter"
"cuelang.org/go/cue/ast"
+ "cuelang.org/go/cue/errors"
"cuelang.org/go/cue/token"
)
@@ -42,6 +43,8 @@
output []byte
indent int
spaceBefore bool
+
+ errs errors.Error
}
type line int
@@ -51,6 +54,10 @@
p.pos = token.Position{Line: 1, Column: 1}
}
+func (p *printer) errf(n ast.Node, format string, args ...interface{}) {
+ p.errs = errors.Append(p.errs, errors.Newf(n.Pos(), format, args...))
+}
+
const debug = false
func (p *printer) internalError(msg ...interface{}) {
@@ -127,8 +134,9 @@
case *ast.Ident:
data = x.Name
- if q, err := ast.QuoteIdent(data); err == nil {
- data = q
+ if !ast.IsValidIdent(data) {
+ p.errf(x, "invalid identifier %q", x.Name)
+ data = "*bad identifier*"
}
impliedComma = true
p.lastTok = token.IDENT
diff --git a/cue/format/testdata/expressions.golden b/cue/format/testdata/expressions.golden
index 51c0577..64123e4 100644
--- a/cue/format/testdata/expressions.golden
+++ b/cue/format/testdata/expressions.golden
@@ -4,6 +4,8 @@
a: 1 // comment
aaa: 22 // comment
+ "": 3
+
b: 3
c: b: a: 4
diff --git a/cue/format/testdata/expressions.input b/cue/format/testdata/expressions.input
index 16f42d4..f36c7ef 100644
--- a/cue/format/testdata/expressions.input
+++ b/cue/format/testdata/expressions.input
@@ -4,6 +4,8 @@
a: 1 // comment
aaa: 22 // comment
+ "": 3
+
b: 3
c b a: 4
diff --git a/cue/parser/parser_test.go b/cue/parser/parser_test.go
index 3d9f5c5..e5eb5b6 100644
--- a/cue/parser/parser_test.go
+++ b/cue/parser/parser_test.go
@@ -173,6 +173,12 @@
`,
"a: {b: {c: d}}, c: a, d: a.b, e: a.b.c, \"f\": f, [X=_]: X",
}, {
+ "empty fields",
+ `
+ "": 3
+ `,
+ `"": 3`,
+ }, {
"expressions",
` a: (2 + 3) * 5
b: (2 + 3) + 4