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