github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/compile/internal/gc/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 gc 6 7 import ( 8 "bytes" 9 "cmd/internal/obj" 10 "fmt" 11 "strconv" 12 "strings" 13 "unicode/utf8" 14 ) 15 16 // A FmtFlag value is a set of flags (or 0). 17 // They control how the Xconv functions format their values. 18 // See the respective function's documentation for details. 19 type FmtFlag int 20 21 const ( 22 FmtWidth FmtFlag = 1 << iota 23 FmtLeft // "-" 24 FmtSharp // "#" 25 FmtSign // "+" 26 FmtUnsigned // "u" 27 FmtShort // "h" 28 FmtLong // "l" 29 FmtComma // "," 30 FmtByte // "hh" 31 FmtBody // for printing export bodies 32 ) 33 34 // 35 // Format conversions 36 // %L int Line numbers 37 // 38 // %E int etype values (aka 'Kind') 39 // 40 // %O int Node Opcodes 41 // Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg) 42 // 43 // %J Node* Node details 44 // Flags: "%hJ" suppresses things not relevant until walk. 45 // 46 // %V Val* Constant values 47 // 48 // %S Sym* Symbols 49 // Flags: +,- #: mode (see below) 50 // "%hS" unqualified identifier in any mode 51 // "%hhS" in export mode: unqualified identifier if exported, qualified if not 52 // 53 // %T Type* Types 54 // Flags: +,- #: mode (see below) 55 // 'l' definition instead of name. 56 // 'h' omit "func" and receiver in function types 57 // 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix. 58 // 59 // %N Node* Nodes 60 // Flags: +,- #: mode (see below) 61 // 'h' (only in +/debug mode) suppress recursion 62 // 'l' (only in Error mode) print "foo (type Bar)" 63 // 64 // %H Nodes Nodes 65 // Flags: those of %N 66 // ',' separate items with ',' instead of ';' 67 // 68 // In mparith2.go and mparith3.go: 69 // %B Mpint* Big integers 70 // %F Mpflt* Big floats 71 // 72 // %S, %T and %N obey use the following flags to set the format mode: 73 const ( 74 FErr = iota 75 FDbg 76 FExp 77 FTypeId 78 ) 79 80 var fmtmode int = FErr 81 82 var fmtpkgpfx int // %uT stickyness 83 84 var fmtbody bool 85 86 // 87 // E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode. 88 // 89 // The mode flags +, - and # are sticky, meaning they persist through 90 // recursions of %N, %T and %S, but not the h and l flags. The u flag is 91 // sticky only on %T recursions and only used in %-/Sym mode. 92 93 // 94 // Useful format combinations: 95 // 96 // %+N %+H multiline recursive debug dump of node/nodelist 97 // %+hN %+hH non recursive debug dump 98 // 99 // %#N %#T export format 100 // %#lT type definition instead of name 101 // %#hT omit"func" and receiver in function signature 102 // 103 // %lN "foo (type Bar)" for error messages 104 // 105 // %-T type identifiers 106 // %-hT type identifiers without "func" and arg names in type signatures (methodsym) 107 // %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash) 108 // 109 110 func setfmode(flags *FmtFlag) (fm int, fb bool) { 111 fm = fmtmode 112 fb = fmtbody 113 if *flags&FmtSign != 0 { 114 fmtmode = FDbg 115 } else if *flags&FmtSharp != 0 { 116 fmtmode = FExp 117 } else if *flags&FmtLeft != 0 { 118 fmtmode = FTypeId 119 } 120 121 if *flags&FmtBody != 0 { 122 fmtbody = true 123 } 124 125 *flags &^= (FmtSharp | FmtLeft | FmtSign | FmtBody) 126 return 127 } 128 129 // Fmt "%L": Linenumbers 130 131 var goopnames = []string{ 132 OADDR: "&", 133 OADD: "+", 134 OADDSTR: "+", 135 OANDAND: "&&", 136 OANDNOT: "&^", 137 OAND: "&", 138 OAPPEND: "append", 139 OAS: "=", 140 OAS2: "=", 141 OBREAK: "break", 142 OCALL: "function call", // not actual syntax 143 OCAP: "cap", 144 OCASE: "case", 145 OCLOSE: "close", 146 OCOMPLEX: "complex", 147 OCOM: "^", 148 OCONTINUE: "continue", 149 OCOPY: "copy", 150 ODEC: "--", 151 ODELETE: "delete", 152 ODEFER: "defer", 153 ODIV: "/", 154 OEQ: "==", 155 OFALL: "fallthrough", 156 OFOR: "for", 157 OGE: ">=", 158 OGOTO: "goto", 159 OGT: ">", 160 OIF: "if", 161 OIMAG: "imag", 162 OINC: "++", 163 OIND: "*", 164 OLEN: "len", 165 OLE: "<=", 166 OLSH: "<<", 167 OLT: "<", 168 OMAKE: "make", 169 OMINUS: "-", 170 OMOD: "%", 171 OMUL: "*", 172 ONEW: "new", 173 ONE: "!=", 174 ONOT: "!", 175 OOROR: "||", 176 OOR: "|", 177 OPANIC: "panic", 178 OPLUS: "+", 179 OPRINTN: "println", 180 OPRINT: "print", 181 ORANGE: "range", 182 OREAL: "real", 183 ORECV: "<-", 184 ORECOVER: "recover", 185 ORETURN: "return", 186 ORSH: ">>", 187 OSELECT: "select", 188 OSEND: "<-", 189 OSUB: "-", 190 OSWITCH: "switch", 191 OXOR: "^", 192 OXFALL: "fallthrough", 193 } 194 195 func (o Op) String() string { 196 return oconv(o, 0) 197 } 198 199 func (o Op) GoString() string { 200 return oconv(o, FmtSharp) 201 } 202 203 func oconv(o Op, flag FmtFlag) string { 204 if (flag&FmtSharp != 0) || fmtmode != FDbg { 205 if o >= 0 && int(o) < len(goopnames) && goopnames[o] != "" { 206 return goopnames[o] 207 } 208 } 209 210 if o >= 0 && int(o) < len(opnames) && opnames[o] != "" { 211 return opnames[o] 212 } 213 214 return fmt.Sprintf("O-%d", o) 215 } 216 217 var classnames = []string{ 218 "Pxxx", 219 "PEXTERN", 220 "PAUTO", 221 "PAUTOHEAP", 222 "PPARAM", 223 "PPARAMOUT", 224 "PFUNC", 225 } 226 227 // Fmt "%J": Node details. 228 func jconv(n *Node, flag FmtFlag) string { 229 var buf bytes.Buffer 230 231 c := flag & FmtShort 232 233 if c == 0 && n.Ullman != 0 { 234 fmt.Fprintf(&buf, " u(%d)", n.Ullman) 235 } 236 237 if c == 0 && n.Addable { 238 fmt.Fprintf(&buf, " a(%v)", n.Addable) 239 } 240 241 if c == 0 && n.Name != nil && n.Name.Vargen != 0 { 242 fmt.Fprintf(&buf, " g(%d)", n.Name.Vargen) 243 } 244 245 if n.Lineno != 0 { 246 fmt.Fprintf(&buf, " l(%d)", n.Lineno) 247 } 248 249 if c == 0 && n.Xoffset != BADWIDTH { 250 fmt.Fprintf(&buf, " x(%d%+d)", n.Xoffset, stkdelta[n]) 251 } 252 253 if n.Class != 0 { 254 if int(n.Class) < len(classnames) { 255 fmt.Fprintf(&buf, " class(%s)", classnames[n.Class]) 256 } else { 257 fmt.Fprintf(&buf, " class(%d?)", n.Class) 258 } 259 } 260 261 if n.Colas { 262 fmt.Fprintf(&buf, " colas(%v)", n.Colas) 263 } 264 265 if n.Name != nil && n.Name.Funcdepth != 0 { 266 fmt.Fprintf(&buf, " f(%d)", n.Name.Funcdepth) 267 } 268 if n.Func != nil && n.Func.Depth != 0 { 269 fmt.Fprintf(&buf, " ff(%d)", n.Func.Depth) 270 } 271 272 switch n.Esc { 273 case EscUnknown: 274 break 275 276 case EscHeap: 277 buf.WriteString(" esc(h)") 278 279 case EscScope: 280 buf.WriteString(" esc(s)") 281 282 case EscNone: 283 buf.WriteString(" esc(no)") 284 285 case EscNever: 286 if c == 0 { 287 buf.WriteString(" esc(N)") 288 } 289 290 default: 291 fmt.Fprintf(&buf, " esc(%d)", n.Esc) 292 } 293 294 if e, ok := n.Opt().(*NodeEscState); ok && e.Escloopdepth != 0 { 295 fmt.Fprintf(&buf, " ld(%d)", e.Escloopdepth) 296 } 297 298 if c == 0 && n.Typecheck != 0 { 299 fmt.Fprintf(&buf, " tc(%d)", n.Typecheck) 300 } 301 302 if c == 0 && n.Dodata != 0 { 303 fmt.Fprintf(&buf, " dd(%d)", n.Dodata) 304 } 305 306 if n.Isddd { 307 fmt.Fprintf(&buf, " isddd(%v)", n.Isddd) 308 } 309 310 if n.Implicit { 311 fmt.Fprintf(&buf, " implicit(%v)", n.Implicit) 312 } 313 314 if n.Embedded != 0 { 315 fmt.Fprintf(&buf, " embedded(%d)", n.Embedded) 316 } 317 318 if n.Addrtaken { 319 buf.WriteString(" addrtaken") 320 } 321 322 if n.Assigned { 323 buf.WriteString(" assigned") 324 } 325 if n.Bounded { 326 buf.WriteString(" bounded") 327 } 328 if n.NonNil { 329 buf.WriteString(" nonnil") 330 } 331 332 if c == 0 && n.Used { 333 fmt.Fprintf(&buf, " used(%v)", n.Used) 334 } 335 return buf.String() 336 } 337 338 // Fmt "%V": Values 339 func vconv(v Val, flag FmtFlag) string { 340 switch u := v.U.(type) { 341 case *Mpint: 342 if !u.Rune { 343 if (flag&FmtSharp != 0) || fmtmode == FExp { 344 return bconv(u, FmtSharp) 345 } 346 return bconv(u, 0) 347 } 348 349 x := u.Int64() 350 if ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'' { 351 return fmt.Sprintf("'%c'", int(x)) 352 } 353 if 0 <= x && x < 1<<16 { 354 return fmt.Sprintf("'\\u%04x'", uint(int(x))) 355 } 356 if 0 <= x && x <= utf8.MaxRune { 357 return fmt.Sprintf("'\\U%08x'", uint64(x)) 358 } 359 return fmt.Sprintf("('\\x00' + %v)", u) 360 361 case *Mpflt: 362 if (flag&FmtSharp != 0) || fmtmode == FExp { 363 return fconv(u, 0) 364 } 365 return fconv(u, FmtSharp) 366 367 case *Mpcplx: 368 if (flag&FmtSharp != 0) || fmtmode == FExp { 369 return fmt.Sprintf("(%v+%vi)", &u.Real, &u.Imag) 370 } 371 if v.U.(*Mpcplx).Real.CmpFloat64(0) == 0 { 372 return fmt.Sprintf("%vi", fconv(&u.Imag, FmtSharp)) 373 } 374 if v.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 { 375 return fconv(&u.Real, FmtSharp) 376 } 377 if v.U.(*Mpcplx).Imag.CmpFloat64(0) < 0 { 378 return fmt.Sprintf("(%v%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp)) 379 } 380 return fmt.Sprintf("(%v+%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp)) 381 382 case string: 383 return strconv.Quote(u) 384 385 case bool: 386 if u { 387 return "true" 388 } 389 return "false" 390 391 case *NilVal: 392 return "nil" 393 } 394 395 return fmt.Sprintf("<ctype=%d>", v.Ctype()) 396 } 397 398 /* 399 s%,%,\n%g 400 s%\n+%\n%g 401 s%^[ ]*T%%g 402 s%,.*%%g 403 s%.+% [T&] = "&",%g 404 s%^ ........*\]%&~%g 405 s%~ %%g 406 */ 407 var etnames = []string{ 408 Txxx: "Txxx", 409 TINT: "INT", 410 TUINT: "UINT", 411 TINT8: "INT8", 412 TUINT8: "UINT8", 413 TINT16: "INT16", 414 TUINT16: "UINT16", 415 TINT32: "INT32", 416 TUINT32: "UINT32", 417 TINT64: "INT64", 418 TUINT64: "UINT64", 419 TUINTPTR: "UINTPTR", 420 TFLOAT32: "FLOAT32", 421 TFLOAT64: "FLOAT64", 422 TCOMPLEX64: "COMPLEX64", 423 TCOMPLEX128: "COMPLEX128", 424 TBOOL: "BOOL", 425 TPTR32: "PTR32", 426 TPTR64: "PTR64", 427 TFUNC: "FUNC", 428 TARRAY: "ARRAY", 429 TSLICE: "SLICE", 430 TSTRUCT: "STRUCT", 431 TCHAN: "CHAN", 432 TMAP: "MAP", 433 TINTER: "INTER", 434 TFORW: "FORW", 435 TSTRING: "STRING", 436 TUNSAFEPTR: "TUNSAFEPTR", 437 TANY: "ANY", 438 TIDEAL: "TIDEAL", 439 TNIL: "TNIL", 440 TBLANK: "TBLANK", 441 TFUNCARGS: "TFUNCARGS", 442 TCHANARGS: "TCHANARGS", 443 TINTERMETH: "TINTERMETH", 444 TDDDFIELD: "TDDDFIELD", 445 } 446 447 func (et EType) String() string { 448 if int(et) < len(etnames) && etnames[et] != "" { 449 return etnames[et] 450 } 451 return fmt.Sprintf("E-%d", et) 452 } 453 454 // Fmt "%S": syms 455 func symfmt(s *Sym, flag FmtFlag) string { 456 if s.Pkg != nil && flag&FmtShort == 0 { 457 switch fmtmode { 458 case FErr: // This is for the user 459 if s.Pkg == builtinpkg || s.Pkg == localpkg { 460 return s.Name 461 } 462 463 // If the name was used by multiple packages, display the full path, 464 if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 { 465 return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name) 466 } 467 return s.Pkg.Name + "." + s.Name 468 469 case FDbg: 470 return s.Pkg.Name + "." + s.Name 471 472 case FTypeId: 473 if flag&FmtUnsigned != 0 { 474 return s.Pkg.Name + "." + s.Name // dcommontype, typehash 475 } 476 return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym 477 478 case FExp: 479 if s.Name != "" && s.Name[0] == '.' { 480 Fatalf("exporting synthetic symbol %s", s.Name) 481 } 482 if s.Pkg != builtinpkg { 483 return fmt.Sprintf("@%q.%s", s.Pkg.Path, s.Name) 484 } 485 } 486 } 487 488 if flag&FmtByte != 0 { 489 // FmtByte (hh) implies FmtShort (h) 490 // skip leading "type." in method name 491 p := s.Name 492 if i := strings.LastIndex(s.Name, "."); i >= 0 { 493 p = s.Name[i+1:] 494 } 495 496 // exportname needs to see the name without the prefix too. 497 if (fmtmode == FExp && !exportname(p)) || fmtmode == FDbg { 498 return fmt.Sprintf("@%q.%s", s.Pkg.Path, p) 499 } 500 501 return p 502 } 503 504 return s.Name 505 } 506 507 var basicnames = []string{ 508 TINT: "int", 509 TUINT: "uint", 510 TINT8: "int8", 511 TUINT8: "uint8", 512 TINT16: "int16", 513 TUINT16: "uint16", 514 TINT32: "int32", 515 TUINT32: "uint32", 516 TINT64: "int64", 517 TUINT64: "uint64", 518 TUINTPTR: "uintptr", 519 TFLOAT32: "float32", 520 TFLOAT64: "float64", 521 TCOMPLEX64: "complex64", 522 TCOMPLEX128: "complex128", 523 TBOOL: "bool", 524 TANY: "any", 525 TSTRING: "string", 526 TNIL: "nil", 527 TIDEAL: "untyped number", 528 TBLANK: "blank", 529 } 530 531 func typefmt(t *Type, flag FmtFlag) string { 532 if t == nil { 533 return "<T>" 534 } 535 536 if t == bytetype || t == runetype { 537 // in %-T mode collapse rune and byte with their originals. 538 if fmtmode != FTypeId { 539 return sconv(t.Sym, FmtShort) 540 } 541 t = Types[t.Etype] 542 } 543 544 if t == errortype { 545 return "error" 546 } 547 548 // Unless the 'l' flag was specified, if the type has a name, just print that name. 549 if flag&FmtLong == 0 && t.Sym != nil && t != Types[t.Etype] { 550 switch fmtmode { 551 case FTypeId: 552 if flag&FmtShort != 0 { 553 if t.Vargen != 0 { 554 return fmt.Sprintf("%v·%d", sconv(t.Sym, FmtShort), t.Vargen) 555 } 556 return sconv(t.Sym, FmtShort) 557 } 558 559 if flag&FmtUnsigned != 0 { 560 return sconv(t.Sym, FmtUnsigned) 561 } 562 fallthrough 563 564 case FExp: 565 if t.Sym.Pkg == localpkg && t.Vargen != 0 { 566 return fmt.Sprintf("%v·%d", t.Sym, t.Vargen) 567 } 568 } 569 570 return sconv(t.Sym, 0) 571 } 572 573 if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" { 574 prefix := "" 575 if fmtmode == FErr && (t == idealbool || t == idealstring) { 576 prefix = "untyped " 577 } 578 return prefix + basicnames[t.Etype] 579 } 580 581 if fmtmode == FDbg { 582 fmtmode = 0 583 str := t.Etype.String() + "-" + typefmt(t, flag) 584 fmtmode = FDbg 585 return str 586 } 587 588 switch t.Etype { 589 case TPTR32, TPTR64: 590 if fmtmode == FTypeId && (flag&FmtShort != 0) { 591 return "*" + Tconv(t.Elem(), FmtShort) 592 } 593 return "*" + t.Elem().String() 594 595 case TARRAY: 596 if t.isDDDArray() { 597 return "[...]" + t.Elem().String() 598 } 599 return fmt.Sprintf("[%d]%v", t.NumElem(), t.Elem()) 600 601 case TSLICE: 602 return "[]" + t.Elem().String() 603 604 case TCHAN: 605 switch t.ChanDir() { 606 case Crecv: 607 return "<-chan " + t.Elem().String() 608 609 case Csend: 610 return "chan<- " + t.Elem().String() 611 } 612 613 if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == Crecv { 614 return "chan (" + t.Elem().String() + ")" 615 } 616 return "chan " + t.Elem().String() 617 618 case TMAP: 619 return "map[" + t.Key().String() + "]" + t.Val().String() 620 621 case TINTER: 622 var buf bytes.Buffer 623 buf.WriteString("interface {") 624 for i, f := range t.Fields().Slice() { 625 if i != 0 { 626 buf.WriteString(";") 627 } 628 buf.WriteString(" ") 629 switch { 630 case f.Sym == nil: 631 // Check first that a symbol is defined for this type. 632 // Wrong interface definitions may have types lacking a symbol. 633 break 634 case exportname(f.Sym.Name): 635 buf.WriteString(sconv(f.Sym, FmtShort)) 636 default: 637 buf.WriteString(sconv(f.Sym, FmtUnsigned)) 638 } 639 buf.WriteString(Tconv(f.Type, FmtShort)) 640 } 641 if t.NumFields() != 0 { 642 buf.WriteString(" ") 643 } 644 buf.WriteString("}") 645 return buf.String() 646 647 case TFUNC: 648 var buf bytes.Buffer 649 if flag&FmtShort != 0 { 650 // no leading func 651 } else { 652 if t.Recv() != nil { 653 buf.WriteString("method") 654 buf.WriteString(Tconv(t.Recvs(), 0)) 655 buf.WriteString(" ") 656 } 657 buf.WriteString("func") 658 } 659 buf.WriteString(Tconv(t.Params(), 0)) 660 661 switch t.Results().NumFields() { 662 case 0: 663 break 664 665 case 1: 666 if fmtmode != FExp { 667 buf.WriteString(" ") 668 buf.WriteString(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type 669 break 670 } 671 fallthrough 672 673 default: 674 buf.WriteString(" ") 675 buf.WriteString(Tconv(t.Results(), 0)) 676 } 677 return buf.String() 678 679 case TSTRUCT: 680 if m := t.StructType().Map; m != nil { 681 mt := m.MapType() 682 // Format the bucket struct for map[x]y as map.bucket[x]y. 683 // This avoids a recursive print that generates very long names. 684 if mt.Bucket == t { 685 return "map.bucket[" + m.Key().String() + "]" + m.Val().String() 686 } 687 688 if mt.Hmap == t { 689 return "map.hdr[" + m.Key().String() + "]" + m.Val().String() 690 } 691 692 if mt.Hiter == t { 693 return "map.iter[" + m.Key().String() + "]" + m.Val().String() 694 } 695 696 Yyerror("unknown internal map type") 697 } 698 699 var buf bytes.Buffer 700 if t.IsFuncArgStruct() { 701 buf.WriteString("(") 702 var flag1 FmtFlag 703 if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags 704 flag1 = FmtShort 705 } 706 for i, f := range t.Fields().Slice() { 707 if i != 0 { 708 buf.WriteString(", ") 709 } 710 buf.WriteString(Fldconv(f, flag1)) 711 } 712 buf.WriteString(")") 713 } else { 714 buf.WriteString("struct {") 715 for i, f := range t.Fields().Slice() { 716 if i != 0 { 717 buf.WriteString(";") 718 } 719 buf.WriteString(" ") 720 buf.WriteString(Fldconv(f, FmtLong)) 721 } 722 if t.NumFields() != 0 { 723 buf.WriteString(" ") 724 } 725 buf.WriteString("}") 726 } 727 return buf.String() 728 729 case TFORW: 730 if t.Sym != nil { 731 return "undefined " + t.Sym.String() 732 } 733 return "undefined" 734 735 case TUNSAFEPTR: 736 if fmtmode == FExp { 737 return "@\"unsafe\".Pointer" 738 } 739 return "unsafe.Pointer" 740 741 case TDDDFIELD: 742 if fmtmode == FExp { 743 Fatalf("cannot use TDDDFIELD with old exporter") 744 } 745 return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField()) 746 747 case Txxx: 748 return "Txxx" 749 } 750 751 if fmtmode == FExp { 752 Fatalf("missing %v case during export", t.Etype) 753 } 754 755 // Don't know how to handle - fall back to detailed prints. 756 return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem()) 757 } 758 759 // Statements which may be rendered with a simplestmt as init. 760 func stmtwithinit(op Op) bool { 761 switch op { 762 case OIF, OFOR, OSWITCH: 763 return true 764 } 765 766 return false 767 } 768 769 func stmtfmt(n *Node) string { 770 var f string 771 772 // some statements allow for an init, but at most one, 773 // but we may have an arbitrary number added, eg by typecheck 774 // and inlining. If it doesn't fit the syntax, emit an enclosing 775 // block starting with the init statements. 776 777 // if we can just say "for" n->ninit; ... then do so 778 simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && stmtwithinit(n.Op) 779 780 // otherwise, print the inits as separate statements 781 complexinit := n.Ninit.Len() != 0 && !simpleinit && (fmtmode != FErr) 782 783 // but if it was for if/for/switch, put in an extra surrounding block to limit the scope 784 extrablock := complexinit && stmtwithinit(n.Op) 785 786 if extrablock { 787 f += "{" 788 } 789 790 if complexinit { 791 f += fmt.Sprintf(" %v; ", n.Ninit) 792 } 793 794 switch n.Op { 795 case ODCL: 796 if fmtmode == FExp { 797 switch n.Left.Class { 798 case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP: 799 f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type) 800 goto ret 801 } 802 } 803 804 f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type) 805 806 case ODCLFIELD: 807 if n.Left != nil { 808 f += fmt.Sprintf("%v %v", n.Left, n.Right) 809 } else { 810 f += Nconv(n.Right, 0) 811 } 812 813 // Don't export "v = <N>" initializing statements, hope they're always 814 // preceded by the DCL which will be re-parsed and typechecked to reproduce 815 // the "v = <N>" again. 816 case OAS, OASWB: 817 if fmtmode == FExp && n.Right == nil { 818 break 819 } 820 821 if n.Colas && !complexinit { 822 f += fmt.Sprintf("%v := %v", n.Left, n.Right) 823 } else { 824 f += fmt.Sprintf("%v = %v", n.Left, n.Right) 825 } 826 827 case OASOP: 828 if n.Implicit { 829 if Op(n.Etype) == OADD { 830 f += fmt.Sprintf("%v++", n.Left) 831 } else { 832 f += fmt.Sprintf("%v--", n.Left) 833 } 834 break 835 } 836 837 f += fmt.Sprintf("%v %#v= %v", n.Left, Op(n.Etype), n.Right) 838 839 case OAS2: 840 if n.Colas && !complexinit { 841 f += fmt.Sprintf("%v := %v", hconv(n.List, FmtComma), hconv(n.Rlist, FmtComma)) 842 break 843 } 844 fallthrough 845 846 case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: 847 f += fmt.Sprintf("%v = %v", hconv(n.List, FmtComma), hconv(n.Rlist, FmtComma)) 848 849 case ORETURN: 850 f += fmt.Sprintf("return %v", hconv(n.List, FmtComma)) 851 852 case ORETJMP: 853 f += fmt.Sprintf("retjmp %v", n.Sym) 854 855 case OPROC: 856 f += fmt.Sprintf("go %v", n.Left) 857 858 case ODEFER: 859 f += fmt.Sprintf("defer %v", n.Left) 860 861 case OIF: 862 if simpleinit { 863 f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody) 864 } else { 865 f += fmt.Sprintf("if %v { %v }", n.Left, n.Nbody) 866 } 867 if n.Rlist.Len() != 0 { 868 f += fmt.Sprintf(" else { %v }", n.Rlist) 869 } 870 871 case OFOR: 872 if fmtmode == FErr { // TODO maybe only if FmtShort, same below 873 f += "for loop" 874 break 875 } 876 877 f += "for" 878 if simpleinit { 879 f += fmt.Sprintf(" %v;", n.Ninit.First()) 880 } else if n.Right != nil { 881 f += " ;" 882 } 883 884 if n.Left != nil { 885 f += fmt.Sprintf(" %v", n.Left) 886 } 887 888 if n.Right != nil { 889 f += fmt.Sprintf("; %v", n.Right) 890 } else if simpleinit { 891 f += ";" 892 } 893 894 f += fmt.Sprintf(" { %v }", n.Nbody) 895 896 case ORANGE: 897 if fmtmode == FErr { 898 f += "for loop" 899 break 900 } 901 902 if n.List.Len() == 0 { 903 f += fmt.Sprintf("for range %v { %v }", n.Right, n.Nbody) 904 break 905 } 906 907 f += fmt.Sprintf("for %v = range %v { %v }", hconv(n.List, FmtComma), n.Right, n.Nbody) 908 909 case OSELECT, OSWITCH: 910 if fmtmode == FErr { 911 f += fmt.Sprintf("%v statement", n.Op) 912 break 913 } 914 915 f += n.Op.GoString() // %#v 916 if simpleinit { 917 f += fmt.Sprintf(" %v;", n.Ninit.First()) 918 } 919 if n.Left != nil { 920 f += fmt.Sprintf(" %s ", Nconv(n.Left, 0)) 921 } 922 923 f += fmt.Sprintf(" { %v }", n.List) 924 925 case OCASE, OXCASE: 926 if n.List.Len() != 0 { 927 f += fmt.Sprintf("case %v: %v", hconv(n.List, FmtComma), n.Nbody) 928 } else { 929 f += fmt.Sprintf("default: %v", n.Nbody) 930 } 931 932 case OBREAK, 933 OCONTINUE, 934 OGOTO, 935 OFALL, 936 OXFALL: 937 if n.Left != nil { 938 f += fmt.Sprintf("%#v %v", n.Op, n.Left) 939 } else { 940 f += n.Op.GoString() // %#v 941 } 942 943 case OEMPTY: 944 break 945 946 case OLABEL: 947 f += fmt.Sprintf("%v: ", n.Left) 948 } 949 950 ret: 951 if extrablock { 952 f += "}" 953 } 954 955 return f 956 } 957 958 var opprec = []int{ 959 OAPPEND: 8, 960 OARRAYBYTESTR: 8, 961 OARRAYLIT: 8, 962 OARRAYRUNESTR: 8, 963 OCALLFUNC: 8, 964 OCALLINTER: 8, 965 OCALLMETH: 8, 966 OCALL: 8, 967 OCAP: 8, 968 OCLOSE: 8, 969 OCONVIFACE: 8, 970 OCONVNOP: 8, 971 OCONV: 8, 972 OCOPY: 8, 973 ODELETE: 8, 974 OGETG: 8, 975 OLEN: 8, 976 OLITERAL: 8, 977 OMAKESLICE: 8, 978 OMAKE: 8, 979 OMAPLIT: 8, 980 ONAME: 8, 981 ONEW: 8, 982 ONONAME: 8, 983 OPACK: 8, 984 OPANIC: 8, 985 OPAREN: 8, 986 OPRINTN: 8, 987 OPRINT: 8, 988 ORUNESTR: 8, 989 OSTRARRAYBYTE: 8, 990 OSTRARRAYRUNE: 8, 991 OSTRUCTLIT: 8, 992 OTARRAY: 8, 993 OTCHAN: 8, 994 OTFUNC: 8, 995 OTINTER: 8, 996 OTMAP: 8, 997 OTSTRUCT: 8, 998 OINDEXMAP: 8, 999 OINDEX: 8, 1000 OSLICE: 8, 1001 OSLICESTR: 8, 1002 OSLICEARR: 8, 1003 OSLICE3: 8, 1004 OSLICE3ARR: 8, 1005 ODOTINTER: 8, 1006 ODOTMETH: 8, 1007 ODOTPTR: 8, 1008 ODOTTYPE2: 8, 1009 ODOTTYPE: 8, 1010 ODOT: 8, 1011 OXDOT: 8, 1012 OCALLPART: 8, 1013 OPLUS: 7, 1014 ONOT: 7, 1015 OCOM: 7, 1016 OMINUS: 7, 1017 OADDR: 7, 1018 OIND: 7, 1019 ORECV: 7, 1020 OMUL: 6, 1021 ODIV: 6, 1022 OMOD: 6, 1023 OLSH: 6, 1024 ORSH: 6, 1025 OAND: 6, 1026 OANDNOT: 6, 1027 OADD: 5, 1028 OSUB: 5, 1029 OOR: 5, 1030 OXOR: 5, 1031 OEQ: 4, 1032 OLT: 4, 1033 OLE: 4, 1034 OGE: 4, 1035 OGT: 4, 1036 ONE: 4, 1037 OCMPSTR: 4, 1038 OCMPIFACE: 4, 1039 OSEND: 3, 1040 OANDAND: 2, 1041 OOROR: 1, 1042 // Statements handled by stmtfmt 1043 OAS: -1, 1044 OAS2: -1, 1045 OAS2DOTTYPE: -1, 1046 OAS2FUNC: -1, 1047 OAS2MAPR: -1, 1048 OAS2RECV: -1, 1049 OASOP: -1, 1050 OBREAK: -1, 1051 OCASE: -1, 1052 OCONTINUE: -1, 1053 ODCL: -1, 1054 ODCLFIELD: -1, 1055 ODEFER: -1, 1056 OEMPTY: -1, 1057 OFALL: -1, 1058 OFOR: -1, 1059 OGOTO: -1, 1060 OIF: -1, 1061 OLABEL: -1, 1062 OPROC: -1, 1063 ORANGE: -1, 1064 ORETURN: -1, 1065 OSELECT: -1, 1066 OSWITCH: -1, 1067 OXCASE: -1, 1068 OXFALL: -1, 1069 OEND: 0, 1070 } 1071 1072 func exprfmt(n *Node, prec int) string { 1073 for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) { 1074 n = n.Left 1075 } 1076 1077 if n == nil { 1078 return "<N>" 1079 } 1080 1081 nprec := opprec[n.Op] 1082 if n.Op == OTYPE && n.Sym != nil { 1083 nprec = 8 1084 } 1085 1086 if prec > nprec { 1087 return fmt.Sprintf("(%v)", n) 1088 } 1089 1090 switch n.Op { 1091 case OPAREN: 1092 return fmt.Sprintf("(%v)", n.Left) 1093 1094 case ODDDARG: 1095 return "... argument" 1096 1097 case OREGISTER: 1098 return obj.Rconv(int(n.Reg)) 1099 1100 case OLITERAL: // this is a bit of a mess 1101 if fmtmode == FErr { 1102 if n.Orig != nil && n.Orig != n { 1103 return exprfmt(n.Orig, prec) 1104 } 1105 if n.Sym != nil { 1106 return sconv(n.Sym, 0) 1107 } 1108 } 1109 if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n { 1110 return exprfmt(n.Orig, prec) 1111 } 1112 if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != idealbool && n.Type != idealstring { 1113 // Need parens when type begins with what might 1114 // be misinterpreted as a unary operator: * or <-. 1115 if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == Crecv) { 1116 return fmt.Sprintf("(%v)(%v)", n.Type, vconv(n.Val(), 0)) 1117 } else { 1118 return fmt.Sprintf("%v(%v)", n.Type, vconv(n.Val(), 0)) 1119 } 1120 } 1121 1122 return vconv(n.Val(), 0) 1123 1124 // Special case: name used as local variable in export. 1125 // _ becomes ~b%d internally; print as _ for export 1126 case ONAME: 1127 if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { 1128 return "_" 1129 } 1130 if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 { 1131 return fmt.Sprintf("%v·%d", n.Sym, n.Name.Vargen) 1132 } 1133 1134 // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, 1135 // but for export, this should be rendered as (*pkg.T).meth. 1136 // These nodes have the special property that they are names with a left OTYPE and a right ONAME. 1137 if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME { 1138 if n.Left.Type.IsPtr() { 1139 return fmt.Sprintf("(%v).%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte)) 1140 } else { 1141 return fmt.Sprintf("%v.%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte)) 1142 } 1143 } 1144 fallthrough 1145 1146 case OPACK, ONONAME: 1147 return sconv(n.Sym, 0) 1148 1149 case OTYPE: 1150 if n.Type == nil && n.Sym != nil { 1151 return sconv(n.Sym, 0) 1152 } 1153 return Tconv(n.Type, 0) 1154 1155 case OTARRAY: 1156 if n.Left != nil { 1157 return fmt.Sprintf("[]%v", n.Left) 1158 } 1159 return fmt.Sprintf("[]%v", n.Right) // happens before typecheck 1160 1161 case OTMAP: 1162 return fmt.Sprintf("map[%v]%v", n.Left, n.Right) 1163 1164 case OTCHAN: 1165 switch ChanDir(n.Etype) { 1166 case Crecv: 1167 return fmt.Sprintf("<-chan %v", n.Left) 1168 1169 case Csend: 1170 return fmt.Sprintf("chan<- %v", n.Left) 1171 1172 default: 1173 if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv { 1174 return fmt.Sprintf("chan (%v)", n.Left) 1175 } else { 1176 return fmt.Sprintf("chan %v", n.Left) 1177 } 1178 } 1179 1180 case OTSTRUCT: 1181 return "<struct>" 1182 1183 case OTINTER: 1184 return "<inter>" 1185 1186 case OTFUNC: 1187 return "<func>" 1188 1189 case OCLOSURE: 1190 if fmtmode == FErr { 1191 return "func literal" 1192 } 1193 if n.Nbody.Len() != 0 { 1194 return fmt.Sprintf("%v { %v }", n.Type, n.Nbody) 1195 } 1196 return fmt.Sprintf("%v { %v }", n.Type, n.Func.Closure.Nbody) 1197 1198 case OCOMPLIT: 1199 ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr() 1200 if fmtmode == FErr { 1201 if n.Right != nil && n.Right.Type != nil && !n.Implicit { 1202 if ptrlit { 1203 return fmt.Sprintf("&%v literal", n.Right.Type.Elem()) 1204 } else { 1205 return fmt.Sprintf("%v literal", n.Right.Type) 1206 } 1207 } 1208 1209 return "composite literal" 1210 } 1211 1212 if fmtmode == FExp && ptrlit { 1213 // typecheck has overwritten OIND by OTYPE with pointer type. 1214 return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Elem(), hconv(n.List, FmtComma)) 1215 } 1216 1217 return fmt.Sprintf("(%v{ %v })", n.Right, hconv(n.List, FmtComma)) 1218 1219 case OPTRLIT: 1220 if fmtmode == FExp && n.Left.Implicit { 1221 return Nconv(n.Left, 0) 1222 } 1223 return fmt.Sprintf("&%v", n.Left) 1224 1225 case OSTRUCTLIT: 1226 if fmtmode == FExp { // requires special handling of field names 1227 var f string 1228 if n.Implicit { 1229 f += "{" 1230 } else { 1231 f += fmt.Sprintf("(%v{", n.Type) 1232 } 1233 for i1, n1 := range n.List.Slice() { 1234 f += fmt.Sprintf(" %v:%v", sconv(n1.Left.Sym, FmtShort|FmtByte), n1.Right) 1235 1236 if i1+1 < n.List.Len() { 1237 f += "," 1238 } else { 1239 f += " " 1240 } 1241 } 1242 1243 if !n.Implicit { 1244 f += "})" 1245 return f 1246 } 1247 f += "}" 1248 return f 1249 } 1250 fallthrough 1251 1252 case OARRAYLIT, OMAPLIT: 1253 if fmtmode == FErr { 1254 return fmt.Sprintf("%v literal", n.Type) 1255 } 1256 if fmtmode == FExp && n.Implicit { 1257 return fmt.Sprintf("{ %v }", hconv(n.List, FmtComma)) 1258 } 1259 return fmt.Sprintf("(%v{ %v })", n.Type, hconv(n.List, FmtComma)) 1260 1261 case OKEY: 1262 if n.Left != nil && n.Right != nil { 1263 if fmtmode == FExp && n.Left.Type == structkey { 1264 // requires special handling of field names 1265 return fmt.Sprintf("%v:%v", sconv(n.Left.Sym, FmtShort|FmtByte), n.Right) 1266 } else { 1267 return fmt.Sprintf("%v:%v", n.Left, n.Right) 1268 } 1269 } 1270 1271 if n.Left == nil && n.Right != nil { 1272 return fmt.Sprintf(":%v", n.Right) 1273 } 1274 if n.Left != nil && n.Right == nil { 1275 return fmt.Sprintf("%v:", n.Left) 1276 } 1277 return ":" 1278 1279 case OCALLPART: 1280 var f string 1281 f += exprfmt(n.Left, nprec) 1282 if n.Right == nil || n.Right.Sym == nil { 1283 f += ".<nil>" 1284 return f 1285 } 1286 f += fmt.Sprintf(".%v", sconv(n.Right.Sym, FmtShort|FmtByte)) 1287 return f 1288 1289 case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: 1290 var f string 1291 f += exprfmt(n.Left, nprec) 1292 if n.Sym == nil { 1293 f += ".<nil>" 1294 return f 1295 } 1296 f += fmt.Sprintf(".%v", sconv(n.Sym, FmtShort|FmtByte)) 1297 return f 1298 1299 case ODOTTYPE, ODOTTYPE2: 1300 var f string 1301 f += exprfmt(n.Left, nprec) 1302 if n.Right != nil { 1303 f += fmt.Sprintf(".(%v)", n.Right) 1304 return f 1305 } 1306 f += fmt.Sprintf(".(%v)", n.Type) 1307 return f 1308 1309 case OINDEX, OINDEXMAP: 1310 return fmt.Sprintf("%s[%v]", exprfmt(n.Left, nprec), n.Right) 1311 1312 case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: 1313 var buf bytes.Buffer 1314 buf.WriteString(exprfmt(n.Left, nprec)) 1315 buf.WriteString("[") 1316 low, high, max := n.SliceBounds() 1317 if low != nil { 1318 buf.WriteString(low.String()) 1319 } 1320 buf.WriteString(":") 1321 if high != nil { 1322 buf.WriteString(high.String()) 1323 } 1324 if n.Op.IsSlice3() { 1325 buf.WriteString(":") 1326 if max != nil { 1327 buf.WriteString(max.String()) 1328 } 1329 } 1330 buf.WriteString("]") 1331 return buf.String() 1332 1333 case OCOPY, OCOMPLEX: 1334 return fmt.Sprintf("%#v(%v, %v)", n.Op, n.Left, n.Right) 1335 1336 case OCONV, 1337 OCONVIFACE, 1338 OCONVNOP, 1339 OARRAYBYTESTR, 1340 OARRAYRUNESTR, 1341 OSTRARRAYBYTE, 1342 OSTRARRAYRUNE, 1343 ORUNESTR: 1344 if n.Type == nil || n.Type.Sym == nil { 1345 return fmt.Sprintf("(%v)(%v)", n.Type, n.Left) 1346 } 1347 if n.Left != nil { 1348 return fmt.Sprintf("%v(%v)", n.Type, n.Left) 1349 } 1350 return fmt.Sprintf("%v(%v)", n.Type, hconv(n.List, FmtComma)) 1351 1352 case OREAL, 1353 OIMAG, 1354 OAPPEND, 1355 OCAP, 1356 OCLOSE, 1357 ODELETE, 1358 OLEN, 1359 OMAKE, 1360 ONEW, 1361 OPANIC, 1362 ORECOVER, 1363 OPRINT, 1364 OPRINTN: 1365 if n.Left != nil { 1366 return fmt.Sprintf("%#v(%v)", n.Op, n.Left) 1367 } 1368 if n.Isddd { 1369 return fmt.Sprintf("%#v(%v...)", n.Op, hconv(n.List, FmtComma)) 1370 } 1371 return fmt.Sprintf("%#v(%v)", n.Op, hconv(n.List, FmtComma)) 1372 1373 case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG: 1374 var f string 1375 f += exprfmt(n.Left, nprec) 1376 if n.Isddd { 1377 f += fmt.Sprintf("(%v...)", hconv(n.List, FmtComma)) 1378 return f 1379 } 1380 f += fmt.Sprintf("(%v)", hconv(n.List, FmtComma)) 1381 return f 1382 1383 case OMAKEMAP, OMAKECHAN, OMAKESLICE: 1384 if n.List.Len() != 0 { // pre-typecheck 1385 return fmt.Sprintf("make(%v, %v)", n.Type, hconv(n.List, FmtComma)) 1386 } 1387 if n.Right != nil { 1388 return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right) 1389 } 1390 if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) { 1391 return fmt.Sprintf("make(%v, %v)", n.Type, n.Left) 1392 } 1393 return fmt.Sprintf("make(%v)", n.Type) 1394 1395 // Unary 1396 case OPLUS, 1397 OMINUS, 1398 OADDR, 1399 OCOM, 1400 OIND, 1401 ONOT, 1402 ORECV: 1403 f := n.Op.GoString() // %#v 1404 if n.Left.Op == n.Op { 1405 f += " " 1406 } 1407 f += exprfmt(n.Left, nprec+1) 1408 return f 1409 1410 // Binary 1411 case OADD, 1412 OAND, 1413 OANDAND, 1414 OANDNOT, 1415 ODIV, 1416 OEQ, 1417 OGE, 1418 OGT, 1419 OLE, 1420 OLT, 1421 OLSH, 1422 OMOD, 1423 OMUL, 1424 ONE, 1425 OOR, 1426 OOROR, 1427 ORSH, 1428 OSEND, 1429 OSUB, 1430 OXOR: 1431 var f string 1432 f += exprfmt(n.Left, nprec) 1433 1434 f += fmt.Sprintf(" %#v ", n.Op) 1435 f += exprfmt(n.Right, nprec+1) 1436 return f 1437 1438 case OADDSTR: 1439 var f string 1440 i := 0 1441 for _, n1 := range n.List.Slice() { 1442 if i != 0 { 1443 f += " + " 1444 } 1445 f += exprfmt(n1, nprec) 1446 i++ 1447 } 1448 1449 return f 1450 1451 case OCMPSTR, OCMPIFACE: 1452 var f string 1453 f += exprfmt(n.Left, nprec) 1454 // TODO(marvin): Fix Node.EType type union. 1455 f += fmt.Sprintf(" %#v ", Op(n.Etype)) 1456 f += exprfmt(n.Right, nprec+1) 1457 return f 1458 1459 case ODCLCONST: 1460 // if exporting, DCLCONST should just be removed as its usage 1461 // has already been replaced with literals 1462 if fmtbody { 1463 return "" 1464 } 1465 } 1466 1467 return fmt.Sprintf("<node %v>", n.Op) 1468 } 1469 1470 func nodefmt(n *Node, flag FmtFlag) string { 1471 t := n.Type 1472 1473 // we almost always want the original, except in export mode for literals 1474 // this saves the importer some work, and avoids us having to redo some 1475 // special casing for package unsafe 1476 if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil { 1477 n = n.Orig 1478 } 1479 1480 if flag&FmtLong != 0 && t != nil { 1481 if t.Etype == TNIL { 1482 return "nil" 1483 } else { 1484 return fmt.Sprintf("%v (type %v)", n, t) 1485 } 1486 } 1487 1488 // TODO inlining produces expressions with ninits. we can't print these yet. 1489 1490 if opprec[n.Op] < 0 { 1491 return stmtfmt(n) 1492 } 1493 1494 return exprfmt(n, 0) 1495 } 1496 1497 var dumpdepth int 1498 1499 func indent(buf *bytes.Buffer) { 1500 buf.WriteString("\n") 1501 for i := 0; i < dumpdepth; i++ { 1502 buf.WriteString(". ") 1503 } 1504 } 1505 1506 func nodedump(n *Node, flag FmtFlag) string { 1507 if n == nil { 1508 return "" 1509 } 1510 1511 recur := flag&FmtShort == 0 1512 1513 var buf bytes.Buffer 1514 if recur { 1515 indent(&buf) 1516 if dumpdepth > 10 { 1517 buf.WriteString("...") 1518 return buf.String() 1519 } 1520 1521 if n.Ninit.Len() != 0 { 1522 fmt.Fprintf(&buf, "%v-init%v", n.Op, n.Ninit) 1523 indent(&buf) 1524 } 1525 } 1526 1527 switch n.Op { 1528 default: 1529 fmt.Fprintf(&buf, "%v%v", n.Op, jconv(n, 0)) 1530 1531 case OREGISTER, OINDREG: 1532 fmt.Fprintf(&buf, "%v-%v%v", n.Op, obj.Rconv(int(n.Reg)), jconv(n, 0)) 1533 1534 case OLITERAL: 1535 fmt.Fprintf(&buf, "%v-%v%v", n.Op, vconv(n.Val(), 0), jconv(n, 0)) 1536 1537 case ONAME, ONONAME: 1538 if n.Sym != nil { 1539 fmt.Fprintf(&buf, "%v-%v%v", n.Op, n.Sym, jconv(n, 0)) 1540 } else { 1541 fmt.Fprintf(&buf, "%v%v", n.Op, jconv(n, 0)) 1542 } 1543 if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil { 1544 indent(&buf) 1545 fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype) 1546 } 1547 1548 case OASOP: 1549 fmt.Fprintf(&buf, "%v-%v%v", n.Op, Op(n.Etype), jconv(n, 0)) 1550 1551 case OTYPE: 1552 fmt.Fprintf(&buf, "%v %v%v type=%v", n.Op, n.Sym, jconv(n, 0), n.Type) 1553 if recur && n.Type == nil && n.Name.Param.Ntype != nil { 1554 indent(&buf) 1555 fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype) 1556 } 1557 } 1558 1559 if n.Sym != nil && n.Op != ONAME { 1560 fmt.Fprintf(&buf, " %v", n.Sym) 1561 } 1562 1563 if n.Type != nil { 1564 fmt.Fprintf(&buf, " %v", n.Type) 1565 } 1566 1567 if recur { 1568 if n.Left != nil { 1569 buf.WriteString(Nconv(n.Left, 0)) 1570 } 1571 if n.Right != nil { 1572 buf.WriteString(Nconv(n.Right, 0)) 1573 } 1574 if n.List.Len() != 0 { 1575 indent(&buf) 1576 fmt.Fprintf(&buf, "%v-list%v", n.Op, n.List) 1577 } 1578 1579 if n.Rlist.Len() != 0 { 1580 indent(&buf) 1581 fmt.Fprintf(&buf, "%v-rlist%v", n.Op, n.Rlist) 1582 } 1583 1584 if n.Nbody.Len() != 0 { 1585 indent(&buf) 1586 fmt.Fprintf(&buf, "%v-body%v", n.Op, n.Nbody) 1587 } 1588 } 1589 1590 return buf.String() 1591 } 1592 1593 func (s *Sym) String() string { 1594 return sconv(s, 0) 1595 } 1596 1597 // Fmt "%S": syms 1598 // Flags: "%hS" suppresses qualifying with package 1599 func sconv(s *Sym, flag FmtFlag) string { 1600 if flag&FmtLong != 0 { 1601 panic("linksymfmt") 1602 } 1603 1604 if s == nil { 1605 return "<S>" 1606 } 1607 1608 if s.Name == "_" { 1609 return "_" 1610 } 1611 1612 sf := flag 1613 sm, sb := setfmode(&flag) 1614 str := symfmt(s, flag) 1615 flag = sf 1616 fmtmode = sm 1617 fmtbody = sb 1618 return str 1619 } 1620 1621 func (t *Type) String() string { 1622 return Tconv(t, 0) 1623 } 1624 1625 func Fldconv(f *Field, flag FmtFlag) string { 1626 if f == nil { 1627 return "<T>" 1628 } 1629 1630 sf := flag 1631 sm, sb := setfmode(&flag) 1632 1633 if fmtmode == FTypeId && (sf&FmtUnsigned != 0) { 1634 fmtpkgpfx++ 1635 } 1636 if fmtpkgpfx != 0 { 1637 flag |= FmtUnsigned 1638 } 1639 1640 var name string 1641 if flag&FmtShort == 0 { 1642 s := f.Sym 1643 1644 // Take the name from the original, lest we substituted it with ~r%d or ~b%d. 1645 // ~r%d is a (formerly) unnamed result. 1646 if (fmtmode == FErr || fmtmode == FExp) && f.Nname != nil { 1647 if f.Nname.Orig != nil { 1648 s = f.Nname.Orig.Sym 1649 if s != nil && s.Name[0] == '~' { 1650 if s.Name[1] == 'r' { // originally an unnamed result 1651 s = nil 1652 } else if s.Name[1] == 'b' { // originally the blank identifier _ 1653 s = Lookup("_") 1654 } 1655 } 1656 } else { 1657 s = nil 1658 } 1659 } 1660 1661 if s != nil && f.Embedded == 0 { 1662 if f.Funarg != FunargNone { 1663 name = Nconv(f.Nname, 0) 1664 } else if flag&FmtLong != 0 { 1665 name = sconv(s, FmtShort|FmtByte) // qualify non-exported names (used on structs, not on funarg) 1666 } else { 1667 name = sconv(s, 0) 1668 } 1669 } else if fmtmode == FExp { 1670 if f.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 { 1671 name = fmt.Sprintf("@%q.?", s.Pkg.Path) 1672 } else { 1673 name = "?" 1674 } 1675 } 1676 } 1677 1678 var typ string 1679 if f.Isddd { 1680 typ = "..." + Tconv(f.Type.Elem(), 0) 1681 } else { 1682 typ = Tconv(f.Type, 0) 1683 } 1684 1685 str := typ 1686 if name != "" { 1687 str = name + " " + typ 1688 } 1689 1690 // The fmtbody flag is intended to suppress escape analysis annotations 1691 // when printing a function type used in a function body. 1692 // (The escape analysis tags do not apply to func vars.) 1693 // But it must not suppress struct field tags. 1694 // See golang.org/issue/13777 and golang.org/issue/14331. 1695 if flag&FmtShort == 0 && (!fmtbody || f.Funarg == FunargNone) && f.Note != "" { 1696 str += " " + strconv.Quote(f.Note) 1697 } 1698 1699 if fmtmode == FTypeId && (sf&FmtUnsigned != 0) { 1700 fmtpkgpfx-- 1701 } 1702 1703 flag = sf 1704 fmtbody = sb 1705 fmtmode = sm 1706 return str 1707 } 1708 1709 // Fmt "%T": types. 1710 // Flags: 'l' print definition, not name 1711 // 'h' omit 'func' and receiver from function types, short type names 1712 // 'u' package name, not prefix (FTypeId mode, sticky) 1713 func Tconv(t *Type, flag FmtFlag) string { 1714 if t == nil { 1715 return "<T>" 1716 } 1717 1718 if t.Trecur > 4 { 1719 return "<...>" 1720 } 1721 1722 t.Trecur++ 1723 sf := flag 1724 sm, sb := setfmode(&flag) 1725 1726 if fmtmode == FTypeId && (sf&FmtUnsigned != 0) { 1727 fmtpkgpfx++ 1728 } 1729 if fmtpkgpfx != 0 { 1730 flag |= FmtUnsigned 1731 } 1732 1733 str := typefmt(t, flag) 1734 1735 if fmtmode == FTypeId && (sf&FmtUnsigned != 0) { 1736 fmtpkgpfx-- 1737 } 1738 1739 flag = sf 1740 fmtbody = sb 1741 fmtmode = sm 1742 t.Trecur-- 1743 return str 1744 } 1745 1746 func (n *Node) String() string { 1747 return Nconv(n, 0) 1748 } 1749 1750 // Fmt '%N': Nodes. 1751 // Flags: 'l' suffix with "(type %T)" where possible 1752 // '+h' in debug mode, don't recurse, no multiline output 1753 func Nconv(n *Node, flag FmtFlag) string { 1754 if n == nil { 1755 return "<N>" 1756 } 1757 sf := flag 1758 sm, sb := setfmode(&flag) 1759 1760 var str string 1761 switch fmtmode { 1762 case FErr, FExp: 1763 str = nodefmt(n, flag) 1764 1765 case FDbg: 1766 dumpdepth++ 1767 str = nodedump(n, flag) 1768 dumpdepth-- 1769 1770 default: 1771 Fatalf("unhandled %%N mode") 1772 } 1773 1774 flag = sf 1775 fmtbody = sb 1776 fmtmode = sm 1777 return str 1778 } 1779 1780 func (n Nodes) String() string { 1781 return hconv(n, 0) 1782 } 1783 1784 // Fmt '%H': Nodes. 1785 // Flags: all those of %N plus ',': separate with comma's instead of semicolons. 1786 func hconv(l Nodes, flag FmtFlag) string { 1787 if l.Len() == 0 && fmtmode == FDbg { 1788 return "<nil>" 1789 } 1790 1791 sf := flag 1792 sm, sb := setfmode(&flag) 1793 sep := "; " 1794 if fmtmode == FDbg { 1795 sep = "\n" 1796 } else if flag&FmtComma != 0 { 1797 sep = ", " 1798 } 1799 1800 var buf bytes.Buffer 1801 for i, n := range l.Slice() { 1802 buf.WriteString(Nconv(n, 0)) 1803 if i+1 < l.Len() { 1804 buf.WriteString(sep) 1805 } 1806 } 1807 1808 flag = sf 1809 fmtbody = sb 1810 fmtmode = sm 1811 return buf.String() 1812 } 1813 1814 func dumplist(s string, l Nodes) { 1815 fmt.Printf("%s%v\n", s, hconv(l, FmtSign)) 1816 } 1817 1818 func Dump(s string, n *Node) { 1819 fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, FmtSign)) 1820 }