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