cuelang.org/go@v0.13.0/internal/core/export/value.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 "fmt" 19 "slices" 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) bareValue(v adt.Value) ast.Expr { 31 switch x := v.(type) { 32 case *adt.Vertex: 33 return e.vertex(x) 34 case adt.Value: 35 a := &adt.Vertex{BaseValue: x} 36 return e.vertex(a) 37 default: 38 panic("unreachable") 39 } 40 // TODO: allow a Value context wrapper. 41 } 42 43 // TODO: if the original value was a single reference, we could replace the 44 // value with a reference in graph mode. 45 46 func (e *exporter) vertex(n *adt.Vertex) (result ast.Expr) { 47 var attrs []*ast.Attribute 48 if e.cfg.ShowAttributes { 49 attrs = ExtractDeclAttrs(n) 50 } 51 52 s, saved := e.pushFrame(n, n.Conjuncts) 53 e.top().upCount++ 54 defer func() { 55 e.top().upCount-- 56 e.popFrame(saved) 57 }() 58 59 n.VisitLeafConjuncts(func(c adt.Conjunct) bool { 60 e.markLets(c.Expr().Source(), s) 61 return true 62 }) 63 64 switch x := n.BaseValue.(type) { 65 case nil: 66 // bare 67 case *adt.StructMarker: 68 result = e.structComposite(n, attrs) 69 70 case *adt.ListMarker: 71 if e.showArcs(n) || attrs != nil { 72 result = e.structComposite(n, attrs) 73 } else { 74 result = e.listComposite(n) 75 } 76 77 case *adt.Bottom: 78 switch { 79 case n.ArcType == adt.ArcOptional: 80 // Optional fields may always be the original value. 81 82 case e.cfg.ShowErrors && x.ChildError: 83 // TODO(perf): use precompiled arc statistics 84 if len(n.Arcs) > 0 && n.Arcs[0].Label.IsInt() && !e.showArcs(n) && attrs == nil { 85 result = e.listComposite(n) 86 } else { 87 result = e.structComposite(n, attrs) 88 } 89 90 case !x.IsIncomplete() || !n.HasConjuncts() || e.cfg.Final: 91 result = e.bottom(x) 92 } 93 94 case adt.Value: 95 if e.showArcs(n) || attrs != nil { 96 result = e.structComposite(n, attrs) 97 } else { 98 result = e.value(x, n.Conjuncts...) 99 } 100 101 default: 102 panic("unknown value") 103 } 104 if result == nil { 105 // fall back to expression mode 106 a := []adt.Conjunct{} 107 n.VisitLeafConjuncts(func(c adt.Conjunct) bool { 108 a = append(a, c) 109 return true 110 }) 111 // Use stable sort to ensure that tie breaks (for instance if elements 112 // are not associated with a position) are deterministic. 113 slices.SortStableFunc(a, cmpConjuncts) 114 115 exprs := make([]ast.Expr, 0, len(a)) 116 for _, c := range a { 117 if x := e.expr(c.Env, c.Elem()); x != dummyTop { 118 exprs = append(exprs, x) 119 } 120 } 121 122 result = ast.NewBinExpr(token.AND, exprs...) 123 } 124 125 if len(s.Elts) > 0 { 126 filterUnusedLets(s) 127 } 128 if result != s && len(s.Elts) > 0 { 129 // There are used let expressions within a non-struct. 130 // For now we just fall back to the original expressions. 131 result = e.adt(nil, n) 132 } 133 134 return result 135 } 136 137 func (e *exporter) value(n adt.Value, a ...adt.Conjunct) (result ast.Expr) { 138 if e.cfg.TakeDefaults { 139 n = adt.Default(n) 140 } 141 // Evaluate arc if needed? 142 143 // if e.concrete && !adt.IsConcrete(n.Value) { 144 // return e.errf("non-concrete value: %v", e.bareValue(n.Value)) 145 // } 146 147 switch x := n.(type) { 148 case *adt.Bottom: 149 result = e.bottom(x) 150 151 case *adt.Null: 152 result = e.null(x) 153 154 case *adt.Bool: 155 result = e.bool(x) 156 157 case *adt.Num: 158 result = e.num(x, a) 159 160 case *adt.String: 161 result = e.string(x, a) 162 163 case *adt.Bytes: 164 result = e.bytes(x, a) 165 166 case *adt.BasicType: 167 result = e.basicType(x) 168 169 case *adt.Top: 170 result = ast.NewIdent("_") 171 172 case *adt.BoundValue: 173 result = e.boundValue(x) 174 175 case *adt.Builtin: 176 result = e.builtin(x) 177 178 case *adt.BuiltinValidator: 179 result = e.builtinValidator(x) 180 181 case *adt.Vertex: 182 result = e.vertex(x) 183 184 case *adt.Conjunction: 185 switch len(x.Values) { 186 case 0: 187 return ast.NewIdent("_") 188 case 1: 189 if e.cfg.Simplify { 190 return e.expr(nil, x.Values[0]) 191 } 192 return e.bareValue(x.Values[0]) 193 } 194 195 a := []adt.Value{} 196 b := boundSimplifier{e: e} 197 for _, v := range x.Values { 198 if !e.cfg.Simplify || !b.add(v) { 199 a = append(a, v) 200 } 201 } 202 203 result = b.expr(e.ctx) 204 if result == nil { 205 a = x.Values 206 } 207 208 slices.SortStableFunc(a, cmpLeafNodes) 209 210 for _, x := range a { 211 result = wrapBin(result, e.bareValue(x), adt.AndOp) 212 } 213 214 case *adt.Disjunction: 215 a := []ast.Expr{} 216 217 for i, v := range x.Values { 218 var expr ast.Expr 219 if e.cfg.Simplify { 220 expr = e.bareValue(v) 221 } else { 222 expr = e.expr(nil, v) 223 } 224 if i < x.NumDefaults { 225 expr = &ast.UnaryExpr{Op: token.MUL, X: expr} 226 } 227 a = append(a, expr) 228 } 229 result = ast.NewBinExpr(token.OR, a...) 230 231 default: 232 panic(fmt.Sprintf("unsupported type %T", x)) 233 } 234 235 // TODO: Add comments from original. 236 237 return result 238 } 239 240 func (e *exporter) bottom(n *adt.Bottom) *ast.BottomLit { 241 err := &ast.BottomLit{} 242 if x := n.Err; x != nil { 243 msg := x.Error() 244 comment := &ast.Comment{Text: "// " + msg} 245 err.AddComment(&ast.CommentGroup{ 246 Line: true, 247 Position: 2, 248 List: []*ast.Comment{comment}, 249 }) 250 } 251 return err 252 } 253 254 func (e *exporter) null(n *adt.Null) *ast.BasicLit { 255 return &ast.BasicLit{Kind: token.NULL, Value: "null"} 256 } 257 258 func (e *exporter) bool(n *adt.Bool) (b *ast.BasicLit) { 259 return ast.NewBool(n.B) 260 } 261 262 func extractBasic(a []adt.Conjunct) (lit *ast.BasicLit) { 263 adt.VisitConjuncts(a, func(c adt.Conjunct) bool { 264 if b, ok := c.Source().(*ast.BasicLit); ok { 265 lit = &ast.BasicLit{Kind: b.Kind, Value: b.Value} 266 return false 267 } 268 return true 269 }) 270 return lit 271 } 272 273 func (e *exporter) num(n *adt.Num, orig []adt.Conjunct) *ast.BasicLit { 274 // TODO: take original formatting into account. 275 if b := extractBasic(orig); b != nil { 276 return b 277 } 278 kind := token.FLOAT 279 if n.K&adt.IntKind != 0 { 280 kind = token.INT 281 } 282 s := n.X.String() 283 if kind == token.FLOAT && !strings.ContainsAny(s, "eE.") { 284 s += "." 285 } 286 return &ast.BasicLit{Kind: kind, Value: s} 287 } 288 289 func (e *exporter) string(n *adt.String, orig []adt.Conjunct) *ast.BasicLit { 290 // TODO: take original formatting into account. 291 if b := extractBasic(orig); b != nil { 292 return b 293 } 294 s := literal.String.WithOptionalTabIndent(len(e.stack)).Quote(n.Str) 295 return &ast.BasicLit{ 296 Kind: token.STRING, 297 Value: s, 298 } 299 } 300 301 func (e *exporter) bytes(n *adt.Bytes, orig []adt.Conjunct) *ast.BasicLit { 302 // TODO: take original formatting into account. 303 if b := extractBasic(orig); b != nil { 304 return b 305 } 306 s := literal.Bytes.WithOptionalTabIndent(len(e.stack)).Quote(string(n.B)) 307 return &ast.BasicLit{ 308 Kind: token.STRING, 309 Value: s, 310 } 311 } 312 313 func (e *exporter) basicType(n *adt.BasicType) ast.Expr { 314 // TODO: allow multi-bit types? 315 return ast.NewIdent(n.K.String()) 316 } 317 318 func (e *exporter) boundValue(n *adt.BoundValue) ast.Expr { 319 return &ast.UnaryExpr{Op: n.Op.Token(), X: e.value(n.Value)} 320 } 321 322 func (e *exporter) builtin(x *adt.Builtin) ast.Expr { 323 if x.Package == 0 { 324 return ast.NewIdent(x.Name) 325 } 326 spec := ast.NewImport(nil, x.Package.StringValue(e.index)) 327 info, _ := astutil.ParseImportSpec(spec) 328 ident := ast.NewIdent(info.Ident) 329 ident.Node = spec 330 return ast.NewSel(ident, x.Name) 331 } 332 333 func (e *exporter) builtinValidator(n *adt.BuiltinValidator) ast.Expr { 334 call := ast.NewCall(e.builtin(n.Builtin)) 335 for _, a := range n.Args { 336 call.Args = append(call.Args, e.value(a)) 337 } 338 return call 339 } 340 341 func (e *exporter) listComposite(v *adt.Vertex) ast.Expr { 342 l := &ast.ListLit{} 343 for _, a := range v.Arcs { 344 if !a.Label.IsInt() { 345 continue 346 } 347 elem := e.vertex(a) 348 349 if e.cfg.ShowDocs { 350 docs := ExtractDoc(a) 351 ast.SetComments(elem, docs) 352 } 353 354 l.Elts = append(l.Elts, elem) 355 } 356 m, ok := v.BaseValue.(*adt.ListMarker) 357 if !e.cfg.TakeDefaults && ok && m.IsOpen { 358 ellipsis := &ast.Ellipsis{} 359 typ := &adt.Vertex{ 360 Parent: v, 361 Label: adt.AnyIndex, 362 } 363 v.MatchAndInsert(e.ctx, typ) 364 typ.Finalize(e.ctx) 365 if typ.Kind() != adt.TopKind { 366 ellipsis.Type = e.value(typ) 367 } 368 369 l.Elts = append(l.Elts, ellipsis) 370 } 371 return l 372 } 373 374 func (e exporter) showArcs(v *adt.Vertex) bool { 375 p := e.cfg 376 if !p.ShowHidden && !p.ShowDefinitions { 377 return false 378 } 379 for _, a := range v.Arcs { 380 switch { 381 case a.Label.IsDef() && p.ShowDefinitions: 382 return true 383 case a.Label.IsHidden() && p.ShowHidden: 384 return true 385 } 386 } 387 return false 388 } 389 390 func (e *exporter) structComposite(v *adt.Vertex, attrs []*ast.Attribute) ast.Expr { 391 s := e.top().scope 392 393 showRegular := false 394 switch x := v.BaseValue.(type) { 395 case *adt.StructMarker: 396 showRegular = true 397 case *adt.ListMarker: 398 // As lists may be long, put them at the end. 399 defer e.addEmbed(e.listComposite(v)) 400 case *adt.Bottom: 401 if !e.cfg.ShowErrors || !x.ChildError { 402 // Should not be reachable, but just in case. The output will be 403 // correct. 404 e.addEmbed(e.value(x)) 405 return s 406 } 407 // Always also show regular fields, even when list, as we are in 408 // debugging mode. 409 showRegular = true 410 // TODO(perf): do something better 411 for _, a := range v.Arcs { 412 if a.Label.IsInt() { 413 defer e.addEmbed(e.listComposite(v)) 414 break 415 } 416 } 417 418 case adt.Value: 419 e.addEmbed(e.value(x)) 420 } 421 422 for _, a := range attrs { 423 s.Elts = append(s.Elts, a) 424 } 425 426 p := e.cfg 427 for _, label := range VertexFeatures(e.ctx, v) { 428 show := false 429 switch label.Typ() { 430 case adt.StringLabel: 431 show = showRegular 432 case adt.IntLabel: 433 continue 434 case adt.DefinitionLabel: 435 show = p.ShowDefinitions 436 case adt.HiddenLabel, adt.HiddenDefinitionLabel: 437 show = p.ShowHidden && label.PkgID(e.ctx) == e.pkgID 438 } 439 if !show { 440 continue 441 } 442 443 f := &ast.Field{Label: e.stringLabel(label)} 444 445 e.addField(label, f, f.Value) 446 447 if label.IsDef() { 448 e.inDefinition++ 449 } 450 451 arc := v.LookupRaw(label) 452 if arc == nil { 453 continue 454 } 455 456 if arc.ArcType == adt.ArcOptional && !p.ShowOptional { 457 continue 458 } 459 // TODO: report an error for required fields in Final mode? 460 // This package typically does not create errors that did not result 461 // from evaluation already. 462 463 internal.SetConstraint(f, arc.ArcType.Token()) 464 465 f.Value = e.vertex(arc.DerefValue()) 466 467 if label.IsDef() { 468 e.inDefinition-- 469 } 470 471 if p.ShowAttributes { 472 f.Attrs = ExtractFieldAttrs(arc) 473 } 474 475 if p.ShowDocs { 476 docs := ExtractDoc(arc) 477 ast.SetComments(f, docs) 478 } 479 480 s.Elts = append(s.Elts, f) 481 } 482 483 return s 484 }