1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package export
16
17 import (
18 "bytes"
19 "fmt"
20 "strings"
21
22 "cuelang.org/go/cue/ast"
23 "cuelang.org/go/cue/ast/astutil"
24 "cuelang.org/go/cue/literal"
25 "cuelang.org/go/cue/token"
26 "cuelang.org/go/internal"
27 "cuelang.org/go/internal/core/adt"
28 )
29
30 func (e *exporter) ident(x adt.Feature) *ast.Ident {
31 s := x.IdentString(e.ctx)
32 if !ast.IsValidIdent(s) {
33 panic(s + " is not a valid identifier")
34 }
35 return ast.NewIdent(s)
36 }
37
38 func (e *exporter) adt(env *adt.Environment, expr adt.Elem) ast.Expr {
39 switch x := expr.(type) {
40 case adt.Value:
41 return e.expr(env, x)
42
43 case *adt.ListLit:
44 env := &adt.Environment{Up: env, Vertex: e.node()}
45 a := []ast.Expr{}
46 for _, x := range x.Elems {
47 a = append(a, e.elem(env, x))
48 }
49 return ast.NewList(a...)
50
51 case *adt.StructLit:
52
53
54
55
56
57 s := &ast.StructLit{}
58
59
60
61 env := &adt.Environment{Up: env, Vertex: e.node()}
62
63 for _, d := range x.Decls {
64 var a *ast.Alias
65 if orig, ok := d.Source().(*ast.Field); ok {
66 if alias, ok := orig.Value.(*ast.Alias); ok {
67 if e.valueAlias == nil {
68 e.valueAlias = map[*ast.Alias]*ast.Alias{}
69 }
70 a = &ast.Alias{Ident: ast.NewIdent(alias.Ident.Name)}
71 e.valueAlias[alias] = a
72 }
73 }
74 decl := e.decl(env, d)
75
76
77
78 if decl == nil {
79 continue
80 }
81
82 if e.cfg.ShowDocs {
83 ast.SetComments(decl, filterDocs(ast.Comments(d.Source())))
84 }
85
86
87
88 if a != nil {
89 if f, ok := decl.(*ast.Field); ok {
90 a.Expr = f.Value
91 f.Value = a
92 }
93 }
94
95 s.Elts = append(s.Elts, decl)
96 }
97
98 return s
99
100
101 case *adt.LabelReference:
102
103 v, ok := e.ctx.Evaluate(env, x)
104 f := e.frame(x.UpCount)
105 if ok && (adt.IsConcrete(v) || f.field == nil) {
106 return e.value(v)
107 }
108 if f.field == nil {
109
110
111
112 return ast.NewIdent("string")
113 }
114 list, ok := f.field.Label.(*ast.ListLit)
115 if !ok || len(list.Elts) != 1 {
116 panic("label reference to non-pattern constraint field or invalid list")
117 }
118 name := ""
119 if a, ok := list.Elts[0].(*ast.Alias); ok {
120 name = a.Ident.Name
121 } else {
122 if x.Src != nil {
123 name = x.Src.Name
124 }
125 name = e.uniqueAlias(name)
126 list.Elts[0] = &ast.Alias{
127 Ident: ast.NewIdent(name),
128 Expr: list.Elts[0],
129 }
130 }
131 ident := ast.NewIdent(name)
132 ident.Scope = f.field
133 ident.Node = f.labelExpr
134 return ident
135
136 case adt.Resolver:
137 return e.resolve(env, x)
138
139 case *adt.SliceExpr:
140 var lo, hi ast.Expr
141 if x.Lo != nil {
142 lo = e.innerExpr(env, x.Lo)
143 }
144 if x.Hi != nil {
145 hi = e.innerExpr(env, x.Hi)
146 }
147
148
149
150
151 return &ast.SliceExpr{X: e.innerExpr(env, x.X), Low: lo, High: hi}
152
153 case *adt.Interpolation:
154 var (
155 tripple = `"""`
156 openQuote = `"`
157 closeQuote = `"`
158 f = literal.String
159 )
160 if x.K&adt.BytesKind != 0 {
161 tripple = `'''`
162 openQuote = `'`
163 closeQuote = `'`
164 f = literal.Bytes
165 }
166 toString := func(v adt.Expr) string {
167 str := ""
168 switch x := v.(type) {
169 case *adt.String:
170 str = x.Str
171 case *adt.Bytes:
172 str = string(x.B)
173 }
174 return str
175 }
176 t := &ast.Interpolation{}
177 f = f.WithGraphicOnly()
178 indent := ""
179
180 for i := 0; i < len(x.Parts); i += 2 {
181 if strings.IndexByte(toString(x.Parts[i]), '\n') >= 0 {
182 f = f.WithTabIndent(len(e.stack))
183 indent = strings.Repeat("\t", len(e.stack))
184 openQuote = tripple + "\n" + indent
185 closeQuote = tripple
186 break
187 }
188 }
189 prefix := openQuote
190 suffix := `\(`
191 for i, elem := range x.Parts {
192 if i%2 == 1 {
193 t.Elts = append(t.Elts, e.innerExpr(env, elem))
194 } else {
195
196 buf := []byte(prefix)
197 str := toString(elem)
198 buf = f.AppendEscaped(buf, str)
199 if i == len(x.Parts)-1 {
200 if len(closeQuote) > 1 {
201 buf = append(buf, '\n')
202 buf = append(buf, indent...)
203 }
204 buf = append(buf, closeQuote...)
205 } else {
206 if bytes.HasSuffix(buf, []byte("\n")) {
207 buf = append(buf, indent...)
208 }
209 buf = append(buf, suffix...)
210 }
211 t.Elts = append(t.Elts, &ast.BasicLit{
212 Kind: token.STRING,
213 Value: string(buf),
214 })
215 }
216 prefix = ")"
217 }
218 return t
219
220 case *adt.BoundExpr:
221 return &ast.UnaryExpr{
222 Op: x.Op.Token(),
223 X: e.innerExpr(env, x.Expr),
224 }
225
226 case *adt.UnaryExpr:
227 return &ast.UnaryExpr{
228 Op: x.Op.Token(),
229 X: e.innerExpr(env, x.X),
230 }
231
232 case *adt.BinaryExpr:
233 return &ast.BinaryExpr{
234 Op: x.Op.Token(),
235 X: e.innerExpr(env, x.X),
236 Y: e.innerExpr(env, x.Y),
237 }
238
239 case *adt.CallExpr:
240 a := []ast.Expr{}
241 for _, arg := range x.Args {
242 v := e.innerExpr(env, arg)
243 if v == nil {
244 e.innerExpr(env, arg)
245 panic("")
246 }
247 a = append(a, v)
248 }
249 fun := e.innerExpr(env, x.Fun)
250 return &ast.CallExpr{Fun: fun, Args: a}
251
252 case *adt.DisjunctionExpr:
253 a := []ast.Expr{}
254 for _, d := range x.Values {
255 v := e.expr(env, d.Val)
256 if d.Default {
257 v = &ast.UnaryExpr{Op: token.MUL, X: v}
258 }
259 a = append(a, v)
260 }
261 return ast.NewBinExpr(token.OR, a...)
262
263 case *adt.ConjunctGroup:
264 a := []ast.Expr{}
265 for _, c := range *x {
266 v := e.expr(c.EnvExpr())
267 a = append(a, v)
268 }
269 return ast.NewBinExpr(token.AND, a...)
270
271 case *adt.Comprehension:
272 if !x.DidResolve() {
273 return dummyTop
274 }
275 for _, c := range x.Clauses {
276 switch c.(type) {
277 case *adt.ForClause:
278 env = &adt.Environment{Up: env, Vertex: empty}
279 case *adt.IfClause:
280 case *adt.LetClause:
281 env = &adt.Environment{Up: env, Vertex: empty}
282 case *adt.ValueClause:
283
284 env = &adt.Environment{Up: env, Vertex: empty}
285 default:
286 panic("unreachable")
287 }
288 }
289
290
291
292 if x.Nest() > 0 {
293 env = &adt.Environment{Up: env, Vertex: empty}
294 }
295
296
297 return e.adt(env, adt.ToExpr(x.Value))
298
299 default:
300 panic(fmt.Sprintf("unknown field %T", x))
301 }
302 }
303
304 var dummyTop = &ast.Ident{Name: "_"}
305
306 func (e *exporter) resolve(env *adt.Environment, r adt.Resolver) ast.Expr {
307 if c := e.pivotter; c != nil {
308 if alt := c.refExpr(r); alt != nil {
309 return alt
310 }
311 }
312
313 switch x := r.(type) {
314 case *adt.FieldReference:
315
316 if x.Src != nil {
317 if f, ok := x.Src.Node.(*ast.Field); ok {
318 if entry, ok := e.fieldAlias[f]; ok {
319 ident := ast.NewIdent(aliasFromLabel(f))
320 ident.Node = entry.field
321 ident.Scope = entry.scope
322 return ident
323 }
324 }
325 }
326
327 ident, _ := e.newIdentForField(x.Src, x.Label, x.UpCount)
328
329
330
331
332 for i := 0; i < int(x.UpCount); i++ {
333 env = env.Up
334 }
335
336
337
338
339
340 if env != nil {
341
342 if v := env.Vertex; v != nil && !v.IsDynamic {
343 if v = v.Lookup(x.Label); v != nil {
344 e.linkIdentifier(v, ident)
345 }
346 }
347 }
348
349 return ident
350
351 case *adt.ValueReference:
352 name := x.Label.IdentString(e.ctx)
353 if a, ok := x.Src.Node.(*ast.Alias); ok {
354 if b, ok := e.valueAlias[a]; ok {
355 name = b.Ident.Name
356 }
357 }
358 ident := ast.NewIdent(name)
359 return ident
360
361 case *adt.DynamicReference:
362
363
364
365
366
367
368
369
370
371
372
373
374
375 name := "X"
376 if x.Src != nil {
377 name = x.Src.Name
378 }
379 var f *ast.Field
380 for i := len(e.stack) - 1; i >= 0; i-- {
381 for _, entry := range e.stack[i].dynamicFields {
382 if entry.alias == name {
383 f = entry.field
384 }
385 }
386 }
387
388 if f != nil {
389 name = e.getFieldAlias(f, name)
390 }
391
392 ident := ast.NewIdent(name)
393 ident.Scope = f
394 ident.Node = f
395 return ident
396
397 case *adt.ImportReference:
398 importPath := x.ImportPath.StringValue(e.index)
399 spec := ast.NewImport(nil, importPath)
400
401 info, _ := astutil.ParseImportSpec(spec)
402 name := info.PkgName
403 if x.Label != 0 {
404 name = x.Label.StringValue(e.index)
405 if name != info.PkgName {
406 spec.Name = ast.NewIdent(name)
407 }
408 }
409 ident := ast.NewIdent(name)
410 ident.Node = spec
411 return ident
412
413 case *adt.LetReference:
414 return e.resolveLet(env, x)
415
416 case *adt.SelectorExpr:
417 return &ast.SelectorExpr{
418 X: e.innerExpr(env, x.X),
419 Sel: e.stringLabel(x.Sel),
420 }
421
422 case *adt.IndexExpr:
423 return &ast.IndexExpr{
424 X: e.innerExpr(env, x.X),
425 Index: e.innerExpr(env, x.Index),
426 }
427 }
428 panic("unreachable")
429 }
430
431 func (e *exporter) newIdentForField(
432 orig *ast.Ident,
433 label adt.Feature,
434 upCount int32) (ident *ast.Ident, ok bool) {
435 f := e.frame(upCount)
436 entry := f.fields[label]
437
438 name := e.identString(label)
439 switch {
440 case entry.alias != "":
441 name = entry.alias
442
443 case !ast.IsValidIdent(name):
444 name = "X"
445 if orig != nil {
446 name = orig.Name
447 }
448 name = e.uniqueAlias(name)
449 entry.alias = name
450 }
451
452 ident = ast.NewIdent(name)
453 entry.references = append(entry.references, ident)
454
455 if f.fields != nil {
456 f.fields[label] = entry
457 ok = true
458 }
459
460 return ident, ok
461 }
462
463 func (e *exporter) decl(env *adt.Environment, d adt.Decl) ast.Decl {
464 switch x := d.(type) {
465 case adt.Elem:
466 return e.elem(env, x)
467
468 case *adt.Field:
469 e.setDocs(x)
470 f := e.getFixedField(x)
471
472 internal.SetConstraint(f, x.ArcType.Token())
473 e.setField(x.Label, f)
474
475 f.Attrs = extractFieldAttrs(nil, x)
476
477 st, ok := x.Value.(*adt.StructLit)
478 if !ok {
479 f.Value = e.expr(env, x.Value)
480 return f
481
482 }
483
484 top := e.frame(0)
485 var src *adt.Vertex
486 if top.node != nil {
487 src = top.node.Lookup(x.Label)
488 }
489
490
491
492 c := adt.MakeRootConjunct(env, st)
493 f.Value = e.mergeValues(adt.InvalidLabel, src, []conjunct{{c: c, up: 0}}, c)
494
495 if top.node != nil {
496 if v := top.node.Lookup(x.Label); v != nil {
497 e.linkField(v, f)
498 }
499 }
500
501 return f
502
503 case *adt.LetField:
504
505 return nil
506
507 case *adt.BulkOptionalField:
508 e.setDocs(x)
509
510 frame := e.frame(0)
511
512 expr := e.innerExpr(env, x.Filter)
513 frame.labelExpr = expr
514
515 if x.Label != 0 {
516 expr = &ast.Alias{Ident: e.ident(x.Label), Expr: expr}
517 }
518 f := &ast.Field{
519 Label: ast.NewList(expr),
520 }
521
522 frame.field = f
523
524 if alias := aliasFromLabel(x.Src); alias != "" {
525 frame.dynamicFields = append(frame.dynamicFields, &entry{
526 alias: alias,
527 field: f,
528 })
529 }
530
531 f.Value = e.expr(env, x.Value)
532 f.Attrs = extractFieldAttrs(nil, x)
533
534 return f
535
536 case *adt.DynamicField:
537 e.setDocs(x)
538 srcKey := x.Key
539
540 f := &ast.Field{}
541 internal.SetConstraint(f, x.ArcType.Token())
542
543 v, _ := e.ctx.Evaluate(env, x.Key)
544
545 switch s, ok := v.(*adt.String); {
546
547
548
549
550
551
552 case ok:
553 srcKey = s
554
555 fallthrough
556
557 default:
558 key := e.innerExpr(env, srcKey)
559 switch key.(type) {
560 case *ast.Interpolation, *ast.BasicLit:
561 default:
562 key = &ast.ParenExpr{X: key}
563 }
564 f.Label = key.(ast.Label)
565 }
566
567 alias := aliasFromLabel(x.Src)
568
569 frame := e.frame(0)
570 frame.dynamicFields = append(frame.dynamicFields, &entry{
571 alias: alias,
572 field: f,
573 })
574
575 f.Value = e.expr(env, x.Value)
576 f.Attrs = extractFieldAttrs(nil, x)
577
578 return f
579
580 default:
581 panic(fmt.Sprintf("unknown field %T", x))
582 }
583 }
584
585 func (e *exporter) copyMeta(dst, src ast.Node) {
586 if e.cfg.ShowDocs {
587 ast.SetComments(dst, filterDocs(ast.Comments(src)))
588 }
589 astutil.CopyPosition(dst, src)
590 }
591
592 func filterDocs(a []*ast.CommentGroup) (out []*ast.CommentGroup) {
593 out = append(out, a...)
594 k := 0
595 for _, c := range a {
596 if !c.Doc {
597 continue
598 }
599 out[k] = c
600 k++
601 }
602 out = out[:k]
603 return out
604 }
605
606 func (e *exporter) setField(label adt.Feature, f *ast.Field) {
607 frame := e.frame(0)
608 entry := frame.fields[label]
609 entry.field = f
610 entry.node = f.Value
611
612 if frame.fields != nil {
613 frame.fields[label] = entry
614 }
615 }
616
617 func aliasFromLabel(src *ast.Field) string {
618 if src != nil {
619 if a, ok := src.Label.(*ast.Alias); ok {
620 return a.Ident.Name
621 }
622 }
623 return ""
624 }
625
626 func (e *exporter) elem(env *adt.Environment, d adt.Elem) ast.Expr {
627
628 switch x := d.(type) {
629 case adt.Expr:
630 return e.expr(env, x)
631
632 case *adt.Ellipsis:
633 t := &ast.Ellipsis{}
634 if x.Value != nil {
635 t.Type = e.expr(env, x.Value)
636 }
637 return t
638
639 case *adt.Comprehension:
640 return e.comprehension(env, x)
641
642 default:
643 panic(fmt.Sprintf("unknown field %T", x))
644 }
645 }
646
647 func (e *exporter) comprehension(env *adt.Environment, comp *adt.Comprehension) *ast.Comprehension {
648 c := &ast.Comprehension{}
649
650 for _, y := range comp.Clauses {
651 switch x := y.(type) {
652 case *adt.ForClause:
653 env = &adt.Environment{Up: env, Vertex: empty}
654 value := e.ident(x.Value)
655 src := e.innerExpr(env, x.Src)
656 clause := &ast.ForClause{Value: value, Source: src}
657 e.copyMeta(clause, x.Syntax)
658 c.Clauses = append(c.Clauses, clause)
659
660 _, saved := e.pushFrame(empty, nil)
661 defer e.popFrame(saved)
662
663 if x.Key != adt.InvalidLabel ||
664 (x.Syntax != nil && x.Syntax.Key != nil) {
665 key := e.ident(x.Key)
666 clause.Key = key
667 e.addField(x.Key, nil, clause)
668 }
669 e.addField(x.Value, nil, clause)
670
671 case *adt.IfClause:
672 cond := e.innerExpr(env, x.Condition)
673 clause := &ast.IfClause{Condition: cond}
674 e.copyMeta(clause, x.Src)
675 c.Clauses = append(c.Clauses, clause)
676
677 case *adt.LetClause:
678 env = &adt.Environment{Up: env, Vertex: empty}
679 expr := e.innerExpr(env, x.Expr)
680 clause := &ast.LetClause{
681 Ident: e.ident(x.Label),
682 Expr: expr,
683 }
684 e.copyMeta(clause, x.Src)
685 c.Clauses = append(c.Clauses, clause)
686
687 _, saved := e.pushFrame(empty, nil)
688 defer e.popFrame(saved)
689
690 e.addField(x.Label, nil, clause)
691
692 case *adt.ValueClause:
693
694 env = &adt.Environment{Up: env, Vertex: empty}
695
696 default:
697 panic(fmt.Sprintf("unknown field %T", x))
698 }
699 }
700 e.copyMeta(c, comp.Syntax)
701
702
703
704 if comp.Nest() > 0 {
705 env = &adt.Environment{Up: env, Vertex: empty}
706 }
707
708
709 v := e.expr(env, adt.ToExpr(comp.Value))
710 if _, ok := v.(*ast.StructLit); !ok {
711 v = ast.NewStruct(ast.Embed(v))
712 }
713 c.Value = v
714 return c
715 }
716
View as plain text