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