cue: fix attribute parsing bugs
One check caused spurious errors and another
bug caused this error to silently drop the
corresponding field.
Change-Id: Ib38939abf190668925063fab7a96d92062af3d0a
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2711
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast.go b/cue/ast.go
index 267a125..df566c4 100644
--- a/cue/ast.go
+++ b/cue/ast.go
@@ -362,7 +362,7 @@
v.sel, _ = ast.LabelName(x)
attrs, err := createAttrs(v.ctx(), newNode(n), n.Attrs)
if err != nil {
- return err
+ return v.errf(n, err.format, err.args)
}
f, ok := v.nodeLabel(x)
if !ok {
diff --git a/cue/ast_test.go b/cue/ast_test.go
index 806cce1..5fa74fb 100644
--- a/cue/ast_test.go
+++ b/cue/ast_test.go
@@ -247,6 +247,16 @@
`,
out: `<0>{a: _|_(preference mark not allowed at this position), ` +
`b: (*_|_(preference mark not allowed at this position) | 2)}`,
+ }, {
+ in: `
+ a: int @foo(1,"str")
+ `,
+ out: "<0>{a: int @foo(1,\"str\")}",
+ }, {
+ in: `
+ a: int @b('' ,b) // invalid
+ `,
+ out: "attribute missing ')':\n test:2:16\nmissing ',' in file:\n test:3:3\n<0>{}",
}}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
diff --git a/cue/attr.go b/cue/attr.go
index a00982d..636fa05 100644
--- a/cue/attr.go
+++ b/cue/attr.go
@@ -45,7 +45,7 @@
return a.text[a.offset+1 : len(a.text)-1]
}
-func createAttrs(ctx *context, src source, attrs []*ast.Attribute) (a *attributes, err evaluated) {
+func createAttrs(ctx *context, src source, attrs []*ast.Attribute) (a *attributes, err *bottom) {
if len(attrs) == 0 {
return nil, nil
}
@@ -57,6 +57,10 @@
return nil, ctx.mkErr(newNode(a), "invalid attribute %q", a.Text)
}
as = append(as, attr{a.Text[:n], index})
+
+ if err := parseAttrBody(ctx, src, a.Text[index+1:n-1], nil); err != nil {
+ return nil, err
+ }
}
sort.Slice(as, func(i, j int) bool { return as[i].text < as[j].text })
@@ -67,11 +71,6 @@
}
}
- for _, a := range attrs {
- if err := parseAttrBody(ctx, src, a.Text, nil); err != nil {
- return nil, err
- }
- }
return &attributes{as}, nil
}
@@ -131,7 +130,7 @@
func (kv *keyValue) key() string { return kv.data[:kv.equal] }
func (kv *keyValue) value() string { return kv.data[kv.equal+1:] }
-func parseAttrBody(ctx *context, src source, s string, a *parsedAttr) (err evaluated) {
+func parseAttrBody(ctx *context, src source, s string, a *parsedAttr) (err *bottom) {
i := 0
for {
// always scan at least one, possibly empty element.
@@ -150,7 +149,7 @@
return nil
}
-func scanAttributeElem(ctx *context, src source, s string, a *parsedAttr) (n int, err evaluated) {
+func scanAttributeElem(ctx *context, src source, s string, a *parsedAttr) (n int, err *bottom) {
// try CUE string
kv := keyValue{}
if n, kv.data, err = scanAttributeString(ctx, src, s); n == 0 {
@@ -187,7 +186,7 @@
return n, err
}
-func scanAttributeString(ctx *context, src source, s string) (n int, str string, err evaluated) {
+func scanAttributeString(ctx *context, src source, s string) (n int, str string, err *bottom) {
if s == "" || (s[0] != '#' && s[0] != '"' && s[0] != '\'') {
return 0, "", nil
}
diff --git a/cue/attr_test.go b/cue/attr_test.go
index d3f08fd..3f30f79 100644
--- a/cue/attr_test.go
+++ b/cue/attr_test.go
@@ -37,6 +37,9 @@
in: "a,",
out: "[{a 0} { 0}]",
}, {
+ in: `"a",`,
+ out: "[{a 0} { 0}]",
+ }, {
in: "a,b",
out: "[{a 0} {b 0}]",
}, {
@@ -118,6 +121,18 @@
}, {
in: "@b('' ,b)",
err: "invalid attribute",
+ }, {
+ in: `@foo(,"bar")`,
+ out: `foo:,"bar"`,
+ }, {
+ in: `@foo("bar",1)`,
+ out: `foo:"bar",1`,
+ }, {
+ in: `@foo("bar")`,
+ out: `foo:"bar"`,
+ }, {
+ in: `@foo(,"bar",1)`,
+ out: `foo:,"bar",1`,
}}
for _, tc := range testdata {
t.Run(tc.in, func(t *testing.T) {
diff --git a/cue/export_test.go b/cue/export_test.go
index 9da8857..de354eb 100644
--- a/cue/export_test.go
+++ b/cue/export_test.go
@@ -382,6 +382,26 @@
a: b - 100
b: a + 100
}`),
+ }, {
+ in: `A: {
+ <_>: B
+ } @protobuf(1,"test")
+
+ B: {}
+ B: {a: int} | {b: int}
+ `,
+ out: unindent(`
+ {
+ A: {
+ <_>: B
+ } @protobuf(1,"test")
+ B: {
+ } & ({
+ a: int
+ } | {
+ b: int
+ })
+ }`),
}}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
diff --git a/cue/parser/parser_test.go b/cue/parser/parser_test.go
index 053e9b1..89973a5 100644
--- a/cue/parser/parser_test.go
+++ b/cue/parser/parser_test.go
@@ -69,9 +69,9 @@
b: 2 @foo(a,b=4) @go(Foo)
c: {
d: "x" @go(D) @json(,omitempty)
- e: "y" @ts(,type=string)
+ e: "y" @ts(,type=string,"str")
}`,
- `a: 1 @xml(,attr), b: 2 @foo(a,b=4) @go(Foo), c: {d: "x" @go(D) @json(,omitempty), e: "y" @ts(,type=string)}`,
+ `a: 1 @xml(,attr), b: 2 @foo(a,b=4) @go(Foo), c: {d: "x" @go(D) @json(,omitempty), e: "y" @ts(,type=string,"str")}`,
}, {
"not emitted",
`a: true
diff --git a/cue/types.go b/cue/types.go
index cb39921..9133853 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -1522,7 +1522,7 @@
}
at := Attribute{}
if err := parseAttrBody(v.ctx(), nil, a.body(), &at.attr); err != nil {
- return Attribute{err: err.(error)}
+ return Attribute{err: v.toErr(err)}
}
return at
}