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