github.com/solo-io/cue@v0.4.7/internal/core/convert/go.go (about)

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package convert allows converting to and from Go values and Types.
    16  package convert
    17  
    18  import (
    19  	"encoding"
    20  	"encoding/json"
    21  	"fmt"
    22  	"math/big"
    23  	"reflect"
    24  	"sort"
    25  	"strconv"
    26  	"strings"
    27  
    28  	"github.com/cockroachdb/apd/v2"
    29  	"golang.org/x/text/encoding/unicode"
    30  
    31  	"github.com/solo-io/cue/cue/ast"
    32  	"github.com/solo-io/cue/cue/ast/astutil"
    33  	"github.com/solo-io/cue/cue/errors"
    34  	"github.com/solo-io/cue/cue/parser"
    35  	"github.com/solo-io/cue/cue/token"
    36  	"github.com/solo-io/cue/internal/core/adt"
    37  	"github.com/solo-io/cue/internal/core/compile"
    38  	"github.com/solo-io/cue/internal/types"
    39  )
    40  
    41  // This file contains functionality for converting Go to CUE.
    42  //
    43  // The code in this file is a prototype implementation and is far from
    44  // optimized.
    45  
    46  func GoValueToValue(ctx *adt.OpContext, x interface{}, nilIsTop bool) adt.Value {
    47  	v := GoValueToExpr(ctx, nilIsTop, x)
    48  	// TODO: return Value
    49  	return toValue(v)
    50  }
    51  
    52  func GoTypeToExpr(ctx *adt.OpContext, x interface{}) (adt.Expr, errors.Error) {
    53  	v := convertGoType(ctx, reflect.TypeOf(x))
    54  	if err := ctx.Err(); err != nil {
    55  		return v, err.Err
    56  	}
    57  	return v, nil
    58  }
    59  
    60  func toValue(e adt.Expr) adt.Value {
    61  	if v, ok := e.(adt.Value); ok {
    62  		return v
    63  	}
    64  	obj := &adt.Vertex{}
    65  	obj.AddConjunct(adt.MakeRootConjunct(nil, e))
    66  	return obj
    67  }
    68  
    69  func compileExpr(ctx *adt.OpContext, expr ast.Expr) adt.Value {
    70  	c, err := compile.Expr(nil, ctx, pkgID(), expr)
    71  	if err != nil {
    72  		return &adt.Bottom{Err: errors.Promote(err, "compile")}
    73  	}
    74  	return adt.Resolve(ctx, c)
    75  }
    76  
    77  // parseTag parses a CUE expression from a cue tag.
    78  func parseTag(ctx *adt.OpContext, obj *ast.StructLit, field, tag string) ast.Expr {
    79  	if p := strings.Index(tag, ","); p >= 0 {
    80  		tag = tag[:p]
    81  	}
    82  	if tag == "" {
    83  		return topSentinel
    84  	}
    85  	expr, err := parser.ParseExpr("<field:>", tag)
    86  	if err != nil {
    87  		err := errors.Promote(err, "parser")
    88  		ctx.AddErr(errors.Wrapf(err, ctx.Pos(),
    89  			"invalid tag %q for field %q", tag, field))
    90  		return &ast.BadExpr{}
    91  	}
    92  	return expr
    93  }
    94  
    95  // TODO: should we allow mapping names in cue tags? This only seems like a good
    96  // idea if we ever want to allow mapping CUE to a different name than JSON.
    97  var tagsWithNames = []string{"json", "yaml", "protobuf"}
    98  
    99  func getName(f *reflect.StructField) string {
   100  	name := f.Name
   101  	if f.Anonymous {
   102  		name = ""
   103  	}
   104  	for _, s := range tagsWithNames {
   105  		if tag, ok := f.Tag.Lookup(s); ok {
   106  			if p := strings.Index(tag, ","); p >= 0 {
   107  				tag = tag[:p]
   108  			}
   109  			if tag != "" {
   110  				name = tag
   111  				break
   112  			}
   113  		}
   114  	}
   115  	return name
   116  }
   117  
   118  // isOptional indicates whether a field should be marked as optional.
   119  func isOptional(f *reflect.StructField) bool {
   120  	isOptional := false
   121  	switch f.Type.Kind() {
   122  	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Interface, reflect.Slice:
   123  		// Note: it may be confusing to distinguish between an empty slice and
   124  		// a nil slice. However, it is also surprising to not be able to specify
   125  		// a default value for a slice. So for now we will allow it.
   126  		isOptional = true
   127  	}
   128  	if tag, ok := f.Tag.Lookup("cue"); ok {
   129  		// TODO: only if first field is not empty.
   130  		isOptional = false
   131  		for _, f := range strings.Split(tag, ",")[1:] {
   132  			switch f {
   133  			case "opt":
   134  				isOptional = true
   135  			case "req":
   136  				return false
   137  			}
   138  		}
   139  	} else if tag, ok = f.Tag.Lookup("json"); ok {
   140  		isOptional = false
   141  		for _, f := range strings.Split(tag, ",")[1:] {
   142  			if f == "omitempty" {
   143  				return true
   144  			}
   145  		}
   146  	}
   147  	return isOptional
   148  }
   149  
   150  // isOmitEmpty means that the zero value is interpreted as undefined.
   151  func isOmitEmpty(f *reflect.StructField) bool {
   152  	isOmitEmpty := false
   153  	switch f.Type.Kind() {
   154  	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Interface, reflect.Slice:
   155  		// Note: it may be confusing to distinguish between an empty slice and
   156  		// a nil slice. However, it is also surprising to not be able to specify
   157  		// a default value for a slice. So for now we will allow it.
   158  		isOmitEmpty = true
   159  
   160  	default:
   161  		// TODO: we can also infer omit empty if a type cannot be nil if there
   162  		// is a constraint that unconditionally disallows the zero value.
   163  	}
   164  	tag, ok := f.Tag.Lookup("json")
   165  	if ok {
   166  		isOmitEmpty = false
   167  		for _, f := range strings.Split(tag, ",")[1:] {
   168  			if f == "omitempty" {
   169  				return true
   170  			}
   171  		}
   172  	}
   173  	return isOmitEmpty
   174  }
   175  
   176  // parseJSON parses JSON into a CUE value. b must be valid JSON.
   177  func parseJSON(ctx *adt.OpContext, b []byte) adt.Value {
   178  	expr, err := parser.ParseExpr("json", b)
   179  	if err != nil {
   180  		panic(err) // cannot happen
   181  	}
   182  	return compileExpr(ctx, expr)
   183  }
   184  
   185  func isZero(v reflect.Value) bool {
   186  	x := v.Interface()
   187  	if x == nil {
   188  		return true
   189  	}
   190  	switch k := v.Kind(); k {
   191  	case reflect.Struct, reflect.Array:
   192  		// we never allow optional values for these types.
   193  		return false
   194  
   195  	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
   196  		reflect.Slice:
   197  		// Note that for maps we preserve the distinction between a nil map and
   198  		// an empty map.
   199  		return v.IsNil()
   200  
   201  	case reflect.String:
   202  		return v.Len() == 0
   203  
   204  	default:
   205  		return x == reflect.Zero(v.Type()).Interface()
   206  	}
   207  }
   208  
   209  func GoValueToExpr(ctx *adt.OpContext, nilIsTop bool, x interface{}) adt.Expr {
   210  	e := convertRec(ctx, nilIsTop, x)
   211  	if e == nil {
   212  		return ctx.AddErrf("unsupported Go type (%T)", x)
   213  	}
   214  	return e
   215  }
   216  
   217  func isNil(x reflect.Value) bool {
   218  	switch x.Kind() {
   219  	// Only check for supported types; ignore func and chan.
   220  	case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Interface:
   221  		return x.IsNil()
   222  	}
   223  	return false
   224  }
   225  
   226  func convertRec(ctx *adt.OpContext, nilIsTop bool, x interface{}) adt.Value {
   227  	if t := (&types.Value{}); types.CastValue(t, x) {
   228  		// TODO: panic if nto the same runtime.
   229  		return t.V
   230  	}
   231  	src := ctx.Source()
   232  	switch v := x.(type) {
   233  	case nil:
   234  		if nilIsTop {
   235  			ident, _ := ctx.Source().(*ast.Ident)
   236  			return &adt.Top{Src: ident}
   237  		}
   238  		return &adt.Null{Src: ctx.Source()}
   239  
   240  	case *ast.File:
   241  		x, err := compile.Files(nil, ctx, pkgID(), v)
   242  		if err != nil {
   243  			return &adt.Bottom{Err: errors.Promote(err, "compile")}
   244  		}
   245  		if len(x.Conjuncts) != 1 {
   246  			panic("unexpected length")
   247  		}
   248  		return x
   249  
   250  	case ast.Expr:
   251  		return compileExpr(ctx, v)
   252  
   253  	case *big.Int:
   254  		return &adt.Num{Src: src, K: adt.IntKind, X: *apd.NewWithBigInt(v, 0)}
   255  
   256  	case *big.Rat:
   257  		// should we represent this as a binary operation?
   258  		n := &adt.Num{Src: src, K: adt.IntKind}
   259  		_, err := apd.BaseContext.Quo(&n.X, apd.NewWithBigInt(v.Num(), 0), apd.NewWithBigInt(v.Denom(), 0))
   260  		if err != nil {
   261  			return ctx.AddErrf("could not convert *big.Rat: %v", err)
   262  		}
   263  		if !v.IsInt() {
   264  			n.K = adt.FloatKind
   265  		}
   266  		return n
   267  
   268  	case *big.Float:
   269  		n := &adt.Num{Src: src, K: adt.FloatKind}
   270  		_, _, err := n.X.SetString(v.String())
   271  		if err != nil {
   272  			return ctx.AddErr(errors.Promote(err, "invalid float"))
   273  		}
   274  		return n
   275  
   276  	case *apd.Decimal:
   277  		// TODO: should we allow an "int" bit to be set here? It is a bit
   278  		// tricky, as we would also need to pass down the result of rounding.
   279  		// So more likely an API must return explicitly whether a value is
   280  		// a float or an int after all.
   281  		// The code to autodetect whether something is an integer can be done
   282  		// with this:
   283  		kind := adt.FloatKind
   284  		var d apd.Decimal
   285  		res, _ := apd.BaseContext.RoundToIntegralExact(&d, v)
   286  		if !res.Inexact() {
   287  			kind = adt.IntKind
   288  		}
   289  		n := &adt.Num{Src: ctx.Source(), K: kind}
   290  		n.X = *v
   291  		return n
   292  
   293  	case json.Marshaler:
   294  		b, err := v.MarshalJSON()
   295  		if err != nil {
   296  			return ctx.AddErr(errors.Promote(err, "json.Marshaler"))
   297  		}
   298  
   299  		return parseJSON(ctx, b)
   300  
   301  	case encoding.TextMarshaler:
   302  		b, err := v.MarshalText()
   303  		if err != nil {
   304  			return ctx.AddErr(errors.Promote(err, "encoding.TextMarshaler"))
   305  		}
   306  		b, err = json.Marshal(string(b))
   307  		if err != nil {
   308  			return ctx.AddErr(errors.Promote(err, "json"))
   309  		}
   310  		return parseJSON(ctx, b)
   311  
   312  	case error:
   313  		var errs errors.Error
   314  		switch x := v.(type) {
   315  		case errors.Error:
   316  			errs = x
   317  		default:
   318  			errs = ctx.Newf("%s", x.Error())
   319  		}
   320  		return &adt.Bottom{Err: errs}
   321  	case bool:
   322  		return &adt.Bool{Src: ctx.Source(), B: v}
   323  	case string:
   324  		s, _ := unicode.UTF8.NewEncoder().String(v)
   325  		return &adt.String{Src: ctx.Source(), Str: s}
   326  	case []byte:
   327  		return &adt.Bytes{Src: ctx.Source(), B: v}
   328  	case int:
   329  		return toInt(ctx, int64(v))
   330  	case int8:
   331  		return toInt(ctx, int64(v))
   332  	case int16:
   333  		return toInt(ctx, int64(v))
   334  	case int32:
   335  		return toInt(ctx, int64(v))
   336  	case int64:
   337  		return toInt(ctx, int64(v))
   338  	case uint:
   339  		return toUint(ctx, uint64(v))
   340  	case uint8:
   341  		return toUint(ctx, uint64(v))
   342  	case uint16:
   343  		return toUint(ctx, uint64(v))
   344  	case uint32:
   345  		return toUint(ctx, uint64(v))
   346  	case uint64:
   347  		return toUint(ctx, uint64(v))
   348  	case uintptr:
   349  		return toUint(ctx, uint64(v))
   350  	case float64:
   351  		n := &adt.Num{Src: src, K: adt.FloatKind}
   352  		_, _, err := n.X.SetString(fmt.Sprint(v))
   353  		if err != nil {
   354  			return ctx.AddErr(errors.Promote(err, "invalid float"))
   355  		}
   356  		return n
   357  	case float32:
   358  		n := &adt.Num{Src: src, K: adt.FloatKind}
   359  		_, _, err := n.X.SetString(fmt.Sprint(v))
   360  		if err != nil {
   361  			return ctx.AddErr(errors.Promote(err, "invalid float"))
   362  		}
   363  		return n
   364  
   365  	case reflect.Value:
   366  		if v.CanInterface() {
   367  			return convertRec(ctx, nilIsTop, v.Interface())
   368  		}
   369  
   370  	default:
   371  		value := reflect.ValueOf(v)
   372  		switch value.Kind() {
   373  		case reflect.Bool:
   374  			return &adt.Bool{Src: ctx.Source(), B: value.Bool()}
   375  
   376  		case reflect.String:
   377  			str := value.String()
   378  			str, _ = unicode.UTF8.NewEncoder().String(str)
   379  			// TODO: here and above: allow to fail on invalid strings.
   380  			// if !utf8.ValidString(str) {
   381  			// 	return ctx.AddErrf("cannot convert result to string: invalid UTF-8")
   382  			// }
   383  			return &adt.String{Src: ctx.Source(), Str: str}
   384  
   385  		case reflect.Int, reflect.Int8, reflect.Int16,
   386  			reflect.Int32, reflect.Int64:
   387  			return toInt(ctx, value.Int())
   388  
   389  		case reflect.Uint, reflect.Uint8, reflect.Uint16,
   390  			reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   391  			return toUint(ctx, value.Uint())
   392  
   393  		case reflect.Float32, reflect.Float64:
   394  			return convertRec(ctx, nilIsTop, value.Float())
   395  
   396  		case reflect.Ptr:
   397  			if value.IsNil() {
   398  				if nilIsTop {
   399  					ident, _ := ctx.Source().(*ast.Ident)
   400  					return &adt.Top{Src: ident}
   401  				}
   402  				return &adt.Null{Src: ctx.Source()}
   403  			}
   404  			return convertRec(ctx, nilIsTop, value.Elem().Interface())
   405  
   406  		case reflect.Struct:
   407  			obj := &adt.StructLit{Src: src}
   408  			v := &adt.Vertex{}
   409  			env := ctx.Env(0)
   410  			if env == nil {
   411  				env = &adt.Environment{}
   412  			}
   413  			v.AddStruct(obj, env, adt.CloseInfo{})
   414  			v.SetValue(ctx, adt.Finalized, &adt.StructMarker{})
   415  
   416  			t := value.Type()
   417  			for i := 0; i < value.NumField(); i++ {
   418  				sf := t.Field(i)
   419  				if sf.PkgPath != "" {
   420  					continue
   421  				}
   422  				val := value.Field(i)
   423  				if !nilIsTop && isNil(val) {
   424  					continue
   425  				}
   426  				if tag, _ := sf.Tag.Lookup("json"); tag == "-" {
   427  					continue
   428  				}
   429  				if isOmitEmpty(&sf) && isZero(val) {
   430  					continue
   431  				}
   432  				sub := convertRec(ctx, nilIsTop, val.Interface())
   433  				if sub == nil {
   434  					// mimic behavior of encoding/json: skip fields of unsupported types
   435  					continue
   436  				}
   437  				if _, ok := sub.(*adt.Bottom); ok {
   438  					return sub
   439  				}
   440  
   441  				// leave errors like we do during normal evaluation or do we
   442  				// want to return the error?
   443  				name := getName(&sf)
   444  				if name == "-" {
   445  					continue
   446  				}
   447  				if sf.Anonymous && name == "" {
   448  					arc, ok := sub.(*adt.Vertex)
   449  					if ok {
   450  						v.Arcs = append(v.Arcs, arc.Arcs...)
   451  					}
   452  					continue
   453  				}
   454  
   455  				f := ctx.StringLabel(name)
   456  				obj.Decls = append(obj.Decls, &adt.Field{Label: f, Value: sub})
   457  				arc, ok := sub.(*adt.Vertex)
   458  				if ok {
   459  					a := *arc
   460  					arc = &a
   461  					arc.Label = f
   462  				} else {
   463  					arc = &adt.Vertex{Label: f, BaseValue: sub}
   464  					arc.UpdateStatus(adt.Finalized)
   465  					arc.AddConjunct(adt.MakeRootConjunct(nil, sub))
   466  				}
   467  				v.Arcs = append(v.Arcs, arc)
   468  			}
   469  
   470  			return v
   471  
   472  		case reflect.Map:
   473  			v := &adt.Vertex{BaseValue: &adt.StructMarker{}}
   474  			v.SetValue(ctx, adt.Finalized, &adt.StructMarker{})
   475  
   476  			t := value.Type()
   477  			switch key := t.Key(); key.Kind() {
   478  			default:
   479  				if !key.Implements(textMarshaler) {
   480  					return ctx.AddErrf("unsupported Go type for map key (%v)", key)
   481  				}
   482  				fallthrough
   483  			case reflect.String,
   484  				reflect.Int, reflect.Int8, reflect.Int16,
   485  				reflect.Int32, reflect.Int64,
   486  				reflect.Uint, reflect.Uint8, reflect.Uint16,
   487  				reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   488  
   489  				keys := value.MapKeys()
   490  				sort.Slice(keys, func(i, j int) bool {
   491  					return fmt.Sprint(keys[i]) < fmt.Sprint(keys[j])
   492  				})
   493  				for _, k := range keys {
   494  					val := value.MapIndex(k)
   495  					// if isNil(val) {
   496  					// 	continue
   497  					// }
   498  
   499  					sub := convertRec(ctx, nilIsTop, val.Interface())
   500  					// mimic behavior of encoding/json: report error of
   501  					// unsupported type.
   502  					if sub == nil {
   503  						return ctx.AddErrf("unsupported Go type (%T)", val.Interface())
   504  					}
   505  					if isBottom(sub) {
   506  						return sub
   507  					}
   508  
   509  					s := fmt.Sprint(k)
   510  					f := ctx.StringLabel(s)
   511  					arc, ok := sub.(*adt.Vertex)
   512  					if ok {
   513  						a := *arc
   514  						arc = &a
   515  						arc.Label = f
   516  					} else {
   517  						arc = &adt.Vertex{Label: f, BaseValue: sub}
   518  						arc.UpdateStatus(adt.Finalized)
   519  						arc.AddConjunct(adt.MakeRootConjunct(nil, sub))
   520  					}
   521  					v.Arcs = append(v.Arcs, arc)
   522  				}
   523  			}
   524  
   525  			return v
   526  
   527  		case reflect.Slice, reflect.Array:
   528  			var values []adt.Value
   529  
   530  			for i := 0; i < value.Len(); i++ {
   531  				val := value.Index(i)
   532  				x := convertRec(ctx, nilIsTop, val.Interface())
   533  				if x == nil {
   534  					return ctx.AddErrf("unsupported Go type (%T)",
   535  						val.Interface())
   536  				}
   537  				if isBottom(x) {
   538  					return x
   539  				}
   540  				values = append(values, x)
   541  			}
   542  
   543  			return ctx.NewList(values...)
   544  		}
   545  	}
   546  	return nil
   547  }
   548  
   549  func toInt(ctx *adt.OpContext, x int64) adt.Value {
   550  	n := &adt.Num{Src: ctx.Source(), K: adt.IntKind}
   551  	n.X = *apd.New(x, 0)
   552  	return n
   553  }
   554  
   555  func toUint(ctx *adt.OpContext, x uint64) adt.Value {
   556  	n := &adt.Num{Src: ctx.Source(), K: adt.IntKind}
   557  	n.X.Coeff.SetUint64(x)
   558  	return n
   559  }
   560  
   561  func convertGoType(ctx *adt.OpContext, t reflect.Type) adt.Expr {
   562  	// TODO: this can be much more efficient.
   563  	// TODO: synchronize
   564  	return goTypeToValue(ctx, true, t)
   565  }
   566  
   567  var (
   568  	jsonMarshaler = reflect.TypeOf(new(json.Marshaler)).Elem()
   569  	textMarshaler = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
   570  	topSentinel   = ast.NewIdent("_")
   571  )
   572  
   573  // goTypeToValue converts a Go Type to a value.
   574  //
   575  // TODO: if this value will always be unified with a concrete type in Go, then
   576  // many of the fields may be omitted.
   577  func goTypeToValue(ctx *adt.OpContext, allowNullDefault bool, t reflect.Type) adt.Expr {
   578  	if _, t, ok := ctx.LoadType(t); ok {
   579  		return t
   580  	}
   581  
   582  	_, v := goTypeToValueRec(ctx, allowNullDefault, t)
   583  	if v == nil {
   584  		return ctx.AddErrf("unsupported Go type (%v)", t)
   585  	}
   586  	return v
   587  }
   588  
   589  func goTypeToValueRec(ctx *adt.OpContext, allowNullDefault bool, t reflect.Type) (e ast.Expr, expr adt.Expr) {
   590  	if src, t, ok := ctx.LoadType(t); ok {
   591  		return src, t
   592  	}
   593  
   594  	switch reflect.Zero(t).Interface().(type) {
   595  	case *big.Int, big.Int:
   596  		e = ast.NewIdent("int")
   597  		goto store
   598  
   599  	case *big.Float, big.Float, *big.Rat, big.Rat:
   600  		e = ast.NewIdent("number")
   601  		goto store
   602  
   603  	case *apd.Decimal, apd.Decimal:
   604  		e = ast.NewIdent("number")
   605  		goto store
   606  	}
   607  
   608  	// Even if this is for types that we know cast to a certain type, it can't
   609  	// hurt to return top, as in these cases the concrete values will be
   610  	// strict instances and there cannot be any tags that further constrain
   611  	// the values.
   612  	if t.Implements(jsonMarshaler) || t.Implements(textMarshaler) {
   613  		return topSentinel, nil
   614  	}
   615  
   616  	switch k := t.Kind(); k {
   617  	case reflect.Ptr:
   618  		elem := t.Elem()
   619  		for elem.Kind() == reflect.Ptr {
   620  			elem = elem.Elem()
   621  		}
   622  		e, _ = goTypeToValueRec(ctx, false, elem)
   623  		if allowNullDefault {
   624  			e = wrapOrNull(e)
   625  		}
   626  
   627  	case reflect.Interface:
   628  		switch t.Name() {
   629  		case "error":
   630  			// This is really null | _|_. There is no error if the error is null.
   631  			e = ast.NewNull()
   632  		default:
   633  			e = topSentinel // `_`
   634  		}
   635  
   636  	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   637  		reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   638  		e = compile.LookupRange(t.Kind().String()).Source().(ast.Expr)
   639  
   640  	case reflect.Uint, reflect.Uintptr:
   641  		e = compile.LookupRange("uint64").Source().(ast.Expr)
   642  
   643  	case reflect.Int:
   644  		e = compile.LookupRange("int64").Source().(ast.Expr)
   645  
   646  	case reflect.String:
   647  		e = ast.NewIdent("__string")
   648  
   649  	case reflect.Bool:
   650  		e = ast.NewIdent("__bool")
   651  
   652  	case reflect.Float32, reflect.Float64:
   653  		e = ast.NewIdent("__number")
   654  
   655  	case reflect.Struct:
   656  		obj := &ast.StructLit{}
   657  
   658  		// TODO: dirty trick: set this to a temporary Vertex and then update the
   659  		// arcs and conjuncts of this vertex below. This will allow circular
   660  		// references. Maybe have a special kind of "hardlink" reference.
   661  		ctx.StoreType(t, obj, nil)
   662  
   663  		for i := 0; i < t.NumField(); i++ {
   664  			f := t.Field(i)
   665  			if f.PkgPath != "" {
   666  				continue
   667  			}
   668  			_, ok := f.Tag.Lookup("cue")
   669  			elem, _ := goTypeToValueRec(ctx, !ok, f.Type)
   670  			if isBad(elem) {
   671  				continue // Ignore fields for unsupported types
   672  			}
   673  
   674  			// leave errors like we do during normal evaluation or do we
   675  			// want to return the error?
   676  			name := getName(&f)
   677  			if name == "-" {
   678  				continue
   679  			}
   680  
   681  			if tag, ok := f.Tag.Lookup("cue"); ok {
   682  				v := parseTag(ctx, obj, name, tag)
   683  				if isBad(v) {
   684  					return v, nil
   685  				}
   686  				elem = ast.NewBinExpr(token.AND, elem, v)
   687  			}
   688  			// TODO: if an identifier starts with __ (or otherwise is not a
   689  			// valid CUE name), make it a string and create a map to a new
   690  			// name for references.
   691  
   692  			// The GO JSON decoder always allows a value to be undefined.
   693  			d := &ast.Field{Label: ast.NewIdent(name), Value: elem}
   694  			if isOptional(&f) {
   695  				d.Optional = token.Blank.Pos()
   696  			}
   697  			obj.Elts = append(obj.Elts, d)
   698  		}
   699  
   700  		// TODO: should we validate references here? Can be done using
   701  		// astutil.ToFile and astutil.Resolve.
   702  
   703  		e = obj
   704  
   705  	case reflect.Array, reflect.Slice:
   706  		if t.Elem().Kind() == reflect.Uint8 {
   707  			e = ast.NewIdent("__bytes")
   708  		} else {
   709  			elem, _ := goTypeToValueRec(ctx, allowNullDefault, t.Elem())
   710  			if elem == nil {
   711  				b := ctx.AddErrf("unsupported Go type (%v)", t.Elem())
   712  				return &ast.BadExpr{}, b
   713  			}
   714  
   715  			if t.Kind() == reflect.Array {
   716  				e = ast.NewBinExpr(token.MUL,
   717  					ast.NewLit(token.INT, strconv.Itoa(t.Len())),
   718  					ast.NewList(elem))
   719  			} else {
   720  				e = ast.NewList(&ast.Ellipsis{Type: elem})
   721  			}
   722  		}
   723  		if k == reflect.Slice {
   724  			e = wrapOrNull(e)
   725  		}
   726  
   727  	case reflect.Map:
   728  		switch key := t.Key(); key.Kind() {
   729  		case reflect.String, reflect.Int, reflect.Int8, reflect.Int16,
   730  			reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
   731  			reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   732  		default:
   733  			b := ctx.AddErrf("unsupported Go type for map key (%v)", key)
   734  			return &ast.BadExpr{}, b
   735  		}
   736  
   737  		v, x := goTypeToValueRec(ctx, allowNullDefault, t.Elem())
   738  		if v == nil {
   739  			b := ctx.AddErrf("unsupported Go type (%v)", t.Elem())
   740  			return &ast.BadExpr{}, b
   741  		}
   742  		if isBad(v) {
   743  			return v, x
   744  		}
   745  
   746  		e = ast.NewStruct(&ast.Field{
   747  			Label: ast.NewList(ast.NewIdent("__string")),
   748  			Value: v,
   749  		})
   750  
   751  		e = wrapOrNull(e)
   752  	}
   753  
   754  store:
   755  	// TODO: store error if not nil?
   756  	if e != nil {
   757  		f := &ast.File{Decls: []ast.Decl{&ast.EmbedDecl{Expr: e}}}
   758  		astutil.Resolve(f, func(_ token.Pos, msg string, args ...interface{}) {
   759  			ctx.AddErrf(msg, args...)
   760  		})
   761  		var x adt.Expr
   762  		c, err := compile.Expr(nil, ctx, pkgID(), e)
   763  		if err != nil {
   764  			b := &adt.Bottom{Err: err}
   765  			ctx.AddBottom(b)
   766  			x = b
   767  		} else {
   768  			x = c.Expr()
   769  		}
   770  		ctx.StoreType(t, e, x)
   771  		return e, x
   772  	}
   773  	return e, nil
   774  }
   775  
   776  func isBottom(x adt.Node) bool {
   777  	if x == nil {
   778  		return true
   779  	}
   780  	b, _ := x.(*adt.Bottom)
   781  	return b != nil
   782  }
   783  
   784  func isBad(x ast.Expr) bool {
   785  	if x == nil {
   786  		return true
   787  	}
   788  	if bad, _ := x.(*ast.BadExpr); bad != nil {
   789  		return true
   790  	}
   791  	return false
   792  }
   793  
   794  func wrapOrNull(e ast.Expr) ast.Expr {
   795  	switch x := e.(type) {
   796  	case *ast.BasicLit:
   797  		if x.Kind == token.NULL {
   798  			return x
   799  		}
   800  	case *ast.BadExpr:
   801  		return e
   802  	}
   803  	return makeNullable(e, true)
   804  }
   805  
   806  func makeNullable(e ast.Expr, nullIsDefault bool) ast.Expr {
   807  	var null ast.Expr = ast.NewNull()
   808  	if nullIsDefault {
   809  		null = &ast.UnaryExpr{Op: token.MUL, X: null}
   810  	}
   811  	return ast.NewBinExpr(token.OR, null, e)
   812  }
   813  
   814  // pkgID returns a package path that can never resolve to an existing package.
   815  func pkgID() string {
   816  	return "_"
   817  }