1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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/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
44
45
46
47
48 func GoValueToValue(ctx *adt.OpContext, x interface{}, nilIsTop bool) adt.Value {
49 v := GoValueToExpr(ctx, nilIsTop, x)
50
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
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
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
105
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
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
133
134
135 isOptional = true
136 }
137 if tag, ok := f.Tag.Lookup("cue"); ok {
138
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
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
166
167
168 isOmitEmpty = true
169
170 default:
171
172
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
187 func parseJSON(ctx *adt.OpContext, b []byte) adt.Value {
188 expr, err := parser.ParseExpr("json", b)
189 if err != nil {
190 panic(err)
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
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
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
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
268
269
270
271
272
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.SetString(fmt.Sprint(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 _, _, err := n.X.SetString(fmt.Sprint(v))
351 if err != nil {
352 return ctx.AddErr(errors.Promote(err, "invalid float"))
353 }
354 return n
355
356 case reflect.Value:
357 if v.CanInterface() {
358 return convertRec(ctx, nilIsTop, v.Interface())
359 }
360
361 default:
362 value := reflect.ValueOf(v)
363 switch value.Kind() {
364 case reflect.Bool:
365 return &adt.Bool{Src: ctx.Source(), B: value.Bool()}
366
367 case reflect.String:
368 str := value.String()
369 str, _ = unicode.UTF8.NewEncoder().String(str)
370
371
372
373
374 return &adt.String{Src: ctx.Source(), Str: str}
375
376 case reflect.Int, reflect.Int8, reflect.Int16,
377 reflect.Int32, reflect.Int64:
378 return toInt(ctx, value.Int())
379
380 case reflect.Uint, reflect.Uint8, reflect.Uint16,
381 reflect.Uint32, reflect.Uint64, reflect.Uintptr:
382 return toUint(ctx, value.Uint())
383
384 case reflect.Float32, reflect.Float64:
385 return convertRec(ctx, nilIsTop, value.Float())
386
387 case reflect.Ptr:
388 if value.IsNil() {
389 if nilIsTop {
390 ident, _ := ctx.Source().(*ast.Ident)
391 return &adt.Top{Src: ident}
392 }
393 return &adt.Null{Src: ctx.Source()}
394 }
395 return convertRec(ctx, nilIsTop, value.Elem().Interface())
396
397 case reflect.Struct:
398 obj := &adt.StructLit{Src: src}
399 v := &adt.Vertex{}
400 env := ctx.Env(0)
401 if env == nil {
402 env = &adt.Environment{}
403 }
404
405
406 v.AddStruct(obj, env, adt.CloseInfo{})
407 v.SetValue(ctx, &adt.StructMarker{})
408
409 t := value.Type()
410 for i := 0; i < value.NumField(); i++ {
411 sf := t.Field(i)
412 if sf.PkgPath != "" {
413 continue
414 }
415 val := value.Field(i)
416 if !nilIsTop && isNil(val) {
417 continue
418 }
419 if tag, _ := sf.Tag.Lookup("json"); tag == "-" {
420 continue
421 }
422 if isOmitEmpty(&sf) && val.IsZero() {
423 continue
424 }
425 sub := convertRec(ctx, nilIsTop, val.Interface())
426 if sub == nil {
427
428 continue
429 }
430 if _, ok := sub.(*adt.Bottom); ok {
431 return sub
432 }
433
434
435
436 name := getName(&sf)
437 if name == "-" {
438 continue
439 }
440 if sf.Anonymous && name == "" {
441 arc, ok := sub.(*adt.Vertex)
442 if ok {
443 v.Arcs = append(v.Arcs, arc.Arcs...)
444 }
445 continue
446 }
447
448 f := ctx.StringLabel(name)
449 obj.Decls = append(obj.Decls, &adt.Field{Label: f, Value: sub})
450 arc, ok := sub.(*adt.Vertex)
451 if ok {
452 a := *arc
453 arc = &a
454 arc.Label = f
455 } else {
456 arc = &adt.Vertex{Label: f, BaseValue: sub}
457 arc.ForceDone()
458 arc.AddConjunct(adt.MakeRootConjunct(nil, sub))
459 }
460 v.Arcs = append(v.Arcs, arc)
461 }
462
463 return v
464
465 case reflect.Map:
466 v := &adt.Vertex{BaseValue: &adt.StructMarker{}}
467 v.SetValue(ctx, &adt.StructMarker{})
468
469 t := value.Type()
470 switch key := t.Key(); key.Kind() {
471 default:
472 if !key.Implements(textMarshaler) {
473 return ctx.AddErrf("unsupported Go type for map key (%v)", key)
474 }
475 fallthrough
476 case reflect.String,
477 reflect.Int, reflect.Int8, reflect.Int16,
478 reflect.Int32, reflect.Int64,
479 reflect.Uint, reflect.Uint8, reflect.Uint16,
480 reflect.Uint32, reflect.Uint64, reflect.Uintptr:
481
482 keys := value.MapKeys()
483 sort.Slice(keys, func(i, j int) bool {
484 return fmt.Sprint(keys[i]) < fmt.Sprint(keys[j])
485 })
486 for _, k := range keys {
487 val := value.MapIndex(k)
488
489
490
491
492 sub := convertRec(ctx, nilIsTop, val.Interface())
493
494
495 if sub == nil {
496 return ctx.AddErrf("unsupported Go type (%T)", val.Interface())
497 }
498 if isBottom(sub) {
499 return sub
500 }
501
502 s := fmt.Sprint(k)
503 f := ctx.StringLabel(s)
504 arc, ok := sub.(*adt.Vertex)
505 if ok {
506 a := *arc
507 arc = &a
508 arc.Label = f
509 } else {
510 arc = &adt.Vertex{Label: f, BaseValue: sub}
511 arc.ForceDone()
512 arc.AddConjunct(adt.MakeRootConjunct(nil, sub))
513 }
514 v.Arcs = append(v.Arcs, arc)
515 }
516 }
517
518 return v
519
520 case reflect.Slice, reflect.Array:
521 var values []adt.Value
522
523 for i := 0; i < value.Len(); i++ {
524 val := value.Index(i)
525 x := convertRec(ctx, nilIsTop, val.Interface())
526 if x == nil {
527 return ctx.AddErrf("unsupported Go type (%T)",
528 val.Interface())
529 }
530 if isBottom(x) {
531 return x
532 }
533 values = append(values, x)
534 }
535
536 return ctx.NewList(values...)
537 }
538 }
539 return nil
540 }
541
542 func toInt(ctx *adt.OpContext, x int64) adt.Value {
543 n := &adt.Num{Src: ctx.Source(), K: adt.IntKind}
544 n.X = *apd.New(x, 0)
545 return n
546 }
547
548 func toUint(ctx *adt.OpContext, x uint64) adt.Value {
549 n := &adt.Num{Src: ctx.Source(), K: adt.IntKind}
550 n.X.Coeff.SetUint64(x)
551 return n
552 }
553
554 func convertGoType(ctx *adt.OpContext, t reflect.Type) adt.Expr {
555
556
557 return goTypeToValue(ctx, true, t)
558 }
559
560 var (
561 jsonMarshaler = reflect.TypeOf(new(json.Marshaler)).Elem()
562 textMarshaler = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
563 topSentinel = ast.NewIdent("_")
564 )
565
566
567
568
569
570 func goTypeToValue(ctx *adt.OpContext, allowNullDefault bool, t reflect.Type) adt.Expr {
571 if _, t, ok := ctx.LoadType(t); ok {
572 return t
573 }
574
575 _, v := goTypeToValueRec(ctx, allowNullDefault, t)
576 if v == nil {
577 return ctx.AddErrf("unsupported Go type (%v)", t)
578 }
579 return v
580 }
581
582 func goTypeToValueRec(ctx *adt.OpContext, allowNullDefault bool, t reflect.Type) (e ast.Expr, expr adt.Expr) {
583 if src, t, ok := ctx.LoadType(t); ok {
584 return src, t
585 }
586
587 switch reflect.Zero(t).Interface().(type) {
588 case *big.Int, big.Int:
589 e = ast.NewIdent("int")
590 goto store
591
592 case *big.Float, big.Float, *big.Rat, big.Rat:
593 e = ast.NewIdent("number")
594 goto store
595
596 case *apd.Decimal, apd.Decimal:
597 e = ast.NewIdent("number")
598 goto store
599 }
600
601
602
603
604
605 if t.Implements(jsonMarshaler) || t.Implements(textMarshaler) {
606 e = topSentinel
607 goto store
608 }
609
610 switch k := t.Kind(); k {
611 case reflect.Ptr:
612 elem := t.Elem()
613 for elem.Kind() == reflect.Ptr {
614 elem = elem.Elem()
615 }
616 e, _ = goTypeToValueRec(ctx, false, elem)
617 if allowNullDefault {
618 e = wrapOrNull(e)
619 }
620
621 case reflect.Interface:
622 switch t.Name() {
623 case "error":
624
625 e = ast.NewNull()
626 default:
627 e = topSentinel
628 }
629
630 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
631 reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
632 e = compile.LookupRange(t.Kind().String()).Source().(ast.Expr)
633
634 case reflect.Uint, reflect.Uintptr:
635 e = compile.LookupRange("uint64").Source().(ast.Expr)
636
637 case reflect.Int:
638 e = compile.LookupRange("int64").Source().(ast.Expr)
639
640 case reflect.String:
641 e = ast.NewIdent("__string")
642
643 case reflect.Bool:
644 e = ast.NewIdent("__bool")
645
646 case reflect.Float32, reflect.Float64:
647 e = ast.NewIdent("__number")
648
649 case reflect.Struct:
650 obj := &ast.StructLit{}
651
652
653
654
655 ctx.StoreType(t, obj, nil)
656
657 for i := 0; i < t.NumField(); i++ {
658 f := t.Field(i)
659 if f.PkgPath != "" {
660 continue
661 }
662 _, ok := f.Tag.Lookup("cue")
663 elem, _ := goTypeToValueRec(ctx, !ok, f.Type)
664 if isBad(elem) {
665 continue
666 }
667
668
669
670 name := getName(&f)
671 if name == "-" {
672 continue
673 }
674
675 if tag, ok := f.Tag.Lookup("cue"); ok {
676 v := parseTag(ctx, obj, name, tag)
677 if isBad(v) {
678 return v, nil
679 }
680 elem = ast.NewBinExpr(token.AND, elem, v)
681 }
682
683
684
685
686
687 d := &ast.Field{Label: ast.NewIdent(name), Value: elem}
688 if isOptional(&f) {
689 internal.SetConstraint(d, token.OPTION)
690 }
691 obj.Elts = append(obj.Elts, d)
692 }
693
694
695
696
697 e = obj
698
699 case reflect.Array, reflect.Slice:
700 if t.Elem().Kind() == reflect.Uint8 {
701 e = ast.NewIdent("__bytes")
702 } else {
703 elem, _ := goTypeToValueRec(ctx, allowNullDefault, t.Elem())
704 if elem == nil {
705 b := ctx.AddErrf("unsupported Go type (%v)", t.Elem())
706 return &ast.BadExpr{}, b
707 }
708
709 if t.Kind() == reflect.Array {
710 e = ast.NewBinExpr(token.MUL,
711 ast.NewLit(token.INT, strconv.Itoa(t.Len())),
712 ast.NewList(elem))
713 } else {
714 e = ast.NewList(&ast.Ellipsis{Type: elem})
715 }
716 }
717 if k == reflect.Slice {
718 e = wrapOrNull(e)
719 }
720
721 case reflect.Map:
722 switch key := t.Key(); key.Kind() {
723 case reflect.String, reflect.Int, reflect.Int8, reflect.Int16,
724 reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
725 reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
726 default:
727 b := ctx.AddErrf("unsupported Go type for map key (%v)", key)
728 return &ast.BadExpr{}, b
729 }
730
731 v, x := goTypeToValueRec(ctx, allowNullDefault, t.Elem())
732 if v == nil {
733 b := ctx.AddErrf("unsupported Go type (%v)", t.Elem())
734 return &ast.BadExpr{}, b
735 }
736 if isBad(v) {
737 return v, x
738 }
739
740 e = ast.NewStruct(&ast.Field{
741 Label: ast.NewList(ast.NewIdent("__string")),
742 Value: v,
743 })
744
745 e = wrapOrNull(e)
746 }
747
748 store:
749
750 if e != nil {
751 f := &ast.File{Decls: []ast.Decl{&ast.EmbedDecl{Expr: e}}}
752 astutil.Resolve(f, func(_ token.Pos, msg string, args ...interface{}) {
753 ctx.AddErrf(msg, args...)
754 })
755 var x adt.Expr
756 c, err := compile.Expr(nil, ctx, pkgID(), e)
757 if err != nil {
758 b := &adt.Bottom{Err: err}
759 ctx.AddBottom(b)
760 x = b
761 } else {
762 x = c.Expr()
763 }
764 ctx.StoreType(t, e, x)
765 return e, x
766 }
767 return e, nil
768 }
769
770 func isBottom(x adt.Node) bool {
771 if x == nil {
772 return true
773 }
774 b, _ := x.(*adt.Bottom)
775 return b != nil
776 }
777
778 func isBad(x ast.Expr) bool {
779 if x == nil {
780 return true
781 }
782 if bad, _ := x.(*ast.BadExpr); bad != nil {
783 return true
784 }
785 return false
786 }
787
788 func wrapOrNull(e ast.Expr) ast.Expr {
789 switch x := e.(type) {
790 case *ast.BasicLit:
791 if x.Kind == token.NULL {
792 return x
793 }
794 case *ast.BadExpr:
795 return e
796 }
797 return makeNullable(e, true)
798 }
799
800 func makeNullable(e ast.Expr, nullIsDefault bool) ast.Expr {
801 var null ast.Expr = ast.NewNull()
802 if nullIsDefault {
803 null = &ast.UnaryExpr{Op: token.MUL, X: null}
804 }
805 return ast.NewBinExpr(token.OR, null, e)
806 }
807
808
809 func pkgID() string {
810 return "_"
811 }
812
View as plain text