github.com/solo-io/cue@v0.4.7/internal/core/export/expr.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 "sort" 20 21 "github.com/solo-io/cue/cue/ast" 22 "github.com/solo-io/cue/cue/token" 23 "github.com/solo-io/cue/internal/core/adt" 24 ) 25 26 // Modes: 27 // raw: as is 28 // def: merge structs, print reset as is. 29 // 30 // Possible simplifications in def mode: 31 // - merge contents of multiple _literal_ structs. 32 // - this is not possible if some of the elements are bulk optional 33 // (or is it?). 34 // - still do not ever resolve references. 35 // - to do this, fields must be pre-linked to their destinations. 36 // - use astutil.Sanitize to resolve shadowing and imports. 37 // 38 // 39 // Categories of printing: 40 // - concrete 41 // - optionals 42 // - references 43 // - constraints 44 // 45 // Mixed mode is also not supported in the old implementation (at least not 46 // correctly). It requires references to resolve properly, backtracking to 47 // a common root and prefixing that to the reference. This is now possible 48 // with the Environment construct and could be done later. 49 50 func (e *exporter) expr(v adt.Expr) (result ast.Expr) { 51 switch x := v.(type) { 52 case nil: 53 return nil 54 55 case *adt.Vertex: 56 if len(x.Conjuncts) == 0 || x.IsData() { 57 // Treat as literal value. 58 return e.value(x) 59 } // Should this be the arcs label? 60 61 a := []conjunct{} 62 for _, c := range x.Conjuncts { 63 a = append(a, conjunct{c, 0}) 64 } 65 66 return e.mergeValues(adt.InvalidLabel, x, a, x.Conjuncts...) 67 68 case *adt.StructLit: 69 c := adt.MakeRootConjunct(nil, x) 70 return e.mergeValues(adt.InvalidLabel, nil, []conjunct{{c: c, up: 0}}, c) 71 72 case adt.Value: 73 return e.value(x) // Use conjuncts. 74 75 default: 76 return e.adt(v, nil) 77 } 78 } 79 80 // Piece out values: 81 82 // For a struct, piece out conjuncts that are already values. Those can be 83 // unified. All other conjuncts are added verbatim. 84 85 func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct, orig ...adt.Conjunct) (expr ast.Expr) { 86 87 e := conjuncts{ 88 exporter: x, 89 values: &adt.Vertex{}, 90 fields: map[adt.Feature]field{}, 91 attrs: []*ast.Attribute{}, 92 } 93 94 _, saved := e.pushFrame(orig) 95 defer e.popFrame(saved) 96 97 // Handle value aliases 98 var valueAlias *ast.Alias 99 for _, c := range a { 100 if f, ok := c.c.Field().Source().(*ast.Field); ok { 101 if a, ok := f.Value.(*ast.Alias); ok { 102 if valueAlias == nil { 103 if e.valueAlias == nil { 104 e.valueAlias = map[*ast.Alias]*ast.Alias{} 105 } 106 name := a.Ident.Name 107 name = e.uniqueAlias(name) 108 valueAlias = &ast.Alias{Ident: ast.NewIdent(name)} 109 } 110 e.valueAlias[a] = valueAlias 111 } 112 } 113 } 114 defer func() { 115 if valueAlias != nil { 116 valueAlias.Expr = expr 117 expr = valueAlias 118 } 119 }() 120 121 for _, c := range a { 122 e.top().upCount = c.up 123 x := c.c.Expr() 124 e.addExpr(c.c.Env, src, x, false) 125 } 126 127 if src != nil { 128 for _, a := range src.Arcs { 129 if x, ok := e.fields[a.Label]; ok { 130 x.arc = a 131 e.fields[a.Label] = x 132 } 133 } 134 } 135 136 s := x.top().scope 137 138 for _, a := range e.attrs { 139 s.Elts = append(s.Elts, a) 140 } 141 142 // Unify values only for one level. 143 if a := e.values.Conjuncts; len(a) > 0 { 144 e.values.Finalize(e.ctx) 145 e.embed = append(e.embed, e.value(e.values, a...)) 146 } 147 148 // Collect and order set of fields. 149 150 fields := []adt.Feature{} 151 for f := range e.fields { 152 fields = append(fields, f) 153 } 154 155 // Sort fields in case features lists are missing to ensure 156 // predictability. Also sort in reverse order, so that bugs 157 // are more likely exposed. 158 sort.Slice(fields, func(i, j int) bool { 159 return fields[i] > fields[j] 160 }) 161 162 m := sortArcs(extractFeatures(e.structs)) 163 sort.SliceStable(fields, func(i, j int) bool { 164 if m[fields[j]] == 0 { 165 return m[fields[i]] != 0 166 } 167 return m[fields[i]] > m[fields[j]] 168 }) 169 170 if len(e.fields) == 0 && !e.hasEllipsis { 171 switch len(e.embed) + len(e.conjuncts) { 172 case 0: 173 if len(e.attrs) > 0 { 174 break 175 } 176 if len(e.structs) > 0 { 177 return s 178 } 179 return ast.NewIdent("_") 180 case 1: 181 var x ast.Expr 182 if len(e.conjuncts) == 1 { 183 x = e.conjuncts[0] 184 } else { 185 x = e.embed[0] 186 } 187 if len(e.attrs) == 0 { 188 return x 189 } 190 if st, ok := x.(*ast.StructLit); ok { 191 s.Elts = append(s.Elts, st.Elts...) 192 return s 193 } 194 case 2: 195 if len(e.attrs) > 0 { 196 break 197 } 198 // Simplify. 199 e.conjuncts = append(e.conjuncts, e.embed...) 200 return ast.NewBinExpr(token.AND, e.conjuncts...) 201 } 202 } 203 204 for _, x := range e.embed { 205 s.Elts = append(s.Elts, &ast.EmbedDecl{Expr: x}) 206 } 207 208 for _, f := range fields { 209 field := e.fields[f] 210 c := field.conjuncts 211 212 label := e.stringLabel(f) 213 214 if f.IsDef() { 215 x.inDefinition++ 216 } 217 218 a := []adt.Conjunct{} 219 for _, cc := range c { 220 a = append(a, cc.c) 221 } 222 223 d := &ast.Field{Label: label} 224 225 top := e.frame(0) 226 if fr, ok := top.fields[f]; ok && fr.alias != "" { 227 setFieldAlias(d, fr.alias) 228 fr.node = d 229 top.fields[f] = fr 230 } 231 232 d.Value = e.mergeValues(f, field.arc, c, a...) 233 234 if f.IsDef() { 235 x.inDefinition-- 236 } 237 238 if isOptional(a) { 239 d.Optional = token.Blank.Pos() 240 } 241 if x.cfg.ShowDocs { 242 docs := extractDocs(src, a) 243 ast.SetComments(d, docs) 244 } 245 if x.cfg.ShowAttributes { 246 for _, c := range a { 247 d.Attrs = extractFieldAttrs(d.Attrs, c) 248 } 249 } 250 s.Elts = append(s.Elts, d) 251 } 252 if e.hasEllipsis { 253 s.Elts = append(s.Elts, &ast.Ellipsis{}) 254 } 255 256 // TODO: why was this necessary? 257 // else if src != nil && src.IsClosedStruct() && e.inDefinition == 0 { 258 // return ast.NewCall(ast.NewIdent("close"), s) 259 // } 260 261 e.conjuncts = append(e.conjuncts, s) 262 263 return ast.NewBinExpr(token.AND, e.conjuncts...) 264 } 265 266 // Conjuncts if for collecting values of a single vertex. 267 type conjuncts struct { 268 *exporter 269 // Values is used to collect non-struct values. 270 values *adt.Vertex 271 embed []ast.Expr 272 conjuncts []ast.Expr 273 structs []*adt.StructInfo 274 fields map[adt.Feature]field 275 attrs []*ast.Attribute 276 hasEllipsis bool 277 } 278 279 func (c *conjuncts) addValueConjunct(src *adt.Vertex, env *adt.Environment, x adt.Expr) { 280 switch b, ok := x.(adt.BaseValue); { 281 case ok && src != nil && isTop(b) && !isTop(src.BaseValue): 282 // drop top 283 default: 284 c.values.AddConjunct(adt.MakeRootConjunct(env, x)) 285 } 286 } 287 288 func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node) { 289 x := c.fields[f] 290 v := adt.MakeRootConjunct(env, n) 291 x.conjuncts = append(x.conjuncts, conjunct{ 292 c: v, 293 up: c.top().upCount, 294 }) 295 // x.upCounts = append(x.upCounts, c.top().upCount) 296 c.fields[f] = x 297 } 298 299 type field struct { 300 docs []*ast.CommentGroup 301 arc *adt.Vertex 302 conjuncts []conjunct 303 } 304 305 type conjunct struct { 306 c adt.Conjunct 307 up int32 308 } 309 310 func (e *conjuncts) addExpr(env *adt.Environment, src *adt.Vertex, x adt.Expr, isEmbed bool) { 311 switch x := x.(type) { 312 case *adt.StructLit: 313 e.top().upCount++ 314 315 if e.cfg.ShowAttributes { 316 e.attrs = extractDeclAttrs(e.attrs, x.Src) 317 } 318 319 // Only add if it only has no bulk fields or elipsis. 320 if isComplexStruct(x) { 321 _, saved := e.pushFrame(nil) 322 e.embed = append(e.embed, e.adt(x, nil)) 323 e.top().upCount-- // not necessary, but for proper form 324 e.popFrame(saved) 325 return 326 } 327 // Used for sorting. 328 e.structs = append(e.structs, &adt.StructInfo{StructLit: x, Env: env}) 329 330 for _, d := range x.Decls { 331 var label adt.Feature 332 switch f := d.(type) { 333 case *adt.Field: 334 label = f.Label 335 case *adt.OptionalField: 336 // TODO: mark optional here. 337 label = f.Label 338 case *adt.Ellipsis: 339 e.hasEllipsis = true 340 continue 341 case adt.Expr: 342 e.addExpr(env, nil, f, true) 343 continue 344 345 // TODO: also handle dynamic fields 346 default: 347 panic(fmt.Sprintf("Unexpected type %T", d)) 348 } 349 e.addConjunct(label, env, d) 350 } 351 e.top().upCount-- 352 353 case adt.Value: // other values. 354 switch v := x.(type) { 355 case nil: 356 default: 357 e.addValueConjunct(src, env, x) 358 359 case *adt.Vertex: 360 if b, ok := v.BaseValue.(*adt.Bottom); ok { 361 if !b.IsIncomplete() || e.cfg.Final { 362 e.addExpr(env, v, b, false) 363 return 364 } 365 } 366 367 switch { 368 default: 369 for _, c := range v.Conjuncts { 370 e.addExpr(c.Env, v, c.Expr(), false) 371 } 372 373 case v.IsData(): 374 e.structs = append(e.structs, v.Structs...) 375 376 if y, ok := v.BaseValue.(adt.Value); ok { 377 e.addValueConjunct(src, env, y) 378 } 379 380 for _, a := range v.Arcs { 381 a.Finalize(e.ctx) // TODO: should we do this? 382 383 e.addConjunct(a.Label, env, a) 384 } 385 } 386 } 387 388 case *adt.BinaryExpr: 389 switch { 390 case x.Op == adt.AndOp && !isEmbed: 391 e.addExpr(env, src, x.X, false) 392 e.addExpr(env, src, x.Y, false) 393 case isSelfContained(x): 394 e.addValueConjunct(src, env, x) 395 default: 396 if isEmbed { 397 e.embed = append(e.embed, e.expr(x)) 398 } else { 399 e.conjuncts = append(e.conjuncts, e.expr(x)) 400 } 401 } 402 403 default: 404 switch { 405 case isSelfContained(x): 406 e.addValueConjunct(src, env, x) 407 case isEmbed: 408 e.embed = append(e.embed, e.expr(x)) 409 default: 410 e.conjuncts = append(e.conjuncts, e.expr(x)) 411 } 412 } 413 } 414 415 func isTop(x adt.BaseValue) bool { 416 switch v := x.(type) { 417 case *adt.Top: 418 return true 419 case *adt.BasicType: 420 return v.K == adt.TopKind 421 default: 422 return false 423 } 424 } 425 426 // TODO: find a better way to annotate optionality. Maybe a special conjunct 427 // or store it in the field information? 428 func isOptional(a []adt.Conjunct) bool { 429 if len(a) == 0 { 430 return false 431 } 432 for _, c := range a { 433 if v, ok := c.Expr().(*adt.Vertex); ok && !v.IsData() && len(v.Conjuncts) > 0 { 434 return isOptional(v.Conjuncts) 435 } 436 switch f := c.Source().(type) { 437 case nil: 438 return false 439 case *ast.Field: 440 if f.Optional == token.NoPos { 441 return false 442 } 443 } 444 } 445 return true 446 } 447 448 func isComplexStruct(s *adt.StructLit) bool { 449 for _, d := range s.Decls { 450 switch x := d.(type) { 451 case *adt.Field: 452 // TODO: remove this and also handle field annotation in expr(). 453 // This allows structs to be merged. Ditto below. 454 if x.Src != nil { 455 if _, ok := x.Src.Label.(*ast.Alias); ok { 456 return ok 457 } 458 } 459 460 case *adt.OptionalField: 461 if x.Src != nil { 462 if _, ok := x.Src.Label.(*ast.Alias); ok { 463 return ok 464 } 465 } 466 467 case adt.Expr: 468 469 case *adt.Ellipsis: 470 if x.Value != nil { 471 return true 472 } 473 474 default: 475 return true 476 } 477 } 478 return false 479 } 480 481 func isSelfContained(expr adt.Expr) bool { 482 switch x := expr.(type) { 483 case *adt.BinaryExpr: 484 return isSelfContained(x.X) && isSelfContained(x.Y) 485 case *adt.UnaryExpr: 486 return isSelfContained(x.X) 487 case *adt.BoundExpr: 488 return isSelfContained(x.Expr) 489 case adt.Value: 490 return true 491 } 492 return false 493 }