internal/core/export: better handling of generated CUE
Generated CUE structs can organized somewhat different from
the ones computed during evaluation. Most notably, conjuncts
can be a Vertex. Handle this.
Fixes #499
Change-Id: I752e2d09ab7f49476d331028a75c1a9c8f9d480a
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7123
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/internal/core/export/export_test.go b/internal/core/export/export_test.go
index 1b415d2..69a44db 100644
--- a/internal/core/export/export_test.go
+++ b/internal/core/export/export_test.go
@@ -22,7 +22,10 @@
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/format"
+ "cuelang.org/go/internal"
+ "cuelang.org/go/internal/core/adt"
"cuelang.org/go/internal/core/compile"
+ "cuelang.org/go/internal/core/convert"
"cuelang.org/go/internal/core/eval"
"cuelang.org/go/internal/core/export"
"cuelang.org/go/internal/core/runtime"
@@ -69,6 +72,75 @@
return b
}
+// TestGenerated tests conversions of generated Go structs, which may be
+// different from parsed or evaluated CUE, such as having Vertex values.
+func TestGenerated(t *testing.T) {
+ testCases := []struct {
+ in interface{}
+ value string
+ typ string
+ }{{
+ in: &C{
+ Terminals: []*A{
+ {Name: "Name", Description: "Desc"},
+ },
+ },
+ value: `{Terminals: [{Description: "Desc", Name: "Name"}]}`,
+ typ: `*null|{Terminals?: *null|[...*null|{Name: string, Description: string}]}`,
+ }, {
+ in: []*A{
+ {Name: "Name", Description: "Desc"},
+ },
+ value: `[{Name: "Name", Description: "Desc"}]`,
+ typ: `*null|[...*null|{Name: string, Description: string}]`,
+ }}
+ for _, tc := range testCases {
+ t.Run("", func(t *testing.T) {
+ r := runtime.New()
+ e := eval.New(r)
+ ctx := adt.NewContext(r, e, &adt.Vertex{})
+
+ v := convert.GoValueToValue(ctx, tc.in, false)
+
+ expr, err := export.Expr(ctx, v)
+ if err != nil {
+ t.Fatal(err)
+ }
+ got := internal.DebugStr(expr)
+ if got != tc.value {
+ t.Errorf("value: got: %s\nwant: %s", got, tc.value)
+ }
+
+ x, err := convert.GoTypeToExpr(ctx, tc.in)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expr, err = export.Expr(ctx, x)
+ if err != nil {
+ t.Fatal(err)
+ }
+ got = internal.DebugStr(expr)
+ if got != tc.typ {
+ t.Errorf("type: got: %s\nwant: %s", got, tc.typ)
+ }
+
+ })
+ }
+}
+
+type A struct {
+ Name string
+ Description string
+}
+
+type B struct {
+ Image string
+}
+
+type C struct {
+ Terminals []*A
+}
+
// For debugging purposes. Do not delete.
func TestX(t *testing.T) {
t.Skip()
diff --git a/internal/core/export/expr.go b/internal/core/export/expr.go
index 7f130f5..d58eff8 100644
--- a/internal/core/export/expr.go
+++ b/internal/core/export/expr.go
@@ -263,9 +263,20 @@
case adt.Value: // other values.
if v, ok := x.(*adt.Vertex); ok {
- // if !v.IsList() {
- // panic("what to do?") // TO
- // }
+ if v.IsList() {
+ a := []ast.Expr{}
+ for _, x := range v.Elems() {
+ a = append(a, e.expr(x))
+ }
+ if !v.IsClosed(e.ctx) {
+ v := &adt.Vertex{}
+ v.MatchAndInsert(e.ctx, v)
+ a = append(a, &ast.Ellipsis{Type: e.expr(v)})
+ }
+ e.exprs = append(e.exprs, ast.NewList(a...))
+ return
+ }
+
e.structs = append(e.structs, v.Structs...)
// generated, only consider arcs.