cuelang.org/go@v0.10.1/internal/core/export/adt.go (about) 1 // Copyright 2020 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 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 // TODO: should we use pushFrame here? 53 // _, saved := e.pushFrame([]adt.Conjunct{adt.MakeConjunct(nil, x)}) 54 // defer e.popFrame(saved) 55 // s := e.frame(0).scope 56 57 s := &ast.StructLit{} 58 // TODO: ensure e.node() is set in more cases. Right now it is not 59 // always set in mergeValues, even in cases where it could be. Better 60 // to be conservative for now, though. 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 // decl may be nil if it represents a let. Lets are added later, and 77 // only when they are still used. 78 if decl == nil { 79 continue 80 } 81 82 if e.cfg.ShowDocs { 83 ast.SetComments(decl, filterDocs(ast.Comments(d.Source()))) 84 } 85 // TODO: use e.copyMeta for positions, but only when the original 86 // source is available. 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 // TODO: why does LabelReference not implement resolve? 101 case *adt.LabelReference: 102 // get potential label from Source. Otherwise use X. 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 // This can happen when the LabelReference is evaluated outside of 110 // normal evaluation, that is, if a pattern constraint or 111 // additional constraint is evaluated by itself. 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 // TODO: Stride not yet? implemented. 148 // if x.Stride != nil { 149 // stride = e.innerExpr(env, x.Stride) 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 // TODO: mark formatting in interpolation itself. 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 // b := strings.Builder{} 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 // Can occur in nested comprehenions. 284 env = &adt.Environment{Up: env, Vertex: empty} 285 default: 286 panic("unreachable") 287 } 288 } 289 290 // If this is an "unwrapped" comprehension, we need to also 291 // account for the curly braces of the original comprehension. 292 if x.Nest() > 0 { 293 env = &adt.Environment{Up: env, Vertex: empty} 294 } 295 296 // TODO: consider using adt.EnvExpr. 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 // Special case when the original CUE already had an alias. 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 // Use low-level lookup to bypass structural cycle detection. This is 330 // fine as we do not recurse on the result and it is necessary to detect 331 // shadowing even when a configuration has a structural cycle. 332 for i := 0; i < int(x.UpCount); i++ { 333 env = env.Up 334 } 335 336 // Exclude comprehensions and other temporary/ inlined Vertices, which 337 // cannot be properly resolved, throwing off the sanitize. Also, 338 // comprehensions originate from a single source and do not need to be 339 // handled. 340 if env != nil { // for generated stuff 341 // TODO: note that env.Vertex should never be nil; investigate and replace the nil check below. 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 { // Should always pass 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 // TODO(unshadow): ensure we correctly unshadow newly visible fields. 363 // before uncommenting this. 364 // if v := x.EvaluateLabel(e.ctx, env); v != 0 { 365 // str := v.StringValue(e.ctx) 366 // if ast.IsValidIdent(str) { 367 // label := e.ctx.StringLabel(str) 368 // ident, ok := e.newIdentForField(x.Src, label, x.UpCount) 369 // if ok { 370 // return ident 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 // Instead of calling e.expr directly, we inline the case for 491 // *adt.StructLit, so that we can pass src. 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 // Handled elsewhere 505 return nil 506 507 case *adt.BulkOptionalField: 508 e.setDocs(x) 509 // set bulk in frame. 510 frame := e.frame(0) 511 512 expr := e.innerExpr(env, x.Filter) 513 frame.labelExpr = expr // see astutil.Resolve. 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 // TODO(unshadow): allow once unshadowing algorithm is fixed. 547 // case ok && ast.IsValidIdent(s.Str): 548 // label := e.ctx.StringLabel(s.Str) 549 // f.Label = ast.NewIdent(s.Str) 550 // e.setField(label, f) 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 // This can happen when evaluation is "pivoted". 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 // Can occur in nested comprehenions. 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 // If this is an "unwrapped" comprehension, we need to also 703 // account for the curly braces of the original comprehension. 704 if comp.Nest() > 0 { 705 env = &adt.Environment{Up: env, Vertex: empty} 706 } 707 708 // TODO: consider using adt.EnvExpr. 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 }