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