cuelang.org/go@v0.13.0/internal/core/debug/debug.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 debug prints a given ADT node. 16 // 17 // Note that the result is not valid CUE, but instead prints the internals 18 // of an ADT node in human-readable form. It uses a simple indentation algorithm 19 // for improved readability and diffing. 20 package debug 21 22 import ( 23 "fmt" 24 "strconv" 25 "strings" 26 27 "cuelang.org/go/cue/errors" 28 "cuelang.org/go/cue/literal" 29 "cuelang.org/go/internal/core/adt" 30 ) 31 32 const ( 33 openTuple = "\u3008" 34 closeTuple = "\u3009" 35 ) 36 37 type Config struct { 38 Cwd string 39 Compact bool 40 Raw bool 41 } 42 43 // AppendNode writes a string representation of the node to w. 44 func AppendNode(dst []byte, i adt.StringIndexer, n adt.Node, config *Config) []byte { 45 if config == nil { 46 config = &Config{} 47 } 48 p := printer{dst: dst, index: i, cfg: config} 49 if config.Compact { 50 p := compactPrinter{p} 51 p.node(n) 52 return p.dst 53 } 54 p.node(n) 55 return p.dst 56 } 57 58 // NodeString returns a string representation of the given node. 59 // The StringIndexer value i is used to translate elements of n to strings. 60 // Commonly available implementations of StringIndexer include *adt.OpContext 61 // and *runtime.Runtime. 62 func NodeString(i adt.StringIndexer, n adt.Node, config *Config) string { 63 var buf [128]byte 64 return string(AppendNode(buf[:0], i, n, config)) 65 } 66 67 type printer struct { 68 dst []byte 69 index adt.StringIndexer 70 indent string 71 cfg *Config 72 73 // keep track of vertices to avoid cycles. 74 stack []*adt.Vertex 75 76 // modes: 77 // - show vertex 78 // - show original conjuncts 79 // - show unevaluated 80 // - auto 81 } 82 83 func (w *printer) string(s string) { 84 if len(w.indent) > 0 { 85 s = strings.Replace(s, "\n", "\n"+w.indent, -1) 86 } 87 w.dst = append(w.dst, s...) 88 } 89 90 func (w *printer) int(i int64) { 91 w.dst = strconv.AppendInt(w.dst, i, 10) 92 } 93 94 func (w *printer) label(f adt.Feature) { 95 switch { 96 case f.IsHidden(): 97 ident := f.IdentString(w.index) 98 if pkgName := f.PkgID(w.index); pkgName != "_" { 99 ident = fmt.Sprintf("%s(%s)", ident, pkgName) 100 } 101 w.string(ident) 102 103 case f.IsLet(): 104 ident := f.RawString(w.index) 105 ident = strings.Replace(ident, "\x00", "#", 1) 106 w.string(ident) 107 108 default: 109 w.string(f.SelectorString(w.index)) 110 } 111 } 112 113 func (w *printer) ident(f adt.Feature) { 114 w.string(f.IdentString(w.index)) 115 } 116 117 func (w *printer) path(v *adt.Vertex) { 118 if p := v.Parent; p != nil && p.Label != 0 { 119 w.path(v.Parent) 120 w.string(".") 121 } 122 w.label(v.Label) 123 } 124 125 func (w *printer) shared(v *adt.Vertex) { 126 w.string("~(") 127 w.path(v) 128 w.string(")") 129 } 130 131 // printShared prints a reference to a structure-shared node that is a value 132 // of v, if it is a shared node. It reports the dereferenced node and whether 133 // the node was printed. 134 func (w *printer) printShared(v0 *adt.Vertex) (x *adt.Vertex, ok bool) { 135 // Handle cyclic shared nodes differently. If a shared node was part of 136 // a disjunction, it will still be wrapped in a disjunct Vertex. 137 // Similarly, a shared node should never point to a disjunct directly, 138 // but rather to the original arc that subsequently points to a 139 // disjunct. 140 v0 = v0.DerefDisjunct() 141 isCyclic := v0.IsCyclic 142 s, ok := v0.BaseValue.(*adt.Vertex) 143 v1 := v0.DerefValue() 144 useReference := v0.IsShared && !v1.Internal() 145 isCyclic = isCyclic || v1.IsCyclic 146 _ = isCyclic 147 // NOTE(debug): use this line instead of the following to expand shared 148 // cases where it is safe to do so. 149 // if useReference && isCyclic && ok && len(v.Arcs) > 0 { 150 if useReference && ok && len(v1.Arcs) > 0 { 151 w.shared(v1) 152 return v1, true 153 } 154 if !w.pushVertex(v1) { 155 if s != nil { 156 w.shared(s) 157 w.string(" =>") 158 } 159 w.shared(v1) 160 return v1, true 161 } 162 return v1, false 163 } 164 165 func (w *printer) pushVertex(v *adt.Vertex) bool { 166 for _, x := range w.stack { 167 if x == v { 168 w.string("<TODO: unmarked structural cycle>") 169 return false 170 } 171 } 172 w.stack = append(w.stack, v) 173 return true 174 } 175 176 func (w *printer) popVertex() { 177 w.stack = w.stack[:len(w.stack)-1] 178 } 179 180 func (w *printer) shortError(errs errors.Error) { 181 for { 182 msg, args := errs.Msg() 183 w.dst = fmt.Appendf(w.dst, msg, args...) 184 185 err := errors.Unwrap(errs) 186 if err == nil { 187 break 188 } 189 190 if errs, _ = err.(errors.Error); errs != nil { 191 w.string(err.Error()) 192 break 193 } 194 } 195 } 196 197 func (w *printer) interpolation(x *adt.Interpolation) { 198 quote := `"` 199 if x.K == adt.BytesKind { 200 quote = `'` 201 } 202 w.string(quote) 203 for i := 0; i < len(x.Parts); i += 2 { 204 switch x.K { 205 case adt.StringKind: 206 if s, ok := x.Parts[i].(*adt.String); ok { 207 w.string(s.Str) 208 } else { 209 w.string("<bad string>") 210 } 211 case adt.BytesKind: 212 if s, ok := x.Parts[i].(*adt.Bytes); ok { 213 w.dst = append(w.dst, s.B...) 214 } else { 215 w.string("<bad bytes>") 216 } 217 } 218 if i+1 < len(x.Parts) { 219 w.string(`\(`) 220 w.node(x.Parts[i+1]) 221 w.string(`)`) 222 } 223 } 224 w.string(quote) 225 } 226 227 func (w *printer) arg(n adt.Node) { 228 if x, ok := n.(*adt.Vertex); ok { 229 if x.Label != adt.InvalidLabel { 230 w.path(x) 231 return 232 } 233 } 234 w.node(n) 235 } 236 237 func (w *printer) node(n adt.Node) { 238 switch x := n.(type) { 239 case *adt.Vertex: 240 x, ok := w.printShared(x) 241 if ok { 242 return 243 } 244 defer w.popVertex() 245 246 var kind adt.Kind 247 if x.BaseValue != nil { 248 kind = x.BaseValue.Kind() 249 } 250 251 kindStr := kind.String() 252 253 // TODO: replace with showing full closedness data. 254 if x.IsClosedList() || x.IsClosedStruct() { 255 if kind == adt.ListKind || kind == adt.StructKind { 256 kindStr = "#" + kindStr 257 } 258 } 259 260 w.dst = fmt.Appendf(w.dst, "(%s){", kindStr) 261 262 saved := w.indent 263 w.indent += " " 264 defer func() { w.indent = saved }() 265 266 switch v := x.BaseValue.(type) { 267 case nil: 268 case *adt.Bottom: 269 // TODO: reuse bottom. 270 saved := w.indent 271 w.indent += "// " 272 w.string("\n") 273 w.dst = fmt.Appendf(w.dst, "[%v]", v.Code) 274 if !v.ChildError { 275 msg := errors.Details(v.Err, &errors.Config{ 276 Cwd: w.cfg.Cwd, 277 ToSlash: true, 278 }) 279 msg = strings.TrimSpace(msg) 280 if msg != "" { 281 w.string(" ") 282 w.string(msg) 283 } 284 285 // TODO: we could consider removing CycleError here. It does 286 // seem safer, however, as sometimes structural cycles are 287 // detected as regular cycles. 288 // Alternatively, we could consider to never report arcs if 289 // there is any error. 290 if v.Code == adt.CycleError || v.Code == adt.StructuralCycleError { 291 goto endVertex 292 } 293 } 294 w.indent = saved 295 296 case *adt.StructMarker, *adt.ListMarker: 297 // if len(x.Arcs) == 0 { 298 // // w.string("}") 299 // // return 300 // } 301 302 case adt.Value: 303 if len(x.Arcs) == 0 { 304 w.string(" ") 305 w.node(v) 306 w.string(" }") 307 return 308 } 309 w.string("\n") 310 w.node(v) 311 } 312 313 for _, a := range x.Arcs { 314 if a.ArcType == adt.ArcNotPresent { 315 continue 316 } 317 if a.Label.IsLet() { 318 w.string("\n") 319 w.string("let ") 320 w.label(a.Label) 321 if a.MultiLet { 322 w.string("multi") 323 } 324 w.string(" = ") 325 if c := a.ConjunctAt(0); a.MultiLet { 326 w.node(c.Expr()) 327 continue 328 } 329 w.node(a) 330 } else { 331 w.string("\n") 332 w.label(a.Label) 333 w.string(a.ArcType.Suffix()) 334 w.string(": ") 335 w.node(a) 336 } 337 } 338 339 if x.BaseValue == nil { 340 w.indent += "// " 341 w.string("// ") 342 for i, c := range x.Conjuncts { 343 if c.CloseInfo.FromDef || c.CloseInfo.FromEmbed { 344 w.string("[") 345 if c.CloseInfo.FromDef { 346 w.string("d") 347 } 348 if c.CloseInfo.FromEmbed { 349 w.string("e") 350 } 351 w.string("]") 352 } 353 if i > 0 { 354 w.string(" & ") 355 } 356 w.node(c.Elem()) // TODO: also include env? 357 } 358 } 359 360 endVertex: 361 362 w.indent = saved 363 w.string("\n") 364 w.string("}") 365 366 case *adt.StructMarker: 367 w.string("struct") 368 369 case *adt.ListMarker: 370 w.string("list") 371 372 case *adt.StructLit: 373 if len(x.Decls) == 0 { 374 w.string("{}") 375 break 376 } 377 w.string("{") 378 w.indent += " " 379 for _, d := range x.Decls { 380 w.string("\n") 381 w.node(d) 382 } 383 w.indent = w.indent[:len(w.indent)-2] 384 w.string("\n}") 385 386 case *adt.ListLit: 387 if len(x.Elems) == 0 { 388 w.string("[]") 389 break 390 } 391 w.string("[") 392 w.indent += " " 393 for _, d := range x.Elems { 394 w.string("\n") 395 w.node(d) 396 w.string(",") 397 } 398 w.indent = w.indent[:len(w.indent)-2] 399 w.string("\n]") 400 401 case *adt.Field: 402 w.label(x.Label) 403 w.string(x.ArcType.Suffix()) 404 w.string(":") 405 w.string(" ") 406 w.node(x.Value) 407 408 case *adt.LetField: 409 w.string("let ") 410 w.label(x.Label) 411 if x.IsMulti { 412 w.string("multi") 413 } 414 w.string(" = ") 415 w.node(x.Value) 416 417 case *adt.BulkOptionalField: 418 w.string("[") 419 w.node(x.Filter) 420 w.string("]: ") 421 w.node(x.Value) 422 423 case *adt.DynamicField: 424 w.node(x.Key) 425 w.string(x.ArcType.Suffix()) 426 w.string(": ") 427 w.node(x.Value) 428 429 case *adt.Ellipsis: 430 w.string("...") 431 if x.Value != nil { 432 w.node(x.Value) 433 } 434 435 case *adt.Bottom: 436 w.string(`_|_`) 437 if x.Err != nil { 438 w.string("(") 439 w.shortError(x.Err) 440 w.string(")") 441 } 442 443 case *adt.Null: 444 w.string("null") 445 446 case *adt.Bool: 447 w.dst = strconv.AppendBool(w.dst, x.B) 448 449 case *adt.Num: 450 w.string(x.X.String()) 451 452 case *adt.String: 453 w.dst = literal.String.Append(w.dst, x.Str) 454 455 case *adt.Bytes: 456 w.dst = literal.Bytes.Append(w.dst, string(x.B)) 457 458 case *adt.Top: 459 w.string("_") 460 461 case *adt.BasicType: 462 w.string(x.K.String()) 463 464 case *adt.BoundExpr: 465 w.string(x.Op.String()) 466 w.node(x.Expr) 467 468 case *adt.BoundValue: 469 w.string(x.Op.String()) 470 w.node(x.Value) 471 472 case *adt.NodeLink: 473 w.string(openTuple) 474 for i, f := range x.Node.Path() { 475 if i > 0 { 476 w.string(".") 477 } 478 w.label(f) 479 } 480 w.string(closeTuple) 481 482 case *adt.FieldReference: 483 w.string(openTuple) 484 w.int(int64(x.UpCount)) 485 w.string(";") 486 w.label(x.Label) 487 w.string(closeTuple) 488 489 case *adt.ValueReference: 490 w.string(openTuple) 491 w.int(int64(x.UpCount)) 492 w.string(closeTuple) 493 494 case *adt.LabelReference: 495 w.string(openTuple) 496 w.int(int64(x.UpCount)) 497 w.string(";-") 498 w.string(closeTuple) 499 500 case *adt.DynamicReference: 501 w.string(openTuple) 502 w.int(int64(x.UpCount)) 503 w.string(";(") 504 w.node(x.Label) 505 w.string(")") 506 w.string(closeTuple) 507 508 case *adt.ImportReference: 509 w.string(openTuple + "import;") 510 w.label(x.ImportPath) 511 w.string(closeTuple) 512 513 case *adt.LetReference: 514 w.string(openTuple) 515 w.int(int64(x.UpCount)) 516 w.string(";let ") 517 w.label(x.Label) 518 w.string(closeTuple) 519 520 case *adt.SelectorExpr: 521 w.node(x.X) 522 w.string(".") 523 w.label(x.Sel) 524 525 case *adt.IndexExpr: 526 w.node(x.X) 527 w.string("[") 528 w.node(x.Index) 529 w.string("]") 530 531 case *adt.SliceExpr: 532 w.node(x.X) 533 w.string("[") 534 if x.Lo != nil { 535 w.node(x.Lo) 536 } 537 w.string(":") 538 if x.Hi != nil { 539 w.node(x.Hi) 540 } 541 if x.Stride != nil { 542 w.string(":") 543 w.node(x.Stride) 544 } 545 w.string("]") 546 547 case *adt.Interpolation: 548 w.interpolation(x) 549 550 case *adt.UnaryExpr: 551 w.string(x.Op.String()) 552 w.node(x.X) 553 554 case *adt.BinaryExpr: 555 w.string("(") 556 w.node(x.X) 557 w.string(" ") 558 w.string(x.Op.String()) 559 w.string(" ") 560 w.node(x.Y) 561 w.string(")") 562 563 case *adt.CallExpr: 564 w.node(x.Fun) 565 w.string("(") 566 for i, a := range x.Args { 567 if i > 0 { 568 w.string(", ") 569 } 570 w.arg(a) 571 } 572 w.string(")") 573 574 case *adt.Builtin: 575 if x.Package != 0 { 576 w.label(x.Package) 577 w.string(".") 578 } 579 w.string(x.Name) 580 581 case *adt.BuiltinValidator: 582 w.node(x.Builtin) 583 w.string("(") 584 for i, a := range x.Args { 585 if i > 0 { 586 w.string(", ") 587 } 588 w.arg(a) 589 } 590 w.string(")") 591 592 case *adt.DisjunctionExpr: 593 w.string("(") 594 for i, a := range x.Values { 595 if i > 0 { 596 w.string("|") 597 } 598 // Disjunct 599 if a.Default { 600 w.string("*") 601 } 602 w.node(a.Val) 603 } 604 w.string(")") 605 606 case *adt.Conjunction: 607 w.string("&(") 608 for i, c := range x.Values { 609 if i > 0 { 610 w.string(", ") 611 } 612 w.node(c) 613 } 614 w.string(")") 615 616 case *adt.ConjunctGroup: 617 w.string("&[") 618 for i, c := range *x { 619 if i > 0 { 620 w.string(", ") 621 } 622 w.node(c.Expr()) 623 } 624 w.string("]") 625 626 case *adt.Disjunction: 627 w.string("|(") 628 for i, c := range x.Values { 629 if i > 0 { 630 w.string(", ") 631 } 632 if i < x.NumDefaults { 633 w.string("*") 634 } 635 w.node(c) 636 } 637 w.string(")") 638 639 case *adt.Comprehension: 640 for _, c := range x.Clauses { 641 w.node(c) 642 } 643 w.node(adt.ToExpr(x.Value)) 644 645 case *adt.ForClause: 646 w.string("for ") 647 w.ident(x.Key) 648 w.string(", ") 649 w.ident(x.Value) 650 w.string(" in ") 651 w.node(x.Src) 652 w.string(" ") 653 654 case *adt.IfClause: 655 w.string("if ") 656 w.node(x.Condition) 657 w.string(" ") 658 659 case *adt.LetClause: 660 w.string("let ") 661 w.ident(x.Label) 662 w.string(" = ") 663 w.node(x.Expr) 664 w.string(" ") 665 666 case *adt.ValueClause: 667 668 default: 669 panic(fmt.Sprintf("unknown type %T", x)) 670 } 671 }