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