github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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/joomcode/cue/cue/ast" 22 "github.com/joomcode/cue/cue/token" 23 "github.com/joomcode/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.Elem) (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 s, saved := e.pushFrame(orig) 95 defer e.popFrame(saved) 96 97 // Handle value aliases and lets 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 x.markLets(c.c.Expr().Source()) 114 } 115 116 defer filterUnusedLets(s) 117 118 defer func() { 119 if valueAlias != nil { 120 valueAlias.Expr = expr 121 expr = valueAlias 122 } 123 }() 124 125 hasAlias := len(s.Elts) > 0 126 127 for _, c := range a { 128 e.top().upCount = c.up 129 x := c.c.Elem() 130 e.addExpr(c.c.Env, src, x, false) 131 } 132 133 if src != nil { 134 for _, a := range src.Arcs { 135 if x, ok := e.fields[a.Label]; ok { 136 x.arc = a 137 e.fields[a.Label] = x 138 } 139 } 140 } 141 142 for _, a := range e.attrs { 143 s.Elts = append(s.Elts, a) 144 } 145 146 // Unify values only for one level. 147 if a := e.values.Conjuncts; len(a) > 0 { 148 e.values.Finalize(e.ctx) 149 e.embed = append(e.embed, e.value(e.values, a...)) 150 } 151 152 // Collect and order set of fields. 153 154 fields := []adt.Feature{} 155 for f := range e.fields { 156 fields = append(fields, f) 157 } 158 159 // Sort fields in case features lists are missing to ensure 160 // predictability. Also sort in reverse order, so that bugs 161 // are more likely exposed. 162 sort.Slice(fields, func(i, j int) bool { 163 return fields[i] > fields[j] 164 }) 165 166 if adt.DebugSort == 0 { 167 m := sortArcs(extractFeatures(e.structs)) 168 sort.SliceStable(fields, func(i, j int) bool { 169 if m[fields[j]] == 0 { 170 return m[fields[i]] != 0 171 } 172 return m[fields[i]] > m[fields[j]] 173 }) 174 } else { 175 adt.DebugSortFields(e.ctx, fields) 176 } 177 178 if len(e.fields) == 0 && !e.hasEllipsis { 179 switch len(e.embed) + len(e.conjuncts) { 180 case 0: 181 if len(e.attrs) > 0 { 182 break 183 } 184 if len(e.structs) > 0 || e.isData { 185 return e.wrapCloseIfNecessary(s, src) 186 } 187 return ast.NewIdent("_") 188 case 1: 189 var x ast.Expr 190 if len(e.conjuncts) == 1 { 191 x = e.conjuncts[0] 192 } else { 193 x = e.embed[0] 194 } 195 if len(e.attrs) == 0 && !hasAlias { 196 return x 197 } 198 if st, ok := x.(*ast.StructLit); ok { 199 s.Elts = append(s.Elts, st.Elts...) 200 return e.wrapCloseIfNecessary(s, src) 201 } 202 } 203 } 204 205 for _, x := range e.embed { 206 s.Elts = append(s.Elts, &ast.EmbedDecl{Expr: x}) 207 } 208 209 for _, f := range fields { 210 field := e.fields[f] 211 c := field.conjuncts 212 213 label := e.stringLabel(f) 214 215 if f.IsDef() { 216 x.inDefinition++ 217 } 218 219 a := []adt.Conjunct{} 220 for _, cc := range c { 221 a = append(a, cc.c) 222 } 223 224 d := &ast.Field{Label: label} 225 226 top := e.frame(0) 227 if fr, ok := top.fields[f]; ok && fr.alias != "" { 228 setFieldAlias(d, fr.alias) 229 fr.node = d 230 top.fields[f] = fr 231 } 232 233 d.Value = e.mergeValues(f, field.arc, c, a...) 234 235 if f.IsDef() { 236 x.inDefinition-- 237 } 238 239 if isOptional(a) { 240 d.Optional = token.Blank.Pos() 241 } 242 if x.cfg.ShowDocs { 243 docs := extractDocs(src, a) 244 ast.SetComments(d, docs) 245 } 246 if x.cfg.ShowAttributes { 247 for _, c := range a { 248 d.Attrs = extractFieldAttrs(d.Attrs, c) 249 } 250 } 251 s.Elts = append(s.Elts, d) 252 } 253 if e.hasEllipsis { 254 s.Elts = append(s.Elts, &ast.Ellipsis{}) 255 } 256 257 ws := e.wrapCloseIfNecessary(s, src) 258 switch { 259 case len(e.conjuncts) == 0: 260 return ws 261 262 case len(e.structs) > 0, len(s.Elts) > 0: 263 e.conjuncts = append(e.conjuncts, ws) 264 } 265 266 return ast.NewBinExpr(token.AND, e.conjuncts...) 267 } 268 269 func (e *conjuncts) wrapCloseIfNecessary(s *ast.StructLit, v *adt.Vertex) ast.Expr { 270 if !e.hasEllipsis && v != nil { 271 if st, ok := v.BaseValue.(*adt.StructMarker); ok && st.NeedClose { 272 return ast.NewCall(ast.NewIdent("close"), s) 273 } 274 } 275 return s 276 } 277 278 // Conjuncts if for collecting values of a single vertex. 279 type conjuncts struct { 280 *exporter 281 // Values is used to collect non-struct values. 282 values *adt.Vertex 283 embed []ast.Expr 284 conjuncts []ast.Expr 285 structs []*adt.StructInfo 286 fields map[adt.Feature]field 287 attrs []*ast.Attribute 288 hasEllipsis bool 289 290 // A value is a struct if it has a non-zero structs slice or if isData is 291 // set to true. Data vertices may not have conjuncts associated with them. 292 isData bool 293 } 294 295 func (c *conjuncts) addValueConjunct(src *adt.Vertex, env *adt.Environment, x adt.Elem) { 296 switch b, ok := x.(adt.BaseValue); { 297 case ok && src != nil && isTop(b) && !isTop(src.BaseValue): 298 // drop top 299 default: 300 c.values.AddConjunct(adt.MakeRootConjunct(env, x)) 301 } 302 } 303 304 func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node) { 305 x := c.fields[f] 306 v := adt.MakeRootConjunct(env, n) 307 x.conjuncts = append(x.conjuncts, conjunct{ 308 c: v, 309 up: c.top().upCount, 310 }) 311 // x.upCounts = append(x.upCounts, c.top().upCount) 312 c.fields[f] = x 313 } 314 315 type field struct { 316 docs []*ast.CommentGroup 317 arc *adt.Vertex 318 conjuncts []conjunct 319 } 320 321 type conjunct struct { 322 c adt.Conjunct 323 up int32 324 } 325 326 func (e *conjuncts) addExpr(env *adt.Environment, src *adt.Vertex, x adt.Elem, isEmbed bool) { 327 switch x := x.(type) { 328 case *adt.StructLit: 329 e.top().upCount++ 330 331 if e.cfg.ShowAttributes { 332 e.attrs = extractDeclAttrs(e.attrs, x.Src) 333 } 334 335 // Only add if it only has no bulk fields or elipsis. 336 if isComplexStruct(x) { 337 _, saved := e.pushFrame(nil) 338 e.embed = append(e.embed, e.adt(x, nil)) 339 e.top().upCount-- // not necessary, but for proper form 340 e.popFrame(saved) 341 return 342 } 343 // Used for sorting. 344 e.structs = append(e.structs, &adt.StructInfo{StructLit: x, Env: env}) 345 346 for _, d := range x.Decls { 347 var label adt.Feature 348 switch f := d.(type) { 349 case *adt.Field: 350 label = f.Label 351 case *adt.OptionalField: 352 // TODO: mark optional here. 353 label = f.Label 354 case *adt.Ellipsis: 355 e.hasEllipsis = true 356 continue 357 case adt.Expr: 358 e.addExpr(env, nil, f, true) 359 continue 360 361 // TODO: also handle dynamic fields 362 default: 363 panic(fmt.Sprintf("Unexpected type %T", d)) 364 } 365 e.addConjunct(label, env, d) 366 } 367 e.top().upCount-- 368 369 case adt.Value: // other values. 370 switch v := x.(type) { 371 case nil: 372 default: 373 e.addValueConjunct(src, env, x) 374 375 case *adt.Vertex: 376 if b, ok := v.BaseValue.(*adt.Bottom); ok { 377 if !b.IsIncomplete() || e.cfg.Final { 378 e.addExpr(env, v, b, false) 379 return 380 } 381 } 382 383 switch { 384 default: 385 for _, c := range v.Conjuncts { 386 e.addExpr(c.Env, v, c.Elem(), false) 387 } 388 389 case v.IsData(): 390 e.structs = append(e.structs, v.Structs...) 391 e.isData = true 392 393 if y, ok := v.BaseValue.(adt.Value); ok { 394 e.addValueConjunct(src, env, y) 395 } 396 397 for _, a := range v.Arcs { 398 a.Finalize(e.ctx) // TODO: should we do this? 399 400 e.addConjunct(a.Label, env, a) 401 } 402 } 403 } 404 405 case *adt.BinaryExpr: 406 switch { 407 case x.Op == adt.AndOp && !isEmbed: 408 e.addExpr(env, src, x.X, false) 409 e.addExpr(env, src, x.Y, false) 410 case isSelfContained(x): 411 e.addValueConjunct(src, env, x) 412 default: 413 if isEmbed { 414 e.embed = append(e.embed, e.expr(x)) 415 } else { 416 e.conjuncts = append(e.conjuncts, e.expr(x)) 417 } 418 } 419 420 default: 421 switch { 422 case isSelfContained(x): 423 e.addValueConjunct(src, env, x) 424 case isEmbed: 425 e.embed = append(e.embed, e.expr(x)) 426 default: 427 e.conjuncts = append(e.conjuncts, e.expr(x)) 428 } 429 } 430 } 431 432 func isTop(x adt.BaseValue) bool { 433 switch v := x.(type) { 434 case *adt.Top: 435 return true 436 case *adt.BasicType: 437 return v.K == adt.TopKind 438 default: 439 return false 440 } 441 } 442 443 // TODO: find a better way to annotate optionality. Maybe a special conjunct 444 // or store it in the field information? 445 func isOptional(a []adt.Conjunct) bool { 446 if len(a) == 0 { 447 return false 448 } 449 for _, c := range a { 450 if v, ok := c.Elem().(*adt.Vertex); ok && !v.IsData() && len(v.Conjuncts) > 0 { 451 return isOptional(v.Conjuncts) 452 } 453 switch f := c.Source().(type) { 454 case nil: 455 return false 456 case *ast.Field: 457 if f.Optional == token.NoPos { 458 return false 459 } 460 } 461 } 462 return true 463 } 464 465 func isComplexStruct(s *adt.StructLit) bool { 466 for _, d := range s.Decls { 467 switch x := d.(type) { 468 case *adt.Field: 469 // TODO: remove this and also handle field annotation in expr(). 470 // This allows structs to be merged. Ditto below. 471 if x.Src != nil { 472 if _, ok := x.Src.Label.(*ast.Alias); ok { 473 return ok 474 } 475 } 476 477 case *adt.OptionalField: 478 if x.Src != nil { 479 if _, ok := x.Src.Label.(*ast.Alias); ok { 480 return ok 481 } 482 } 483 484 case adt.Expr: 485 486 case *adt.Ellipsis: 487 if x.Value != nil { 488 return true 489 } 490 491 default: 492 return true 493 } 494 } 495 return false 496 } 497 498 func isSelfContained(expr adt.Elem) bool { 499 switch x := expr.(type) { 500 case *adt.BinaryExpr: 501 return isSelfContained(x.X) && isSelfContained(x.Y) 502 case *adt.UnaryExpr: 503 return isSelfContained(x.X) 504 case *adt.BoundExpr: 505 return isSelfContained(x.Expr) 506 case adt.Value: 507 return true 508 } 509 return false 510 }