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