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