blob: b2610b6b3908c89e87286111951c34852befe10c [file] [log] [blame]
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +02001// 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
15package cue
16
17import (
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +020018 "encoding"
19 "encoding/json"
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +020020 "fmt"
21 "math/big"
22 "reflect"
23 "sort"
24 "strings"
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +020025 "sync"
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +020026
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +020027 "cuelang.org/go/cue/parser"
Marcel van Lohuizen2b85fc82019-04-03 22:43:29 +020028 "cuelang.org/go/internal"
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +020029 "github.com/cockroachdb/apd"
30)
31
32// This file contains functionality for converting Go to CUE.
Marcel van Lohuizen2b85fc82019-04-03 22:43:29 +020033//
34// The code in this file is a prototype implementation and is far from
35// optimized.
36
37func init() {
38 internal.FromGoValue = func(instance, x interface{}) interface{} {
39 return convertValue(instance.(*Instance), x)
40 }
41
42 internal.FromGoType = func(instance, x interface{}) interface{} {
43 return convertType(instance.(*Instance), x)
44 }
45}
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +020046
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +020047func convertValue(inst *Instance, x interface{}) Value {
48 ctx := inst.index.newContext()
49 v := convert(ctx, baseValue{}, x)
50 return newValueRoot(ctx, v)
51}
52
53func convertType(inst *Instance, x interface{}) Value {
54 ctx := inst.index.newContext()
55 v := convertGoType(inst, reflect.TypeOf(x))
56 return newValueRoot(ctx, v)
57
58}
59
60// parseTag parses a CUE expression from a cue tag.
61func parseTag(ctx *context, obj *structLit, field label, tag string) value {
62 if p := strings.Index(tag, ","); p >= 0 {
63 tag = tag[:p]
64 }
65 if tag == "" {
66 return &top{}
67 }
68 expr, err := parser.ParseExpr(ctx.index.fset, "<field:>", tag)
69 if err != nil {
70 field := ctx.labelStr(field)
71 return ctx.mkErr(baseValue{}, "invalid tag %q for field %q: %v", tag, field, err)
72 }
73 v := newVisitor(ctx.index, nil, nil, obj)
74 return v.walk(expr)
75}
76
77// TODO: should we allow mapping names in cue tags? This only seems like a good
78// idea if we ever want to allow mapping CUE to a different name than JSON.
79var tagsWithNames = []string{"json", "yaml", "protobuf"}
80
81func getName(f *reflect.StructField) string {
82 name := f.Name
83 for _, s := range tagsWithNames {
84 if tag, ok := f.Tag.Lookup(s); ok {
85 if p := strings.Index(tag, ","); p >= 0 {
86 tag = tag[:p]
87 }
88 if tag != "" {
89 name = tag
90 break
91 }
92 }
93 }
94 return name
95}
96
97// isOptional indicates whether a field should be marked as optional.
98func isOptional(f *reflect.StructField) bool {
99 isOptional := false
100 switch f.Type.Kind() {
101 case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Interface, reflect.Slice:
102 // Note: it may be confusing to distinguish between an empty slice and
103 // a nil slice. However, it is also surprizing to not be able to specify
104 // a default value for a slice. So for now we will allow it.
105 isOptional = true
106 }
107 if tag, ok := f.Tag.Lookup("cue"); ok {
108 // TODO: only if first field is not empty.
109 isOptional = false
110 for _, f := range strings.Split(tag, ",")[1:] {
111 switch f {
112 case "opt":
113 isOptional = true
114 case "req":
115 return false
116 }
117 }
118 } else if tag, ok = f.Tag.Lookup("json"); ok {
119 isOptional = false
120 for _, f := range strings.Split(tag, ",")[1:] {
121 if f == "omitempty" {
122 return true
123 }
124 }
125 }
126 return isOptional
127}
128
129// isOmitEmpty means that the zero value is interpreted as undefined.
130func isOmitEmpty(f *reflect.StructField) bool {
131 isOmitEmpty := false
132 switch f.Type.Kind() {
133 case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Interface, reflect.Slice:
134 // Note: it may be confusing to distinguish between an empty slice and
135 // a nil slice. However, it is also surprizing to not be able to specify
136 // a default value for a slice. So for now we will allow it.
137 isOmitEmpty = true
138
139 default:
140 // TODO: we can also infer omit empty if a type cannot be nil if there
141 // is a constraint that unconditionally disallows the zero value.
142 }
143 tag, ok := f.Tag.Lookup("json")
144 if ok {
145 isOmitEmpty = false
146 for _, f := range strings.Split(tag, ",")[1:] {
147 if f == "omitempty" {
148 return true
149 }
150 }
151 }
152 return isOmitEmpty
153}
154
155// parseJSON parses JSON into a CUE value. b must be valid JSON.
156func parseJSON(ctx *context, b []byte) evaluated {
157 expr, err := parser.ParseExpr(ctx.index.fset, "json", b)
158 if err != nil {
159 panic(err) // cannot happen
160 }
161 v := newVisitor(ctx.index, nil, nil, nil)
162 return v.walk(expr).evalPartial(ctx)
163}
164
165func isZero(v reflect.Value) bool {
166 x := v.Interface()
167 if x == nil {
168 return true
169 }
170 switch k := v.Kind(); k {
171 case reflect.Struct, reflect.Array:
172 // we never allow optional values for these types.
173 return false
174
175 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
176 reflect.Slice:
177 // Note that for maps we preserve the distinction between a nil map and
178 // an empty map.
179 return v.IsNil()
180
181 case reflect.String:
182 return v.Len() == 0
183
184 default:
185 return x == reflect.Zero(v.Type()).Interface()
186 }
187}
188
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200189func convert(ctx *context, src source, x interface{}) evaluated {
190 switch v := x.(type) {
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200191 case nil:
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200192 // Interpret a nil pointer as an undefined value that is only
193 // null by default, but may still be set: *null | _.
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200194 return makeNullable(&top{src.base()}).(evaluated)
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200195
196 case *big.Int:
197 n := newNum(src, intKind)
198 n.v.Coeff.Set(v)
199 if v.Sign() < 0 {
200 n.v.Coeff.Neg(&n.v.Coeff)
201 n.v.Negative = true
202 }
203 return n
204
205 case *big.Rat:
206 // should we represent this as a binary operation?
207 n := newNum(src, numKind)
208 ctx.Quo(&n.v, apd.NewWithBigInt(v.Num(), 0), apd.NewWithBigInt(v.Denom(), 0))
209 if !v.IsInt() {
210 n.k = floatKind
211 }
212 return n
213
214 case *big.Float:
215 n := newNum(src, floatKind)
216 n.v.SetString(v.String())
217 return n
218
219 case *apd.Decimal:
220 n := newNum(src, floatKind|intKind)
221 n.v.Set(v)
222 if !n.isInt(ctx) {
223 n.k = floatKind
224 }
225 return n
226
227 case json.Marshaler:
228 b, err := v.MarshalJSON()
229 if err != nil {
230 return ctx.mkErr(src, err)
231 }
232
233 return parseJSON(ctx, b)
234
235 case encoding.TextMarshaler:
236 b, err := v.MarshalText()
237 if err != nil {
238 return ctx.mkErr(src, err)
239 }
240 b, err = json.Marshal(string(b))
241 if err != nil {
242 return ctx.mkErr(src, err)
243 }
244 return parseJSON(ctx, b)
245
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200246 case error:
247 return ctx.mkErr(src, v.Error())
248 case bool:
249 return &boolLit{src.base(), v}
250 case string:
251 return &stringLit{src.base(), v}
252 case []byte:
253 return &bytesLit{src.base(), v}
254 case int:
255 return toInt(ctx, src, int64(v))
256 case int8:
257 return toInt(ctx, src, int64(v))
258 case int16:
259 return toInt(ctx, src, int64(v))
260 case int32:
261 return toInt(ctx, src, int64(v))
262 case int64:
263 return toInt(ctx, src, int64(v))
264 case uint:
265 return toUint(ctx, src, uint64(v))
266 case uint8:
267 return toUint(ctx, src, uint64(v))
268 case uint16:
269 return toUint(ctx, src, uint64(v))
270 case uint32:
271 return toUint(ctx, src, uint64(v))
272 case uint64:
273 return toUint(ctx, src, uint64(v))
274 case float64:
275 r := newNum(src, floatKind)
276 r.v.SetString(fmt.Sprintf("%g", v))
277 return r
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200278
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200279 case reflect.Value:
280 if v.CanInterface() {
281 return convert(ctx, src, v.Interface())
282 }
283
284 default:
285 value := reflect.ValueOf(v)
286 switch value.Kind() {
287 case reflect.Ptr:
288 if value.IsNil() {
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200289 // Interpret a nil pointer as an undefined value that is only
290 // null by default, but may still be set: *null | _.
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200291 return makeNullable(&top{src.base()}).(evaluated)
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200292 }
293 return convert(ctx, src, value.Elem().Interface())
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200294
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200295 case reflect.Struct:
296 obj := newStruct(src)
297 t := value.Type()
298 for i := 0; i < value.NumField(); i++ {
299 t := t.Field(i)
300 if t.PkgPath != "" {
301 continue
302 }
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200303 val := value.Field(i)
304 if isOmitEmpty(&t) && isZero(val) {
305 continue
306 }
307 sub := convert(ctx, src, val.Interface())
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200308 // leave errors like we do during normal evaluation or do we
309 // want to return the error?
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200310 name := getName(&t)
311 if name == "-" {
312 continue
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200313 }
314 f := ctx.strLabel(name)
315 obj.arcs = append(obj.arcs, arc{feature: f, v: sub})
316 }
317 sort.Sort(obj)
318 return obj
319
320 case reflect.Map:
321 obj := newStruct(src)
322 t := value.Type()
323 if t.Key().Kind() != reflect.String {
324 return ctx.mkErr(src, "builtin map key not a string, but unsupported type %s", t.Key().String())
325 }
326 keys := []string{}
327 for _, k := range value.MapKeys() {
328 keys = append(keys, k.String())
329 }
330 sort.Strings(keys)
331 for _, k := range keys {
332 sub := convert(ctx, src, value.MapIndex(reflect.ValueOf(k)).Interface())
333 // leave errors like we do during normal evaluation or do we
334 // want to return the error?
335 f := ctx.strLabel(k)
336 obj.arcs = append(obj.arcs, arc{feature: f, v: sub})
337 }
338 sort.Sort(obj)
339 return obj
340
341 case reflect.Slice, reflect.Array:
342 list := &list{baseValue: src.base()}
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200343 arcs := []arc{}
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200344 for i := 0; i < value.Len(); i++ {
345 x := convert(ctx, src, value.Index(i).Interface())
346 if isBottom(x) {
347 return x
348 }
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200349 arcs = append(arcs, arc{feature: label(len(arcs)), v: x})
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200350 }
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200351 list.elem = &structLit{baseValue: list.baseValue, arcs: arcs}
Marcel van Lohuizenb46a7ce2019-04-02 16:00:08 +0200352 list.initLit()
353 // There is no need to set the type of the list, as the list will
354 // be of fixed size and all elements will already have a defined
355 // value.
356 return list
357 }
358 }
359 return ctx.mkErr(src, "builtin returned unsupported type %T", x)
360}
361
362func toInt(ctx *context, src source, x int64) evaluated {
363 n := newNum(src, intKind)
364 n.v.SetInt64(x)
365 return n
366}
367
368func toUint(ctx *context, src source, x uint64) evaluated {
369 n := newNum(src, floatKind)
370 n.v.Coeff.SetUint64(x)
371 return n
372}
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200373
374var (
375 typeCache sync.Map // map[reflect.Type]evaluated
376 mutex sync.Mutex
377)
378
379func convertGoType(inst *Instance, t reflect.Type) value {
380 ctx := inst.newContext()
381 // TODO: this can be much more efficient.
382 mutex.Lock()
383 defer mutex.Unlock()
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200384 return goTypeToValue(ctx, true, t)
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200385}
386
387var (
388 jsonMarshaler = reflect.TypeOf(new(json.Marshaler)).Elem()
389 textMarshaler = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
390 topSentinel = &top{}
391)
392
393// goTypeToValue converts a Go Type to a value.
394//
395// TODO: if this value will always be unified with a concrete type in Go, then
396// many of the fields may be omitted.
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200397func goTypeToValue(ctx *context, allowNullDefault bool, t reflect.Type) (e value) {
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200398 if e, ok := typeCache.Load(t); ok {
399 return e.(value)
400 }
401
402 // Even if this is for types that we know cast to a certain type, it can't
403 // hurt to return top, as in these cases the concrete values will be
404 // strict instances and there cannot be any tags that further constrain
405 // the values.
406 if t.Implements(jsonMarshaler) || t.Implements(textMarshaler) {
407 return topSentinel
408 }
409
410 switch k := t.Kind(); k {
411 case reflect.Ptr:
412 elem := t.Elem()
413 for elem.Kind() == reflect.Ptr {
414 elem = elem.Elem()
415 }
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200416 e = goTypeToValue(ctx, false, elem)
417 if allowNullDefault {
418 e = wrapOrNull(e)
419 }
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200420
421 case reflect.Interface:
422 switch t.Name() {
423 case "error":
424 // This is really null | _|_. There is no error if the error is null.
425 e = &nullLit{} // null
426 default:
427 e = topSentinel // `_`
428 }
429
430 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
431 reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
432 e = predefinedRanges[t.Kind().String()]
433
434 case reflect.Uint, reflect.Uintptr:
435 e = predefinedRanges["uint64"]
436
437 case reflect.Int:
438 e = predefinedRanges["int64"]
439
440 case reflect.String:
441 e = &basicType{k: stringKind}
442
443 case reflect.Bool:
444 e = &basicType{k: boolKind}
445
446 case reflect.Float32, reflect.Float64:
447 e = &basicType{k: floatKind}
448
449 case reflect.Struct:
450 // Some of these values have MarshalJSON methods, but that may not be
451 // the case for older Go versions.
452 name := fmt.Sprint(t)
453 switch name {
454 case "big.Int":
455 e = &basicType{k: intKind}
456 goto store
457 case "big.Rat", "big.Float", "apd.Decimal":
458 e = &basicType{k: floatKind}
459 goto store
460 case "time.Time":
461 // We let the concrete value decide.
462 e = topSentinel
463 goto store
464 }
465
466 // First iterate to create struct, then iterate another time to
467 // resolve field tags to allow field tags to refer to the struct fields.
468 tags := map[label]string{}
469 obj := newStruct(baseValue{})
470 typeCache.Store(t, obj)
471
472 for i := 0; i < t.NumField(); i++ {
473 f := t.Field(i)
474 if f.PkgPath != "" {
475 continue
476 }
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200477 _, ok := f.Tag.Lookup("cue")
478 elem := goTypeToValue(ctx, !ok, f.Type)
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200479
480 // leave errors like we do during normal evaluation or do we
481 // want to return the error?
482 name := getName(&f)
483 if name == "-" {
484 continue
485 }
486 l := ctx.strLabel(name)
487 obj.arcs = append(obj.arcs, arc{
488 feature: l,
489 // The GO JSON decoder always allows a value to be undefined.
490 optional: isOptional(&f),
491 v: elem,
492 })
493
494 if tag, ok := f.Tag.Lookup("cue"); ok {
495 tags[l] = tag
496 }
497 }
498 sort.Sort(obj)
499
500 for label, tag := range tags {
501 v := parseTag(ctx, obj, label, tag)
502 for i, a := range obj.arcs {
503 if a.feature == label {
504 // Instead of unifying with the existing type, we substitute
505 // with the constraints from the tags. The type constraints
506 // will be implied when unified with a concrete value.
507 obj.arcs[i].v = mkBin(ctx, 0, opUnify, a.v, v)
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200508 }
509 }
510 }
511
512 return obj
513
514 case reflect.Array, reflect.Slice:
515 if t.Elem().Kind() == reflect.Uint8 {
516 e = &basicType{k: bytesKind}
517 } else {
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200518 elem := goTypeToValue(ctx, allowNullDefault, t.Elem())
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200519
520 var ln value = &top{}
521 if t.Kind() == reflect.Array {
522 ln = toInt(ctx, baseValue{}, int64(t.Len()))
523 }
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200524 e = &list{elem: &structLit{}, typ: elem, len: ln}
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200525 }
526 if k == reflect.Slice {
527 e = wrapOrNull(e)
528 }
529
530 case reflect.Map:
531 if key := t.Key(); key.Kind() != reflect.String {
532 // What does the JSON library do here?
533 e = ctx.mkErr(baseValue{}, "type %v not supported as key type", key)
534 break
535 }
536
537 obj := newStruct(baseValue{})
538 sig := &params{}
539 sig.add(ctx.label("_", true), &basicType{k: stringKind})
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200540 v := goTypeToValue(ctx, allowNullDefault, t.Elem())
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200541 obj.template = &lambdaExpr{params: sig, value: v}
542
543 e = wrapOrNull(obj)
544 }
545
546store:
547 // TODO: store error if not nil?
548 if e != nil {
549 typeCache.Store(t, e)
550 }
551 return e
552}
553
554func wrapOrNull(e value) value {
555 if e.kind().isAnyOf(nullKind) {
556 return e
557 }
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200558 return makeNullable(e)
559}
560
561const nullIsDefault = true
562
563func makeNullable(e value) value {
564 return &disjunction{
565 baseValue: baseValue{e},
566 values: []dValue{
567 {val: &nullLit{}, marked: nullIsDefault},
568 {val: e}},
569 hasDefaults: nullIsDefault,
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200570 }
Marcel van Lohuizen46e73ec2019-04-03 12:19:18 +0200571}