github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/ir/fmt.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ir 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/constant" 11 "io" 12 "os" 13 "path/filepath" 14 "reflect" 15 "strings" 16 17 "unicode/utf8" 18 19 "github.com/go-asm/go/cmd/compile/base" 20 "github.com/go-asm/go/cmd/compile/types" 21 "github.com/go-asm/go/cmd/src" 22 ) 23 24 // Op 25 26 var OpNames = []string{ 27 OADDR: "&", 28 OADD: "+", 29 OADDSTR: "+", 30 OANDAND: "&&", 31 OANDNOT: "&^", 32 OAND: "&", 33 OAPPEND: "append", 34 OAS: "=", 35 OAS2: "=", 36 OBREAK: "break", 37 OCALL: "function call", // not actual syntax 38 OCAP: "cap", 39 OCASE: "case", 40 OCLEAR: "clear", 41 OCLOSE: "close", 42 OCOMPLEX: "complex", 43 OBITNOT: "^", 44 OCONTINUE: "continue", 45 OCOPY: "copy", 46 ODELETE: "delete", 47 ODEFER: "defer", 48 ODIV: "/", 49 OEQ: "==", 50 OFALL: "fallthrough", 51 OFOR: "for", 52 OGE: ">=", 53 OGOTO: "goto", 54 OGT: ">", 55 OIF: "if", 56 OIMAG: "imag", 57 OINLMARK: "inlmark", 58 ODEREF: "*", 59 OLEN: "len", 60 OLE: "<=", 61 OLSH: "<<", 62 OLT: "<", 63 OMAKE: "make", 64 ONEG: "-", 65 OMAX: "max", 66 OMIN: "min", 67 OMOD: "%", 68 OMUL: "*", 69 ONEW: "new", 70 ONE: "!=", 71 ONOT: "!", 72 OOROR: "||", 73 OOR: "|", 74 OPANIC: "panic", 75 OPLUS: "+", 76 OPRINTLN: "println", 77 OPRINT: "print", 78 ORANGE: "range", 79 OREAL: "real", 80 ORECV: "<-", 81 ORECOVER: "recover", 82 ORETURN: "return", 83 ORSH: ">>", 84 OSELECT: "select", 85 OSEND: "<-", 86 OSUB: "-", 87 OSWITCH: "switch", 88 OUNSAFEADD: "unsafe.Add", 89 OUNSAFESLICE: "unsafe.Slice", 90 OUNSAFESLICEDATA: "unsafe.SliceData", 91 OUNSAFESTRING: "unsafe.String", 92 OUNSAFESTRINGDATA: "unsafe.StringData", 93 OXOR: "^", 94 } 95 96 // GoString returns the Go syntax for the Op, or else its name. 97 func (o Op) GoString() string { 98 if int(o) < len(OpNames) && OpNames[o] != "" { 99 return OpNames[o] 100 } 101 return o.String() 102 } 103 104 // Format implements formatting for an Op. 105 // The valid formats are: 106 // 107 // %v Go syntax ("+", "<-", "print") 108 // %+v Debug syntax ("ADD", "RECV", "PRINT") 109 func (o Op) Format(s fmt.State, verb rune) { 110 switch verb { 111 default: 112 fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o)) 113 case 'v': 114 if s.Flag('+') { 115 // %+v is OMUL instead of "*" 116 io.WriteString(s, o.String()) 117 return 118 } 119 io.WriteString(s, o.GoString()) 120 } 121 } 122 123 // Node 124 125 // fmtNode implements formatting for a Node n. 126 // Every Node implementation must define a Format method that calls fmtNode. 127 // The valid formats are: 128 // 129 // %v Go syntax 130 // %L Go syntax followed by " (type T)" if type is known. 131 // %+v Debug syntax, as in Dump. 132 func fmtNode(n Node, s fmt.State, verb rune) { 133 // %+v prints Dump. 134 // Otherwise we print Go syntax. 135 if s.Flag('+') && verb == 'v' { 136 dumpNode(s, n, 1) 137 return 138 } 139 140 if verb != 'v' && verb != 'S' && verb != 'L' { 141 fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n) 142 return 143 } 144 145 if n == nil { 146 fmt.Fprint(s, "<nil>") 147 return 148 } 149 150 t := n.Type() 151 if verb == 'L' && t != nil { 152 if t.Kind() == types.TNIL { 153 fmt.Fprint(s, "nil") 154 } else if n.Op() == ONAME && n.Name().AutoTemp() { 155 fmt.Fprintf(s, "%v value", t) 156 } else { 157 fmt.Fprintf(s, "%v (type %v)", n, t) 158 } 159 return 160 } 161 162 // TODO inlining produces expressions with ninits. we can't print these yet. 163 164 if OpPrec[n.Op()] < 0 { 165 stmtFmt(n, s) 166 return 167 } 168 169 exprFmt(n, s, 0) 170 } 171 172 var OpPrec = []int{ 173 OAPPEND: 8, 174 OBYTES2STR: 8, 175 OARRAYLIT: 8, 176 OSLICELIT: 8, 177 ORUNES2STR: 8, 178 OCALLFUNC: 8, 179 OCALLINTER: 8, 180 OCALLMETH: 8, 181 OCALL: 8, 182 OCAP: 8, 183 OCLEAR: 8, 184 OCLOSE: 8, 185 OCOMPLIT: 8, 186 OCONVIFACE: 8, 187 OCONVNOP: 8, 188 OCONV: 8, 189 OCOPY: 8, 190 ODELETE: 8, 191 OGETG: 8, 192 OLEN: 8, 193 OLITERAL: 8, 194 OMAKESLICE: 8, 195 OMAKESLICECOPY: 8, 196 OMAKE: 8, 197 OMAPLIT: 8, 198 OMAX: 8, 199 OMIN: 8, 200 ONAME: 8, 201 ONEW: 8, 202 ONIL: 8, 203 ONONAME: 8, 204 OPANIC: 8, 205 OPAREN: 8, 206 OPRINTLN: 8, 207 OPRINT: 8, 208 ORUNESTR: 8, 209 OSLICE2ARR: 8, 210 OSLICE2ARRPTR: 8, 211 OSTR2BYTES: 8, 212 OSTR2RUNES: 8, 213 OSTRUCTLIT: 8, 214 OTYPE: 8, 215 OUNSAFEADD: 8, 216 OUNSAFESLICE: 8, 217 OUNSAFESLICEDATA: 8, 218 OUNSAFESTRING: 8, 219 OUNSAFESTRINGDATA: 8, 220 OINDEXMAP: 8, 221 OINDEX: 8, 222 OSLICE: 8, 223 OSLICESTR: 8, 224 OSLICEARR: 8, 225 OSLICE3: 8, 226 OSLICE3ARR: 8, 227 OSLICEHEADER: 8, 228 OSTRINGHEADER: 8, 229 ODOTINTER: 8, 230 ODOTMETH: 8, 231 ODOTPTR: 8, 232 ODOTTYPE2: 8, 233 ODOTTYPE: 8, 234 ODOT: 8, 235 OXDOT: 8, 236 OMETHVALUE: 8, 237 OMETHEXPR: 8, 238 OPLUS: 7, 239 ONOT: 7, 240 OBITNOT: 7, 241 ONEG: 7, 242 OADDR: 7, 243 ODEREF: 7, 244 ORECV: 7, 245 OMUL: 6, 246 ODIV: 6, 247 OMOD: 6, 248 OLSH: 6, 249 ORSH: 6, 250 OAND: 6, 251 OANDNOT: 6, 252 OADD: 5, 253 OSUB: 5, 254 OOR: 5, 255 OXOR: 5, 256 OEQ: 4, 257 OLT: 4, 258 OLE: 4, 259 OGE: 4, 260 OGT: 4, 261 ONE: 4, 262 OSEND: 3, 263 OANDAND: 2, 264 OOROR: 1, 265 266 // Statements handled by stmtfmt 267 OAS: -1, 268 OAS2: -1, 269 OAS2DOTTYPE: -1, 270 OAS2FUNC: -1, 271 OAS2MAPR: -1, 272 OAS2RECV: -1, 273 OASOP: -1, 274 OBLOCK: -1, 275 OBREAK: -1, 276 OCASE: -1, 277 OCONTINUE: -1, 278 ODCL: -1, 279 ODEFER: -1, 280 OFALL: -1, 281 OFOR: -1, 282 OGOTO: -1, 283 OIF: -1, 284 OLABEL: -1, 285 OGO: -1, 286 ORANGE: -1, 287 ORETURN: -1, 288 OSELECT: -1, 289 OSWITCH: -1, 290 291 OEND: 0, 292 } 293 294 // StmtWithInit reports whether op is a statement with an explicit init list. 295 func StmtWithInit(op Op) bool { 296 switch op { 297 case OIF, OFOR, OSWITCH: 298 return true 299 } 300 return false 301 } 302 303 func stmtFmt(n Node, s fmt.State) { 304 // NOTE(rsc): This code used to support the text-based 305 // which was more aggressive about printing full Go syntax 306 // (for example, an actual loop instead of "for loop"). 307 // The code is preserved for now in case we want to expand 308 // any of those shortenings later. Or maybe we will delete 309 // the code. But for now, keep it. 310 const exportFormat = false 311 312 // some statements allow for an init, but at most one, 313 // but we may have an arbitrary number added, eg by typecheck 314 // and inlining. If it doesn't fit the syntax, emit an enclosing 315 // block starting with the init statements. 316 317 // if we can just say "for" n->ninit; ... then do so 318 simpleinit := len(n.Init()) == 1 && len(n.Init()[0].Init()) == 0 && StmtWithInit(n.Op()) 319 320 // otherwise, print the inits as separate statements 321 complexinit := len(n.Init()) != 0 && !simpleinit && exportFormat 322 323 // but if it was for if/for/switch, put in an extra surrounding block to limit the scope 324 extrablock := complexinit && StmtWithInit(n.Op()) 325 326 if extrablock { 327 fmt.Fprint(s, "{") 328 } 329 330 if complexinit { 331 fmt.Fprintf(s, " %v; ", n.Init()) 332 } 333 334 switch n.Op() { 335 case ODCL: 336 n := n.(*Decl) 337 fmt.Fprintf(s, "var %v %v", n.X.Sym(), n.X.Type()) 338 339 // Don't export "v = <N>" initializing statements, hope they're always 340 // preceded by the DCL which will be re-parsed and typechecked to reproduce 341 // the "v = <N>" again. 342 case OAS: 343 n := n.(*AssignStmt) 344 if n.Def && !complexinit { 345 fmt.Fprintf(s, "%v := %v", n.X, n.Y) 346 } else { 347 fmt.Fprintf(s, "%v = %v", n.X, n.Y) 348 } 349 350 case OASOP: 351 n := n.(*AssignOpStmt) 352 if n.IncDec { 353 if n.AsOp == OADD { 354 fmt.Fprintf(s, "%v++", n.X) 355 } else { 356 fmt.Fprintf(s, "%v--", n.X) 357 } 358 break 359 } 360 361 fmt.Fprintf(s, "%v %v= %v", n.X, n.AsOp, n.Y) 362 363 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: 364 n := n.(*AssignListStmt) 365 if n.Def && !complexinit { 366 fmt.Fprintf(s, "%.v := %.v", n.Lhs, n.Rhs) 367 } else { 368 fmt.Fprintf(s, "%.v = %.v", n.Lhs, n.Rhs) 369 } 370 371 case OBLOCK: 372 n := n.(*BlockStmt) 373 if len(n.List) != 0 { 374 fmt.Fprintf(s, "%v", n.List) 375 } 376 377 case ORETURN: 378 n := n.(*ReturnStmt) 379 fmt.Fprintf(s, "return %.v", n.Results) 380 381 case OTAILCALL: 382 n := n.(*TailCallStmt) 383 fmt.Fprintf(s, "tailcall %v", n.Call) 384 385 case OINLMARK: 386 n := n.(*InlineMarkStmt) 387 fmt.Fprintf(s, "inlmark %d", n.Index) 388 389 case OGO: 390 n := n.(*GoDeferStmt) 391 fmt.Fprintf(s, "go %v", n.Call) 392 393 case ODEFER: 394 n := n.(*GoDeferStmt) 395 fmt.Fprintf(s, "defer %v", n.Call) 396 397 case OIF: 398 n := n.(*IfStmt) 399 if simpleinit { 400 fmt.Fprintf(s, "if %v; %v { %v }", n.Init()[0], n.Cond, n.Body) 401 } else { 402 fmt.Fprintf(s, "if %v { %v }", n.Cond, n.Body) 403 } 404 if len(n.Else) != 0 { 405 fmt.Fprintf(s, " else { %v }", n.Else) 406 } 407 408 case OFOR: 409 n := n.(*ForStmt) 410 if !exportFormat { // TODO maybe only if FmtShort, same below 411 fmt.Fprintf(s, "for loop") 412 break 413 } 414 415 fmt.Fprint(s, "for") 416 if n.DistinctVars { 417 fmt.Fprint(s, " /* distinct */") 418 } 419 if simpleinit { 420 fmt.Fprintf(s, " %v;", n.Init()[0]) 421 } else if n.Post != nil { 422 fmt.Fprint(s, " ;") 423 } 424 425 if n.Cond != nil { 426 fmt.Fprintf(s, " %v", n.Cond) 427 } 428 429 if n.Post != nil { 430 fmt.Fprintf(s, "; %v", n.Post) 431 } else if simpleinit { 432 fmt.Fprint(s, ";") 433 } 434 435 fmt.Fprintf(s, " { %v }", n.Body) 436 437 case ORANGE: 438 n := n.(*RangeStmt) 439 if !exportFormat { 440 fmt.Fprint(s, "for loop") 441 break 442 } 443 444 fmt.Fprint(s, "for") 445 if n.Key != nil { 446 fmt.Fprintf(s, " %v", n.Key) 447 if n.Value != nil { 448 fmt.Fprintf(s, ", %v", n.Value) 449 } 450 fmt.Fprint(s, " =") 451 } 452 fmt.Fprintf(s, " range %v { %v }", n.X, n.Body) 453 if n.DistinctVars { 454 fmt.Fprint(s, " /* distinct vars */") 455 } 456 457 case OSELECT: 458 n := n.(*SelectStmt) 459 if !exportFormat { 460 fmt.Fprintf(s, "%v statement", n.Op()) 461 break 462 } 463 fmt.Fprintf(s, "select { %v }", n.Cases) 464 465 case OSWITCH: 466 n := n.(*SwitchStmt) 467 if !exportFormat { 468 fmt.Fprintf(s, "%v statement", n.Op()) 469 break 470 } 471 fmt.Fprintf(s, "switch") 472 if simpleinit { 473 fmt.Fprintf(s, " %v;", n.Init()[0]) 474 } 475 if n.Tag != nil { 476 fmt.Fprintf(s, " %v ", n.Tag) 477 } 478 fmt.Fprintf(s, " { %v }", n.Cases) 479 480 case OCASE: 481 n := n.(*CaseClause) 482 if len(n.List) != 0 { 483 fmt.Fprintf(s, "case %.v", n.List) 484 } else { 485 fmt.Fprint(s, "default") 486 } 487 fmt.Fprintf(s, ": %v", n.Body) 488 489 case OBREAK, OCONTINUE, OGOTO, OFALL: 490 n := n.(*BranchStmt) 491 if n.Label != nil { 492 fmt.Fprintf(s, "%v %v", n.Op(), n.Label) 493 } else { 494 fmt.Fprintf(s, "%v", n.Op()) 495 } 496 497 case OLABEL: 498 n := n.(*LabelStmt) 499 fmt.Fprintf(s, "%v: ", n.Label) 500 } 501 502 if extrablock { 503 fmt.Fprint(s, "}") 504 } 505 } 506 507 func exprFmt(n Node, s fmt.State, prec int) { 508 // NOTE(rsc): This code used to support the text-based 509 // which was more aggressive about printing full Go syntax 510 // (for example, an actual loop instead of "for loop"). 511 // The code is preserved for now in case we want to expand 512 // any of those shortenings later. Or maybe we will delete 513 // the code. But for now, keep it. 514 const exportFormat = false 515 516 for { 517 if n == nil { 518 fmt.Fprint(s, "<nil>") 519 return 520 } 521 522 // Skip implicit operations introduced during typechecking. 523 switch nn := n; nn.Op() { 524 case OADDR: 525 nn := nn.(*AddrExpr) 526 if nn.Implicit() { 527 n = nn.X 528 continue 529 } 530 case ODEREF: 531 nn := nn.(*StarExpr) 532 if nn.Implicit() { 533 n = nn.X 534 continue 535 } 536 case OCONV, OCONVNOP, OCONVIFACE: 537 nn := nn.(*ConvExpr) 538 if nn.Implicit() { 539 n = nn.X 540 continue 541 } 542 } 543 544 break 545 } 546 547 nprec := OpPrec[n.Op()] 548 if n.Op() == OTYPE && n.Type() != nil && n.Type().IsPtr() { 549 nprec = OpPrec[ODEREF] 550 } 551 552 if prec > nprec { 553 fmt.Fprintf(s, "(%v)", n) 554 return 555 } 556 557 switch n.Op() { 558 case OPAREN: 559 n := n.(*ParenExpr) 560 fmt.Fprintf(s, "(%v)", n.X) 561 562 case ONIL: 563 fmt.Fprint(s, "nil") 564 565 case OLITERAL: 566 if n.Sym() != nil { 567 fmt.Fprint(s, n.Sym()) 568 return 569 } 570 571 typ := n.Type() 572 val := n.Val() 573 574 // Special case for rune constants. 575 if typ == types.RuneType || typ == types.UntypedRune { 576 if x, ok := constant.Uint64Val(val); ok && x <= utf8.MaxRune { 577 fmt.Fprintf(s, "%q", x) 578 return 579 } 580 } 581 582 // Only include typ if it's neither the default nor untyped type 583 // for the constant value. 584 if k := val.Kind(); typ == types.Types[types.DefaultKinds[k]] || typ == types.UntypedTypes[k] { 585 fmt.Fprint(s, val) 586 } else { 587 fmt.Fprintf(s, "%v(%v)", typ, val) 588 } 589 590 case ODCLFUNC: 591 n := n.(*Func) 592 if sym := n.Sym(); sym != nil { 593 fmt.Fprint(s, sym) 594 return 595 } 596 fmt.Fprintf(s, "<unnamed Func>") 597 598 case ONAME: 599 n := n.(*Name) 600 // Special case: name used as local variable in export. 601 // _ becomes ~b%d internally; print as _ for export 602 if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' { 603 fmt.Fprint(s, "_") 604 return 605 } 606 fallthrough 607 case ONONAME: 608 fmt.Fprint(s, n.Sym()) 609 610 case OLINKSYMOFFSET: 611 n := n.(*LinksymOffsetExpr) 612 fmt.Fprintf(s, "(%v)(%s@%d)", n.Type(), n.Linksym.Name, n.Offset_) 613 614 case OTYPE: 615 if n.Type() == nil && n.Sym() != nil { 616 fmt.Fprint(s, n.Sym()) 617 return 618 } 619 fmt.Fprintf(s, "%v", n.Type()) 620 621 case OCLOSURE: 622 n := n.(*ClosureExpr) 623 if !exportFormat { 624 fmt.Fprint(s, "func literal") 625 return 626 } 627 fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func.Body) 628 629 case OPTRLIT: 630 n := n.(*AddrExpr) 631 fmt.Fprintf(s, "&%v", n.X) 632 633 case OCOMPLIT, OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT: 634 n := n.(*CompLitExpr) 635 if n.Implicit() { 636 fmt.Fprintf(s, "... argument") 637 return 638 } 639 fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(len(n.List) != 0)) 640 641 case OKEY: 642 n := n.(*KeyExpr) 643 if n.Key != nil && n.Value != nil { 644 fmt.Fprintf(s, "%v:%v", n.Key, n.Value) 645 return 646 } 647 648 if n.Key == nil && n.Value != nil { 649 fmt.Fprintf(s, ":%v", n.Value) 650 return 651 } 652 if n.Key != nil && n.Value == nil { 653 fmt.Fprintf(s, "%v:", n.Key) 654 return 655 } 656 fmt.Fprint(s, ":") 657 658 case OSTRUCTKEY: 659 n := n.(*StructKeyExpr) 660 fmt.Fprintf(s, "%v:%v", n.Field, n.Value) 661 662 case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OMETHVALUE, OMETHEXPR: 663 n := n.(*SelectorExpr) 664 exprFmt(n.X, s, nprec) 665 if n.Sel == nil { 666 fmt.Fprint(s, ".<nil>") 667 return 668 } 669 fmt.Fprintf(s, ".%s", n.Sel.Name) 670 671 case ODOTTYPE, ODOTTYPE2: 672 n := n.(*TypeAssertExpr) 673 exprFmt(n.X, s, nprec) 674 fmt.Fprintf(s, ".(%v)", n.Type()) 675 676 case OINDEX, OINDEXMAP: 677 n := n.(*IndexExpr) 678 exprFmt(n.X, s, nprec) 679 fmt.Fprintf(s, "[%v]", n.Index) 680 681 case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: 682 n := n.(*SliceExpr) 683 exprFmt(n.X, s, nprec) 684 fmt.Fprint(s, "[") 685 if n.Low != nil { 686 fmt.Fprint(s, n.Low) 687 } 688 fmt.Fprint(s, ":") 689 if n.High != nil { 690 fmt.Fprint(s, n.High) 691 } 692 if n.Op().IsSlice3() { 693 fmt.Fprint(s, ":") 694 if n.Max != nil { 695 fmt.Fprint(s, n.Max) 696 } 697 } 698 fmt.Fprint(s, "]") 699 700 case OSLICEHEADER: 701 n := n.(*SliceHeaderExpr) 702 fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.Len, n.Cap) 703 704 case OCOMPLEX, OCOPY, OUNSAFEADD, OUNSAFESLICE: 705 n := n.(*BinaryExpr) 706 fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.X, n.Y) 707 708 case OCONV, 709 OCONVIFACE, 710 OCONVNOP, 711 OBYTES2STR, 712 ORUNES2STR, 713 OSTR2BYTES, 714 OSTR2RUNES, 715 ORUNESTR, 716 OSLICE2ARR, 717 OSLICE2ARRPTR: 718 n := n.(*ConvExpr) 719 if n.Type() == nil || n.Type().Sym() == nil { 720 fmt.Fprintf(s, "(%v)", n.Type()) 721 } else { 722 fmt.Fprintf(s, "%v", n.Type()) 723 } 724 fmt.Fprintf(s, "(%v)", n.X) 725 726 case OREAL, 727 OIMAG, 728 OCAP, 729 OCLEAR, 730 OCLOSE, 731 OLEN, 732 ONEW, 733 OPANIC: 734 n := n.(*UnaryExpr) 735 fmt.Fprintf(s, "%v(%v)", n.Op(), n.X) 736 737 case OAPPEND, 738 ODELETE, 739 OMAKE, 740 OMAX, 741 OMIN, 742 ORECOVER, 743 OPRINT, 744 OPRINTLN: 745 n := n.(*CallExpr) 746 if n.IsDDD { 747 fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.Args) 748 return 749 } 750 fmt.Fprintf(s, "%v(%.v)", n.Op(), n.Args) 751 752 case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG: 753 n := n.(*CallExpr) 754 exprFmt(n.Fun, s, nprec) 755 if n.IsDDD { 756 fmt.Fprintf(s, "(%.v...)", n.Args) 757 return 758 } 759 fmt.Fprintf(s, "(%.v)", n.Args) 760 761 case OINLCALL: 762 n := n.(*InlinedCallExpr) 763 // TODO(mdempsky): Print Init and/or Body? 764 if len(n.ReturnVars) == 1 { 765 fmt.Fprintf(s, "%v", n.ReturnVars[0]) 766 return 767 } 768 fmt.Fprintf(s, "(.%v)", n.ReturnVars) 769 770 case OMAKEMAP, OMAKECHAN, OMAKESLICE: 771 n := n.(*MakeExpr) 772 if n.Cap != nil { 773 fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Len, n.Cap) 774 return 775 } 776 if n.Len != nil && (n.Op() == OMAKESLICE || !n.Len.Type().IsUntyped()) { 777 fmt.Fprintf(s, "make(%v, %v)", n.Type(), n.Len) 778 return 779 } 780 fmt.Fprintf(s, "make(%v)", n.Type()) 781 782 case OMAKESLICECOPY: 783 n := n.(*MakeExpr) 784 fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Len, n.Cap) 785 786 case OPLUS, ONEG, OBITNOT, ONOT, ORECV: 787 // Unary 788 n := n.(*UnaryExpr) 789 fmt.Fprintf(s, "%v", n.Op()) 790 if n.X != nil && n.X.Op() == n.Op() { 791 fmt.Fprint(s, " ") 792 } 793 exprFmt(n.X, s, nprec+1) 794 795 case OADDR: 796 n := n.(*AddrExpr) 797 fmt.Fprintf(s, "%v", n.Op()) 798 if n.X != nil && n.X.Op() == n.Op() { 799 fmt.Fprint(s, " ") 800 } 801 exprFmt(n.X, s, nprec+1) 802 803 case ODEREF: 804 n := n.(*StarExpr) 805 fmt.Fprintf(s, "%v", n.Op()) 806 exprFmt(n.X, s, nprec+1) 807 808 // Binary 809 case OADD, 810 OAND, 811 OANDNOT, 812 ODIV, 813 OEQ, 814 OGE, 815 OGT, 816 OLE, 817 OLT, 818 OLSH, 819 OMOD, 820 OMUL, 821 ONE, 822 OOR, 823 ORSH, 824 OSUB, 825 OXOR: 826 n := n.(*BinaryExpr) 827 exprFmt(n.X, s, nprec) 828 fmt.Fprintf(s, " %v ", n.Op()) 829 exprFmt(n.Y, s, nprec+1) 830 831 case OANDAND, 832 OOROR: 833 n := n.(*LogicalExpr) 834 exprFmt(n.X, s, nprec) 835 fmt.Fprintf(s, " %v ", n.Op()) 836 exprFmt(n.Y, s, nprec+1) 837 838 case OSEND: 839 n := n.(*SendStmt) 840 exprFmt(n.Chan, s, nprec) 841 fmt.Fprintf(s, " <- ") 842 exprFmt(n.Value, s, nprec+1) 843 844 case OADDSTR: 845 n := n.(*AddStringExpr) 846 for i, n1 := range n.List { 847 if i != 0 { 848 fmt.Fprint(s, " + ") 849 } 850 exprFmt(n1, s, nprec) 851 } 852 default: 853 fmt.Fprintf(s, "<node %v>", n.Op()) 854 } 855 } 856 857 func ellipsisIf(b bool) string { 858 if b { 859 return "..." 860 } 861 return "" 862 } 863 864 // Nodes 865 866 // Format implements formatting for a Nodes. 867 // The valid formats are: 868 // 869 // %v Go syntax, semicolon-separated 870 // %.v Go syntax, comma-separated 871 // %+v Debug syntax, as in DumpList. 872 func (l Nodes) Format(s fmt.State, verb rune) { 873 if s.Flag('+') && verb == 'v' { 874 // %+v is DumpList output 875 dumpNodes(s, l, 1) 876 return 877 } 878 879 if verb != 'v' { 880 fmt.Fprintf(s, "%%!%c(Nodes)", verb) 881 return 882 } 883 884 sep := "; " 885 if _, ok := s.Precision(); ok { // %.v is expr list 886 sep = ", " 887 } 888 889 for i, n := range l { 890 fmt.Fprint(s, n) 891 if i+1 < len(l) { 892 fmt.Fprint(s, sep) 893 } 894 } 895 } 896 897 // Dump 898 899 // Dump prints the message s followed by a debug dump of n. 900 func Dump(s string, n Node) { 901 fmt.Printf("%s%+v\n", s, n) 902 } 903 904 // DumpList prints the message s followed by a debug dump of each node in the list. 905 func DumpList(s string, list Nodes) { 906 var buf bytes.Buffer 907 FDumpList(&buf, s, list) 908 os.Stdout.Write(buf.Bytes()) 909 } 910 911 // FDumpList prints to w the message s followed by a debug dump of each node in the list. 912 func FDumpList(w io.Writer, s string, list Nodes) { 913 io.WriteString(w, s) 914 dumpNodes(w, list, 1) 915 io.WriteString(w, "\n") 916 } 917 918 // indent prints indentation to w. 919 func indent(w io.Writer, depth int) { 920 fmt.Fprint(w, "\n") 921 for i := 0; i < depth; i++ { 922 fmt.Fprint(w, ". ") 923 } 924 } 925 926 // EscFmt is set by the escape analysis code to add escape analysis details to the node print. 927 var EscFmt func(n Node) string 928 929 // dumpNodeHeader prints the debug-format node header line to w. 930 func dumpNodeHeader(w io.Writer, n Node) { 931 // Useful to see which nodes in an AST printout are actually identical 932 if base.Debug.DumpPtrs != 0 { 933 fmt.Fprintf(w, " p(%p)", n) 934 } 935 936 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil { 937 // Useful to see where Defn is set and what node it points to 938 fmt.Fprintf(w, " defn(%p)", n.Name().Defn) 939 } 940 941 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Curfn != nil { 942 // Useful to see where Defn is set and what node it points to 943 fmt.Fprintf(w, " curfn(%p)", n.Name().Curfn) 944 } 945 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Outer != nil { 946 // Useful to see where Defn is set and what node it points to 947 fmt.Fprintf(w, " outer(%p)", n.Name().Outer) 948 } 949 950 if EscFmt != nil { 951 if esc := EscFmt(n); esc != "" { 952 fmt.Fprintf(w, " %s", esc) 953 } 954 } 955 956 if n.Sym() != nil && n.Op() != ONAME && n.Op() != ONONAME && n.Op() != OTYPE { 957 fmt.Fprintf(w, " %+v", n.Sym()) 958 } 959 960 // Print Node-specific fields of basic type in header line. 961 v := reflect.ValueOf(n).Elem() 962 t := v.Type() 963 nf := t.NumField() 964 for i := 0; i < nf; i++ { 965 tf := t.Field(i) 966 if tf.PkgPath != "" { 967 // skip unexported field - Interface will fail 968 continue 969 } 970 k := tf.Type.Kind() 971 if reflect.Bool <= k && k <= reflect.Complex128 { 972 name := strings.TrimSuffix(tf.Name, "_") 973 vf := v.Field(i) 974 vfi := vf.Interface() 975 if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && vf.IsZero() { 976 continue 977 } 978 if vfi == true { 979 fmt.Fprintf(w, " %s", name) 980 } else { 981 fmt.Fprintf(w, " %s:%+v", name, vf.Interface()) 982 } 983 } 984 } 985 986 // Print Node-specific booleans by looking for methods. 987 // Different v, t from above - want *Struct not Struct, for methods. 988 v = reflect.ValueOf(n) 989 t = v.Type() 990 nm := t.NumMethod() 991 for i := 0; i < nm; i++ { 992 tm := t.Method(i) 993 if tm.PkgPath != "" { 994 // skip unexported method - call will fail 995 continue 996 } 997 m := v.Method(i) 998 mt := m.Type() 999 if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool { 1000 // TODO(rsc): Remove the func/defer/recover wrapping, 1001 // which is guarding against panics in miniExpr, 1002 // once we get down to the simpler state in which 1003 // nodes have no getter methods that aren't allowed to be called. 1004 func() { 1005 defer func() { recover() }() 1006 if m.Call(nil)[0].Bool() { 1007 name := strings.TrimSuffix(tm.Name, "_") 1008 fmt.Fprintf(w, " %s", name) 1009 } 1010 }() 1011 } 1012 } 1013 1014 if n.Op() == OCLOSURE { 1015 n := n.(*ClosureExpr) 1016 if fn := n.Func; fn != nil && fn.Nname.Sym() != nil { 1017 fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym()) 1018 } 1019 } 1020 1021 if n.Type() != nil { 1022 if n.Op() == OTYPE { 1023 fmt.Fprintf(w, " type") 1024 } 1025 fmt.Fprintf(w, " %+v", n.Type()) 1026 } 1027 if n.Typecheck() != 0 { 1028 fmt.Fprintf(w, " tc(%d)", n.Typecheck()) 1029 } 1030 1031 if n.Pos().IsKnown() { 1032 fmt.Fprint(w, " # ") 1033 switch n.Pos().IsStmt() { 1034 case src.PosNotStmt: 1035 fmt.Fprint(w, "_") // "-" would be confusing 1036 case src.PosIsStmt: 1037 fmt.Fprint(w, "+") 1038 } 1039 sep := "" 1040 base.Ctxt.AllPos(n.Pos(), func(pos src.Pos) { 1041 fmt.Fprint(w, sep) 1042 sep = " " 1043 // TODO(mdempsky): Print line pragma details too. 1044 file := filepath.Base(pos.Filename()) 1045 // Note: this output will be parsed by ssa/html.go:(*HTMLWriter).WriteAST. Keep in sync. 1046 fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col()) 1047 }) 1048 } 1049 } 1050 1051 func dumpNode(w io.Writer, n Node, depth int) { 1052 indent(w, depth) 1053 if depth > 40 { 1054 fmt.Fprint(w, "...") 1055 return 1056 } 1057 1058 if n == nil { 1059 fmt.Fprint(w, "NilIrNode") 1060 return 1061 } 1062 1063 if len(n.Init()) != 0 { 1064 fmt.Fprintf(w, "%+v-init", n.Op()) 1065 dumpNodes(w, n.Init(), depth+1) 1066 indent(w, depth) 1067 } 1068 1069 switch n.Op() { 1070 default: 1071 fmt.Fprintf(w, "%+v", n.Op()) 1072 dumpNodeHeader(w, n) 1073 1074 case OLITERAL: 1075 fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val()) 1076 dumpNodeHeader(w, n) 1077 return 1078 1079 case ONAME, ONONAME: 1080 if n.Sym() != nil { 1081 fmt.Fprintf(w, "%+v-%+v", n.Op(), n.Sym()) 1082 } else { 1083 fmt.Fprintf(w, "%+v", n.Op()) 1084 } 1085 dumpNodeHeader(w, n) 1086 return 1087 1088 case OLINKSYMOFFSET: 1089 n := n.(*LinksymOffsetExpr) 1090 fmt.Fprintf(w, "%+v-%v", n.Op(), n.Linksym) 1091 // Offset is almost always 0, so only print when it's interesting. 1092 if n.Offset_ != 0 { 1093 fmt.Fprintf(w, "%+v", n.Offset_) 1094 } 1095 dumpNodeHeader(w, n) 1096 1097 case OASOP: 1098 n := n.(*AssignOpStmt) 1099 fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp) 1100 dumpNodeHeader(w, n) 1101 1102 case OTYPE: 1103 fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym()) 1104 dumpNodeHeader(w, n) 1105 return 1106 1107 case OCLOSURE: 1108 fmt.Fprintf(w, "%+v", n.Op()) 1109 dumpNodeHeader(w, n) 1110 1111 case ODCLFUNC: 1112 // Func has many fields we don't want to print. 1113 // Bypass reflection and just print what we want. 1114 n := n.(*Func) 1115 fmt.Fprintf(w, "%+v", n.Op()) 1116 dumpNodeHeader(w, n) 1117 fn := n 1118 if len(fn.Dcl) > 0 { 1119 indent(w, depth) 1120 fmt.Fprintf(w, "%+v-Dcl", n.Op()) 1121 for _, dcl := range n.Dcl { 1122 dumpNode(w, dcl, depth+1) 1123 } 1124 } 1125 if len(fn.ClosureVars) > 0 { 1126 indent(w, depth) 1127 fmt.Fprintf(w, "%+v-ClosureVars", n.Op()) 1128 for _, cv := range fn.ClosureVars { 1129 dumpNode(w, cv, depth+1) 1130 } 1131 } 1132 if len(fn.Body) > 0 { 1133 indent(w, depth) 1134 fmt.Fprintf(w, "%+v-body", n.Op()) 1135 dumpNodes(w, fn.Body, depth+1) 1136 } 1137 return 1138 } 1139 1140 v := reflect.ValueOf(n).Elem() 1141 t := reflect.TypeOf(n).Elem() 1142 nf := t.NumField() 1143 for i := 0; i < nf; i++ { 1144 tf := t.Field(i) 1145 vf := v.Field(i) 1146 if tf.PkgPath != "" { 1147 // skip unexported field - Interface will fail 1148 continue 1149 } 1150 switch tf.Type.Kind() { 1151 case reflect.Interface, reflect.Ptr, reflect.Slice: 1152 if vf.IsNil() { 1153 continue 1154 } 1155 } 1156 name := strings.TrimSuffix(tf.Name, "_") 1157 // Do not bother with field name header lines for the 1158 // most common positional arguments: unary, binary expr, 1159 // index expr, send stmt, go and defer call expression. 1160 switch name { 1161 case "X", "Y", "Index", "Chan", "Value", "Call": 1162 name = "" 1163 } 1164 switch val := vf.Interface().(type) { 1165 case Node: 1166 if name != "" { 1167 indent(w, depth) 1168 fmt.Fprintf(w, "%+v-%s", n.Op(), name) 1169 } 1170 dumpNode(w, val, depth+1) 1171 case Nodes: 1172 if len(val) == 0 { 1173 continue 1174 } 1175 if name != "" { 1176 indent(w, depth) 1177 fmt.Fprintf(w, "%+v-%s", n.Op(), name) 1178 } 1179 dumpNodes(w, val, depth+1) 1180 default: 1181 if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) { 1182 if vf.Len() == 0 { 1183 continue 1184 } 1185 if name != "" { 1186 indent(w, depth) 1187 fmt.Fprintf(w, "%+v-%s", n.Op(), name) 1188 } 1189 for i, n := 0, vf.Len(); i < n; i++ { 1190 dumpNode(w, vf.Index(i).Interface().(Node), depth+1) 1191 } 1192 } 1193 } 1194 } 1195 } 1196 1197 var nodeType = reflect.TypeOf((*Node)(nil)).Elem() 1198 1199 func dumpNodes(w io.Writer, list Nodes, depth int) { 1200 if len(list) == 0 { 1201 fmt.Fprintf(w, " <nil>") 1202 return 1203 } 1204 1205 for _, n := range list { 1206 dumpNode(w, n, depth) 1207 } 1208 }