1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package export
16
17 import (
18 "fmt"
19 "math/rand"
20
21 "cuelang.org/go/cue/ast"
22 "cuelang.org/go/cue/ast/astutil"
23 "cuelang.org/go/cue/errors"
24 "cuelang.org/go/internal"
25 "cuelang.org/go/internal/core/adt"
26 "cuelang.org/go/internal/core/eval"
27 "cuelang.org/go/internal/core/walk"
28 )
29
30 const debug = false
31
32 type Profile struct {
33 Simplify bool
34
35
36 Final bool
37
38
39 TakeDefaults bool
40
41 ShowOptional bool
42 ShowDefinitions bool
43
44
45
46
47 ShowHidden bool
48 ShowDocs bool
49 ShowAttributes bool
50
51
52
53
54
55 ShowErrors bool
56
57
58
59
60
61 SelfContained bool
62
63
64 AddPackage bool
65
66
67 InlineImports bool
68 }
69
70 var Simplified = &Profile{
71 Simplify: true,
72 ShowDocs: true,
73 }
74
75 var Final = &Profile{
76 Simplify: true,
77 TakeDefaults: true,
78 Final: true,
79 }
80
81 var Raw = &Profile{
82 ShowOptional: true,
83 ShowDefinitions: true,
84 ShowHidden: true,
85 ShowDocs: true,
86 AddPackage: true,
87 }
88
89 var All = &Profile{
90 Simplify: true,
91 ShowOptional: true,
92 ShowDefinitions: true,
93 ShowHidden: true,
94 ShowDocs: true,
95 ShowAttributes: true,
96 AddPackage: true,
97 }
98
99
100
101
102
103 func Def(r adt.Runtime, pkgID string, v *adt.Vertex) (*ast.File, errors.Error) {
104 return All.Def(r, pkgID, v)
105 }
106
107
108
109 func (p *Profile) Def(r adt.Runtime, pkgID string, v *adt.Vertex) (f *ast.File, err errors.Error) {
110 e := newExporter(p, r, pkgID, v)
111 e.initPivot(v)
112
113 isDef := v.IsRecursivelyClosed()
114 if isDef {
115 e.inDefinition++
116 }
117
118 expr := e.expr(nil, v)
119
120 switch isDef {
121 case true:
122 e.inDefinition--
123
124
125
126 if st, ok := expr.(*ast.StructLit); ok {
127 for _, elem := range st.Elts {
128 if d, ok := elem.(*ast.EmbedDecl); ok {
129 if isDefinitionReference(d.Expr) {
130 return e.finalize(v, expr)
131 }
132 }
133 }
134 }
135
136
137
138 if v.Kind() == adt.StructKind {
139 expr = ast.NewStruct(
140 ast.Embed(ast.NewIdent("_#def")),
141 ast.NewIdent("_#def"), expr,
142 )
143 }
144 }
145
146 return e.finalize(v, expr)
147 }
148
149 func isDefinitionReference(x ast.Expr) bool {
150 switch x := x.(type) {
151 case *ast.Ident:
152 if internal.IsDef(x.Name) {
153 return true
154 }
155 case *ast.SelectorExpr:
156 if internal.IsDefinition(x.Sel) {
157 return true
158 }
159 return isDefinitionReference(x.X)
160 case *ast.IndexExpr:
161 return isDefinitionReference(x.X)
162 }
163 return false
164 }
165
166
167
168 func Expr(r adt.Runtime, pkgID string, n adt.Expr) (ast.Expr, errors.Error) {
169 return Simplified.Expr(r, pkgID, n)
170 }
171
172
173
174 func (p *Profile) Expr(r adt.Runtime, pkgID string, n adt.Expr) (ast.Expr, errors.Error) {
175 e := newExporter(p, r, pkgID, nil)
176
177 return e.expr(nil, n), nil
178 }
179
180 func (e *exporter) toFile(v *adt.Vertex, x ast.Expr) *ast.File {
181 f := &ast.File{}
182
183 if e.cfg.AddPackage {
184 pkgName := ""
185 pkg := &ast.Package{}
186 for _, c := range v.Conjuncts {
187 f, _ := c.Source().(*ast.File)
188 if f == nil {
189 continue
190 }
191
192 if _, name, _ := internal.PackageInfo(f); name != "" {
193 pkgName = name
194 }
195
196 if e.cfg.ShowDocs {
197 if doc := internal.FileComment(f); doc != nil {
198 ast.AddComment(pkg, doc)
199 }
200 }
201 }
202
203 if pkgName != "" {
204 pkg.Name = ast.NewIdent(pkgName)
205 f.Decls = append(f.Decls, pkg)
206 }
207 }
208
209 switch st := x.(type) {
210 case nil:
211 panic("null input")
212
213 case *ast.StructLit:
214 f.Decls = append(f.Decls, st.Elts...)
215
216 default:
217 f.Decls = append(f.Decls, &ast.EmbedDecl{Expr: x})
218 }
219
220 return f
221 }
222
223
224
225 func Vertex(r adt.Runtime, pkgID string, n *adt.Vertex) (*ast.File, errors.Error) {
226 return Simplified.Vertex(r, pkgID, n)
227 }
228
229
230
231 func (p *Profile) Vertex(r adt.Runtime, pkgID string, n *adt.Vertex) (f *ast.File, err errors.Error) {
232 e := newExporter(p, r, pkgID, n)
233 e.initPivot(n)
234
235 v := e.value(n, n.Conjuncts...)
236 return e.finalize(n, v)
237 }
238
239
240
241 func Value(r adt.Runtime, pkgID string, n adt.Value) (ast.Expr, errors.Error) {
242 return Simplified.Value(r, pkgID, n)
243 }
244
245
246
247
248
249
250 func (p *Profile) Value(r adt.Runtime, pkgID string, n adt.Value) (ast.Expr, errors.Error) {
251 e := newExporter(p, r, pkgID, n)
252 v := e.value(n)
253 return v, e.errs
254 }
255
256 type exporter struct {
257 cfg *Profile
258 errs errors.Error
259
260 ctx *adt.OpContext
261
262 index adt.StringIndexer
263 rand *rand.Rand
264
265
266 stack []frame
267
268 inDefinition int
269 inExpression int
270
271
272 pkgID string
273
274
275 pkgHash map[string]string
276
277
278
279 usedFeature map[adt.Feature]adt.Expr
280 labelAlias map[adt.Expr]adt.Feature
281 valueAlias map[*ast.Alias]*ast.Alias
282
283 fieldAlias map[*ast.Field]fieldAndScope
284 letAlias map[*ast.LetClause]*ast.LetClause
285 references map[*adt.Vertex]*referenceInfo
286
287 pivotter *pivotter
288 }
289
290 type fieldAndScope struct {
291 field *ast.Field
292 scope ast.Node
293 }
294
295
296
297
298
299
300 type referenceInfo struct {
301 field *ast.Field
302 references []*ast.Ident
303 }
304
305
306
307
308 func (e *exporter) linkField(v *adt.Vertex, f *ast.Field) {
309 if v == nil {
310 return
311 }
312 refs := e.references[v]
313 if refs == nil {
314
315
316 e.references[v] = &referenceInfo{field: f}
317 return
318 }
319 for _, r := range refs.references {
320 r.Node = f.Value
321 }
322 refs.references = refs.references[:0]
323 }
324
325
326
327 func (e *exporter) linkIdentifier(v *adt.Vertex, ident *ast.Ident) {
328 refs := e.references[v]
329 if refs == nil {
330 refs = &referenceInfo{}
331 e.references[v] = refs
332 }
333 if refs.field == nil {
334 refs.references = append(refs.references, ident)
335 return
336 }
337 ident.Node = refs.field.Value
338 }
339
340
341 func newExporter(p *Profile, r adt.Runtime, pkgID string, v adt.Value) *exporter {
342 n, _ := v.(*adt.Vertex)
343 e := &exporter{
344 cfg: p,
345 ctx: eval.NewContext(r, n),
346 index: r,
347 pkgID: pkgID,
348
349 references: map[*adt.Vertex]*referenceInfo{},
350 }
351
352 e.markUsedFeatures(v)
353
354 return e
355 }
356
357
358
359 func (e *exporter) initPivot(n *adt.Vertex) {
360 if !e.cfg.InlineImports &&
361 !e.cfg.SelfContained &&
362 n.Parent == nil {
363 return
364 }
365
366 e.initPivotter(n)
367 }
368
369
370
371 func (e *exporter) finalize(n *adt.Vertex, v ast.Expr) (f *ast.File, err errors.Error) {
372 f = e.toFile(n, v)
373
374 e.completePivot(f)
375
376 if err := astutil.Sanitize(f); err != nil {
377 err := errors.Promote(err, "export")
378 return f, errors.Append(e.errs, err)
379 }
380
381 return f, nil
382 }
383
384 func (e *exporter) markUsedFeatures(x adt.Expr) {
385 e.usedFeature = make(map[adt.Feature]adt.Expr)
386
387 w := &walk.Visitor{}
388 w.Before = func(n adt.Node) bool {
389 switch x := n.(type) {
390 case *adt.Vertex:
391 if !x.IsData() {
392 for _, c := range x.Conjuncts {
393 w.Elem(c.Elem())
394 }
395 }
396
397 case *adt.DynamicReference:
398 if e.labelAlias == nil {
399 e.labelAlias = make(map[adt.Expr]adt.Feature)
400 }
401
402 e.labelAlias[x.Label] = adt.InvalidLabel
403
404 case *adt.LabelReference:
405 }
406 return true
407 }
408
409 w.Feature = func(f adt.Feature, src adt.Node) {
410 _, ok := e.usedFeature[f]
411
412 switch x := src.(type) {
413 case *adt.LetReference:
414 if !ok {
415 e.usedFeature[f] = x.X
416 }
417
418 default:
419 e.usedFeature[f] = nil
420 }
421 }
422
423 w.Elem(x)
424 }
425
426 func (e *exporter) getFieldAlias(f *ast.Field, name string) string {
427 a, ok := f.Label.(*ast.Alias)
428 if !ok {
429 a = &ast.Alias{
430 Ident: ast.NewIdent(e.uniqueAlias(name)),
431 Expr: f.Label.(ast.Expr),
432 }
433 f.Label = a
434 }
435 return a.Ident.Name
436 }
437
438 func setFieldAlias(f *ast.Field, name string) {
439 if _, ok := f.Label.(*ast.Alias); !ok {
440 x := f.Label.(ast.Expr)
441 f.Label = &ast.Alias{
442 Ident: ast.NewIdent(name),
443 Expr: x,
444 }
445 ast.SetComments(f.Label, ast.Comments(x))
446 ast.SetComments(x, nil)
447
448 }
449 }
450
451 func (e *exporter) markLets(n ast.Node, scope *ast.StructLit) {
452 if n == nil {
453 return
454 }
455 ast.Walk(n, func(n ast.Node) bool {
456 switch v := n.(type) {
457 case *ast.StructLit:
458 e.markLetDecls(v.Elts, scope)
459 case *ast.File:
460 e.markLetDecls(v.Decls, scope)
461
462
463 case *ast.Field,
464 *ast.LetClause,
465 *ast.IfClause,
466 *ast.ForClause,
467 *ast.Comprehension:
468 return false
469 }
470 return true
471 }, nil)
472 }
473
474 func (e *exporter) markLetDecls(decls []ast.Decl, scope *ast.StructLit) {
475 for _, d := range decls {
476 switch x := d.(type) {
477 case *ast.Field:
478 e.prepareAliasedField(x, scope)
479 case *ast.LetClause:
480 e.markLetAlias(x)
481 }
482 }
483 }
484
485
486
487
488
489
490
491 func (e *exporter) prepareAliasedField(f *ast.Field, scope ast.Node) {
492 if _, ok := e.fieldAlias[f]; ok {
493 return
494 }
495
496 alias, ok := f.Label.(*ast.Alias)
497 if !ok {
498 return
499 }
500 field := &ast.Field{
501 Label: &ast.Alias{
502 Ident: ast.NewIdent(alias.Ident.Name),
503 Expr: alias.Expr,
504 },
505 }
506
507 if e.fieldAlias == nil {
508 e.fieldAlias = make(map[*ast.Field]fieldAndScope)
509 }
510
511 e.fieldAlias[f] = fieldAndScope{field: field, scope: scope}
512 }
513
514 func (e *exporter) getFixedField(f *adt.Field) *ast.Field {
515 if f.Src != nil {
516 if entry, ok := e.fieldAlias[f.Src]; ok {
517 return entry.field
518 }
519 }
520 return &ast.Field{
521 Label: e.stringLabel(f.Label),
522 }
523 }
524
525
526
527 func (e *exporter) markLetAlias(x *ast.LetClause) {
528
529
530 let := &ast.LetClause{}
531
532 if e.letAlias == nil {
533 e.letAlias = make(map[*ast.LetClause]*ast.LetClause)
534 }
535 e.letAlias[x] = let
536
537 scope := e.top().scope
538 scope.Elts = append(scope.Elts, let)
539 }
540
541
542 func filterUnusedLets(s *ast.StructLit) {
543 k := 0
544 for i, d := range s.Elts {
545 if let, ok := d.(*ast.LetClause); ok && let.Expr == nil {
546 continue
547 }
548 s.Elts[k] = s.Elts[i]
549 k++
550 }
551 s.Elts = s.Elts[:k]
552 }
553
554
555
556 func (e *exporter) resolveLet(env *adt.Environment, x *adt.LetReference) ast.Expr {
557 letClause, _ := x.Src.Node.(*ast.LetClause)
558 let := e.letAlias[letClause]
559
560 switch {
561 case let == nil:
562 ref, _ := e.ctx.Lookup(env, x)
563 if ref == nil {
564
565
566
567
568
569
570
571
572 return e.expr(env, x.X)
573 }
574 return e.expr(ref.Conjuncts[0].EnvExpr())
575
576 case let.Expr == nil:
577 label := e.uniqueLetIdent(x.Label, x.X)
578
579 let.Ident = e.ident(label)
580 let.Expr = e.expr(env, x.X)
581 }
582
583 ident := ast.NewIdent(let.Ident.Name)
584 ident.Node = let
585
586 return ident
587 }
588
589 func (e *exporter) uniqueLetIdent(f adt.Feature, x adt.Expr) adt.Feature {
590 if e.usedFeature[f] == x {
591 return f
592 }
593
594 f, _ = e.uniqueFeature(f.IdentString(e.ctx))
595 e.usedFeature[f] = x
596 return f
597 }
598
599 func (e *exporter) uniqueAlias(name string) string {
600 f := adt.MakeIdentLabel(e.ctx, name, "")
601
602 if _, ok := e.usedFeature[f]; !ok {
603 e.usedFeature[f] = nil
604 return name
605 }
606
607 _, name = e.uniqueFeature(f.IdentString(e.ctx))
608 return name
609 }
610
611
612
613 type featureSet interface {
614
615 intn(n int) int
616
617
618 makeFeature(s string) (f adt.Feature, ok bool)
619 }
620
621 func (e *exporter) intn(n int) int {
622 return e.rand.Intn(n)
623 }
624
625 func (e *exporter) makeFeature(s string) (f adt.Feature, ok bool) {
626 f = adt.MakeIdentLabel(e.ctx, s, "")
627 _, exists := e.usedFeature[f]
628 if !exists {
629 e.usedFeature[f] = nil
630 }
631 return f, !exists
632 }
633
634
635
636
637
638
639
640
641 func (e *exporter) uniqueFeature(base string) (f adt.Feature, name string) {
642 if e.rand == nil {
643 e.rand = rand.New(rand.NewSource(808))
644 }
645 return findUnique(e, base)
646 }
647
648 func findUnique(set featureSet, base string) (f adt.Feature, name string) {
649 if f, ok := set.makeFeature(base); ok {
650 return f, base
651 }
652
653
654 for i := 1; i < 5; i++ {
655 name := fmt.Sprintf("%s_%01X", base, i)
656 if f, ok := set.makeFeature(name); ok {
657 return f, name
658 }
659 }
660
661 const mask = 0xff_ffff_ffff_ffff
662 const shift = 4
663 digits := 1
664 for n := int64(0x10); ; n = int64(mask&((n<<shift)-1)) + 1 {
665 num := set.intn(int(n)-1) + 1
666 name := fmt.Sprintf("%[1]s_%0[2]*[3]X", base, digits, num)
667 if f, ok := set.makeFeature(name); ok {
668 return f, name
669 }
670 digits++
671 }
672 }
673
674 type frame struct {
675 node *adt.Vertex
676
677 scope *ast.StructLit
678
679 docSources []adt.Conjunct
680
681
682 field *ast.Field
683 labelExpr ast.Expr
684
685 dynamicFields []*entry
686
687
688 upCount int32
689
690
691 fields map[adt.Feature]entry
692
693
694 mapped map[adt.Node]ast.Node
695 }
696
697 type entry struct {
698 alias string
699 field *ast.Field
700 node ast.Node
701 references []*ast.Ident
702 }
703
704 func (e *exporter) addField(label adt.Feature, f *ast.Field, n ast.Node) {
705 frame := e.top()
706 entry := frame.fields[label]
707 entry.field = f
708 entry.node = n
709 frame.fields[label] = entry
710 }
711
712 func (e *exporter) addEmbed(x ast.Expr) {
713 frame := e.top()
714 frame.scope.Elts = append(frame.scope.Elts, x)
715 }
716
717 func (e *exporter) pushFrame(src *adt.Vertex, conjuncts []adt.Conjunct) (s *ast.StructLit, saved []frame) {
718 saved = e.stack
719 s = &ast.StructLit{}
720 e.stack = append(e.stack, frame{
721 node: src,
722 scope: s,
723 mapped: map[adt.Node]ast.Node{},
724 fields: map[adt.Feature]entry{},
725 docSources: conjuncts,
726 })
727 return s, saved
728 }
729
730 func (e *exporter) popFrame(saved []frame) {
731 top := e.stack[len(e.stack)-1]
732
733 for _, f := range top.fields {
734 node := f.node
735 if f.alias != "" && f.field != nil {
736 setFieldAlias(f.field, f.alias)
737 node = f.field
738 }
739 if node != nil {
740 for _, r := range f.references {
741 r.Node = node
742 }
743 }
744 }
745
746 e.stack = saved
747 }
748
749 func (e *exporter) top() *frame {
750 return &(e.stack[len(e.stack)-1])
751 }
752
753 func (e *exporter) node() *adt.Vertex {
754 if len(e.stack) == 0 {
755 return empty
756 }
757 n := e.stack[len(e.stack)-1].node
758 if n == nil {
759 return empty
760 }
761 return n
762 }
763
764 func (e *exporter) frame(upCount int32) *frame {
765 for i := len(e.stack) - 1; i >= 0; i-- {
766 f := &(e.stack[i])
767 if upCount <= (f.upCount - 1) {
768 return f
769 }
770 upCount -= f.upCount
771 }
772 if debug {
773
774
775
776 panic("unreachable reference")
777 }
778
779 return &frame{}
780 }
781
782 func (e *exporter) setDocs(x adt.Node) {
783 f := e.stack[len(e.stack)-1]
784 f.docSources = []adt.Conjunct{adt.MakeRootConjunct(nil, x)}
785 e.stack[len(e.stack)-1] = f
786 }
787
View as plain text