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