github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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 mparith1.c: 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 int, flag int) string { 404 if et >= 0 && 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 Fatal("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(int(t.Etype), 0) + "-" + 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 if exportname(t1.Sym.Name) { 583 buf.WriteString(Sconv(t1.Sym, obj.FmtShort)) 584 } else { 585 buf.WriteString(Sconv(t1.Sym, obj.FmtUnsigned)) 586 } 587 buf.WriteString(Tconv(t1.Type, obj.FmtShort)) 588 if t1.Down != nil { 589 buf.WriteString(";") 590 } 591 } 592 if t.Type != nil { 593 buf.WriteString(" ") 594 } 595 buf.WriteString("}") 596 return buf.String() 597 598 case TFUNC: 599 var buf bytes.Buffer 600 if flag&obj.FmtShort != 0 { 601 // no leading func 602 } else { 603 if t.Thistuple != 0 { 604 buf.WriteString("method") 605 buf.WriteString(Tconv(getthisx(t), 0)) 606 buf.WriteString(" ") 607 } 608 buf.WriteString("func") 609 } 610 buf.WriteString(Tconv(getinargx(t), 0)) 611 612 switch t.Outtuple { 613 case 0: 614 break 615 616 case 1: 617 if fmtmode != FExp { 618 buf.WriteString(" ") 619 buf.WriteString(Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type 620 break 621 } 622 fallthrough 623 624 default: 625 buf.WriteString(" ") 626 buf.WriteString(Tconv(getoutargx(t), 0)) 627 } 628 return buf.String() 629 630 case TSTRUCT: 631 if t.Map != nil { 632 // Format the bucket struct for map[x]y as map.bucket[x]y. 633 // This avoids a recursive print that generates very long names. 634 if t.Map.Bucket == t { 635 return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type) 636 } 637 638 if t.Map.Hmap == t { 639 return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type) 640 } 641 642 if t.Map.Hiter == t { 643 return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type) 644 } 645 646 Yyerror("unknown internal map type") 647 } 648 649 var buf bytes.Buffer 650 if t.Funarg != 0 { 651 buf.WriteString("(") 652 if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags 653 for t1 := t.Type; t1 != nil; t1 = t1.Down { 654 buf.WriteString(Tconv(t1, obj.FmtShort)) 655 if t1.Down != nil { 656 buf.WriteString(", ") 657 } 658 } 659 } else { 660 for t1 := t.Type; t1 != nil; t1 = t1.Down { 661 buf.WriteString(Tconv(t1, 0)) 662 if t1.Down != nil { 663 buf.WriteString(", ") 664 } 665 } 666 } 667 buf.WriteString(")") 668 } else { 669 buf.WriteString("struct {") 670 for t1 := t.Type; t1 != nil; t1 = t1.Down { 671 buf.WriteString(" ") 672 buf.WriteString(Tconv(t1, obj.FmtLong)) 673 if t1.Down != nil { 674 buf.WriteString(";") 675 } 676 } 677 if t.Type != nil { 678 buf.WriteString(" ") 679 } 680 buf.WriteString("}") 681 } 682 return buf.String() 683 684 case TFIELD: 685 var name string 686 if flag&obj.FmtShort == 0 { 687 s := t.Sym 688 689 // Take the name from the original, lest we substituted it with ~r%d or ~b%d. 690 // ~r%d is a (formerly) unnamed result. 691 if (fmtmode == FErr || fmtmode == FExp) && t.Nname != nil { 692 if t.Nname.Orig != nil { 693 s = t.Nname.Orig.Sym 694 if s != nil && s.Name[0] == '~' { 695 if s.Name[1] == 'r' { // originally an unnamed result 696 s = nil 697 } else if s.Name[1] == 'b' { // originally the blank identifier _ 698 s = Lookup("_") 699 } 700 } 701 } else { 702 s = nil 703 } 704 } 705 706 if s != nil && t.Embedded == 0 { 707 if t.Funarg != 0 { 708 name = Nconv(t.Nname, 0) 709 } else if flag&obj.FmtLong != 0 { 710 name = Sconv(s, obj.FmtShort|obj.FmtByte) // qualify non-exported names (used on structs, not on funarg) 711 } else { 712 name = Sconv(s, 0) 713 } 714 } else if fmtmode == FExp { 715 // TODO(rsc) this breaks on the eliding of unused arguments in the backend 716 // when this is fixed, the special case in dcl.c checkarglist can go. 717 //if(t->funarg) 718 // fmtstrcpy(fp, "_ "); 719 //else 720 if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 { 721 name = fmt.Sprintf("@%q.?", s.Pkg.Path) 722 } else { 723 name = "?" 724 } 725 } 726 } 727 728 var typ string 729 if t.Isddd { 730 typ = "..." + Tconv(t.Type.Type, 0) 731 } else { 732 typ = Tconv(t.Type, 0) 733 } 734 735 str := typ 736 if name != "" { 737 str = name + " " + typ 738 } 739 if flag&obj.FmtShort == 0 && t.Note != nil { 740 str += " " + strconv.Quote(*t.Note) 741 } 742 return str 743 744 case TFORW: 745 if t.Sym != nil { 746 return fmt.Sprintf("undefined %v", t.Sym) 747 } 748 return "undefined" 749 750 case TUNSAFEPTR: 751 if fmtmode == FExp { 752 return "@\"unsafe\".Pointer" 753 } 754 return "unsafe.Pointer" 755 } 756 757 if fmtmode == FExp { 758 Fatal("missing %v case during export", Econv(int(t.Etype), 0)) 759 } 760 761 // Don't know how to handle - fall back to detailed prints. 762 return fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), t.Sym, t.Type) 763 } 764 765 // Statements which may be rendered with a simplestmt as init. 766 func stmtwithinit(op int) bool { 767 switch op { 768 case OIF, OFOR, OSWITCH: 769 return true 770 } 771 772 return false 773 } 774 775 func stmtfmt(n *Node) string { 776 var f string 777 778 // some statements allow for an init, but at most one, 779 // but we may have an arbitrary number added, eg by typecheck 780 // and inlining. If it doesn't fit the syntax, emit an enclosing 781 // block starting with the init statements. 782 783 // if we can just say "for" n->ninit; ... then do so 784 simpleinit := n.Ninit != nil && n.Ninit.Next == nil && n.Ninit.N.Ninit == nil && stmtwithinit(int(n.Op)) 785 786 // otherwise, print the inits as separate statements 787 complexinit := n.Ninit != nil && !simpleinit && (fmtmode != FErr) 788 789 // but if it was for if/for/switch, put in an extra surrounding block to limit the scope 790 extrablock := complexinit && stmtwithinit(int(n.Op)) 791 792 if extrablock { 793 f += "{" 794 } 795 796 if complexinit { 797 f += fmt.Sprintf(" %v; ", n.Ninit) 798 } 799 800 switch n.Op { 801 case ODCL: 802 if fmtmode == FExp { 803 switch n.Left.Class &^ PHEAP { 804 case PPARAM, PPARAMOUT, PAUTO: 805 f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type) 806 goto ret 807 } 808 } 809 810 f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type) 811 812 case ODCLFIELD: 813 if n.Left != nil { 814 f += fmt.Sprintf("%v %v", n.Left, n.Right) 815 } else { 816 f += Nconv(n.Right, 0) 817 } 818 819 // Don't export "v = <N>" initializing statements, hope they're always 820 // preceded by the DCL which will be re-parsed and typecheck to reproduce 821 // the "v = <N>" again. 822 case OAS, OASWB: 823 if fmtmode == FExp && n.Right == nil { 824 break 825 } 826 827 if n.Colas && !complexinit { 828 f += fmt.Sprintf("%v := %v", n.Left, n.Right) 829 } else { 830 f += fmt.Sprintf("%v = %v", n.Left, n.Right) 831 } 832 833 case OASOP: 834 if n.Implicit { 835 if n.Etype == OADD { 836 f += fmt.Sprintf("%v++", n.Left) 837 } else { 838 f += fmt.Sprintf("%v--", n.Left) 839 } 840 break 841 } 842 843 f += fmt.Sprintf("%v %v= %v", n.Left, Oconv(int(n.Etype), obj.FmtSharp), n.Right) 844 845 case OAS2: 846 if n.Colas && !complexinit { 847 f += fmt.Sprintf("%v := %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma)) 848 break 849 } 850 fallthrough 851 852 case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: 853 f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma)) 854 855 case ORETURN: 856 f += fmt.Sprintf("return %v", Hconv(n.List, obj.FmtComma)) 857 858 case ORETJMP: 859 f += fmt.Sprintf("retjmp %v", n.Sym) 860 861 case OPROC: 862 f += fmt.Sprintf("go %v", n.Left) 863 864 case ODEFER: 865 f += fmt.Sprintf("defer %v", n.Left) 866 867 case OIF: 868 if simpleinit { 869 f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.N, n.Left, n.Nbody) 870 } else { 871 f += fmt.Sprintf("if %v { %v }", n.Left, n.Nbody) 872 } 873 if n.Rlist != nil { 874 f += fmt.Sprintf(" else { %v }", n.Rlist) 875 } 876 877 case OFOR: 878 if fmtmode == FErr { // TODO maybe only if FmtShort, same below 879 f += "for loop" 880 break 881 } 882 883 f += "for" 884 if simpleinit { 885 f += fmt.Sprintf(" %v;", n.Ninit.N) 886 } else if n.Right != nil { 887 f += " ;" 888 } 889 890 if n.Left != nil { 891 f += fmt.Sprintf(" %v", n.Left) 892 } 893 894 if n.Right != nil { 895 f += fmt.Sprintf("; %v", n.Right) 896 } else if simpleinit { 897 f += ";" 898 } 899 900 f += fmt.Sprintf(" { %v }", n.Nbody) 901 902 case ORANGE: 903 if fmtmode == FErr { 904 f += "for loop" 905 break 906 } 907 908 if n.List == nil { 909 f += fmt.Sprintf("for range %v { %v }", n.Right, n.Nbody) 910 break 911 } 912 913 f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), n.Right, n.Nbody) 914 915 case OSELECT, OSWITCH: 916 if fmtmode == FErr { 917 f += fmt.Sprintf("%v statement", Oconv(int(n.Op), 0)) 918 break 919 } 920 921 f += Oconv(int(n.Op), obj.FmtSharp) 922 if simpleinit { 923 f += fmt.Sprintf(" %v;", n.Ninit.N) 924 } 925 if n.Left != nil { 926 f += Nconv(n.Left, 0) 927 } 928 929 f += fmt.Sprintf(" { %v }", n.List) 930 931 case OCASE, OXCASE: 932 if n.List != nil { 933 f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), n.Nbody) 934 } else { 935 f += fmt.Sprintf("default: %v", n.Nbody) 936 } 937 938 case OBREAK, 939 OCONTINUE, 940 OGOTO, 941 OFALL, 942 OXFALL: 943 if n.Left != nil { 944 f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), n.Left) 945 } else { 946 f += Oconv(int(n.Op), obj.FmtSharp) 947 } 948 949 case OEMPTY: 950 break 951 952 case OLABEL: 953 f += fmt.Sprintf("%v: ", n.Left) 954 } 955 956 ret: 957 if extrablock { 958 f += "}" 959 } 960 961 return f 962 } 963 964 var opprec = []int{ 965 OAPPEND: 8, 966 OARRAYBYTESTR: 8, 967 OARRAYLIT: 8, 968 OARRAYRUNESTR: 8, 969 OCALLFUNC: 8, 970 OCALLINTER: 8, 971 OCALLMETH: 8, 972 OCALL: 8, 973 OCAP: 8, 974 OCLOSE: 8, 975 OCONVIFACE: 8, 976 OCONVNOP: 8, 977 OCONV: 8, 978 OCOPY: 8, 979 ODELETE: 8, 980 OGETG: 8, 981 OLEN: 8, 982 OLITERAL: 8, 983 OMAKESLICE: 8, 984 OMAKE: 8, 985 OMAPLIT: 8, 986 ONAME: 8, 987 ONEW: 8, 988 ONONAME: 8, 989 OPACK: 8, 990 OPANIC: 8, 991 OPAREN: 8, 992 OPRINTN: 8, 993 OPRINT: 8, 994 ORUNESTR: 8, 995 OSTRARRAYBYTE: 8, 996 OSTRARRAYRUNE: 8, 997 OSTRUCTLIT: 8, 998 OTARRAY: 8, 999 OTCHAN: 8, 1000 OTFUNC: 8, 1001 OTINTER: 8, 1002 OTMAP: 8, 1003 OTSTRUCT: 8, 1004 OINDEXMAP: 8, 1005 OINDEX: 8, 1006 OSLICE: 8, 1007 OSLICESTR: 8, 1008 OSLICEARR: 8, 1009 OSLICE3: 8, 1010 OSLICE3ARR: 8, 1011 ODOTINTER: 8, 1012 ODOTMETH: 8, 1013 ODOTPTR: 8, 1014 ODOTTYPE2: 8, 1015 ODOTTYPE: 8, 1016 ODOT: 8, 1017 OXDOT: 8, 1018 OCALLPART: 8, 1019 OPLUS: 7, 1020 ONOT: 7, 1021 OCOM: 7, 1022 OMINUS: 7, 1023 OADDR: 7, 1024 OIND: 7, 1025 ORECV: 7, 1026 OMUL: 6, 1027 ODIV: 6, 1028 OMOD: 6, 1029 OLSH: 6, 1030 ORSH: 6, 1031 OAND: 6, 1032 OANDNOT: 6, 1033 OADD: 5, 1034 OSUB: 5, 1035 OOR: 5, 1036 OXOR: 5, 1037 OEQ: 4, 1038 OLT: 4, 1039 OLE: 4, 1040 OGE: 4, 1041 OGT: 4, 1042 ONE: 4, 1043 OCMPSTR: 4, 1044 OCMPIFACE: 4, 1045 OSEND: 3, 1046 OANDAND: 2, 1047 OOROR: 1, 1048 // Statements handled by stmtfmt 1049 OAS: -1, 1050 OAS2: -1, 1051 OAS2DOTTYPE: -1, 1052 OAS2FUNC: -1, 1053 OAS2MAPR: -1, 1054 OAS2RECV: -1, 1055 OASOP: -1, 1056 OBREAK: -1, 1057 OCASE: -1, 1058 OCONTINUE: -1, 1059 ODCL: -1, 1060 ODCLFIELD: -1, 1061 ODEFER: -1, 1062 OEMPTY: -1, 1063 OFALL: -1, 1064 OFOR: -1, 1065 OGOTO: -1, 1066 OIF: -1, 1067 OLABEL: -1, 1068 OPROC: -1, 1069 ORANGE: -1, 1070 ORETURN: -1, 1071 OSELECT: -1, 1072 OSWITCH: -1, 1073 OXCASE: -1, 1074 OXFALL: -1, 1075 OEND: 0, 1076 } 1077 1078 func exprfmt(n *Node, prec int) string { 1079 for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) { 1080 n = n.Left 1081 } 1082 1083 if n == nil { 1084 return "<N>" 1085 } 1086 1087 nprec := opprec[n.Op] 1088 if n.Op == OTYPE && n.Sym != nil { 1089 nprec = 8 1090 } 1091 1092 if prec > nprec { 1093 return fmt.Sprintf("(%v)", n) 1094 } 1095 1096 switch n.Op { 1097 case OPAREN: 1098 return fmt.Sprintf("(%v)", n.Left) 1099 1100 case ODDDARG: 1101 return "... argument" 1102 1103 case OREGISTER: 1104 return obj.Rconv(int(n.Reg)) 1105 1106 case OLITERAL: // this is a bit of a mess 1107 if fmtmode == FErr { 1108 if n.Orig != nil && n.Orig != n { 1109 return exprfmt(n.Orig, prec) 1110 } 1111 if n.Sym != nil { 1112 return Sconv(n.Sym, 0) 1113 } 1114 } 1115 if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n { 1116 return exprfmt(n.Orig, prec) 1117 } 1118 if n.Type != nil && n.Type != Types[n.Type.Etype] && n.Type != idealbool && n.Type != idealstring { 1119 // Need parens when type begins with what might 1120 // be misinterpreted as a unary operator: * or <-. 1121 if Isptr[n.Type.Etype] || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) { 1122 return fmt.Sprintf("(%v)(%v)", n.Type, Vconv(n.Val(), 0)) 1123 } else { 1124 return fmt.Sprintf("%v(%v)", n.Type, Vconv(n.Val(), 0)) 1125 } 1126 } 1127 1128 return Vconv(n.Val(), 0) 1129 1130 // Special case: name used as local variable in export. 1131 // _ becomes ~b%d internally; print as _ for export 1132 case ONAME: 1133 if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { 1134 return "_" 1135 } 1136 if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 { 1137 return fmt.Sprintf("%v·%d", n.Sym, n.Name.Vargen) 1138 } 1139 1140 // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, 1141 // but for export, this should be rendered as (*pkg.T).meth. 1142 // These nodes have the special property that they are names with a left OTYPE and a right ONAME. 1143 if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME { 1144 if Isptr[n.Left.Type.Etype] { 1145 return fmt.Sprintf("(%v).%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte)) 1146 } else { 1147 return fmt.Sprintf("%v.%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte)) 1148 } 1149 } 1150 fallthrough 1151 1152 //fallthrough 1153 case OPACK, ONONAME: 1154 return Sconv(n.Sym, 0) 1155 1156 case OTYPE: 1157 if n.Type == nil && n.Sym != nil { 1158 return Sconv(n.Sym, 0) 1159 } 1160 return Tconv(n.Type, 0) 1161 1162 case OTARRAY: 1163 if n.Left != nil { 1164 return fmt.Sprintf("[]%v", n.Left) 1165 } 1166 var f string 1167 f += fmt.Sprintf("[]%v", n.Right) 1168 return f // happens before typecheck 1169 1170 case OTMAP: 1171 return fmt.Sprintf("map[%v]%v", n.Left, n.Right) 1172 1173 case OTCHAN: 1174 switch n.Etype { 1175 case Crecv: 1176 return fmt.Sprintf("<-chan %v", n.Left) 1177 1178 case Csend: 1179 return fmt.Sprintf("chan<- %v", n.Left) 1180 1181 default: 1182 if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv { 1183 return fmt.Sprintf("chan (%v)", n.Left) 1184 } else { 1185 return fmt.Sprintf("chan %v", n.Left) 1186 } 1187 } 1188 1189 case OTSTRUCT: 1190 return "<struct>" 1191 1192 case OTINTER: 1193 return "<inter>" 1194 1195 case OTFUNC: 1196 return "<func>" 1197 1198 case OCLOSURE: 1199 if fmtmode == FErr { 1200 return "func literal" 1201 } 1202 if n.Nbody != nil { 1203 return fmt.Sprintf("%v { %v }", n.Type, n.Nbody) 1204 } 1205 return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody) 1206 1207 case OCOMPLIT: 1208 ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype] 1209 if fmtmode == FErr { 1210 if n.Right != nil && n.Right.Type != nil && !n.Implicit { 1211 if ptrlit { 1212 return fmt.Sprintf("&%v literal", n.Right.Type.Type) 1213 } else { 1214 return fmt.Sprintf("%v literal", n.Right.Type) 1215 } 1216 } 1217 1218 return "composite literal" 1219 } 1220 1221 if fmtmode == FExp && ptrlit { 1222 // typecheck has overwritten OIND by OTYPE with pointer type. 1223 return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Type, Hconv(n.List, obj.FmtComma)) 1224 } 1225 1226 return fmt.Sprintf("(%v{ %v })", n.Right, Hconv(n.List, obj.FmtComma)) 1227 1228 case OPTRLIT: 1229 if fmtmode == FExp && n.Left.Implicit { 1230 return Nconv(n.Left, 0) 1231 } 1232 return fmt.Sprintf("&%v", n.Left) 1233 1234 case OSTRUCTLIT: 1235 if fmtmode == FExp { // requires special handling of field names 1236 var f string 1237 if n.Implicit { 1238 f += "{" 1239 } else { 1240 f += fmt.Sprintf("(%v{", n.Type) 1241 } 1242 for l := n.List; l != nil; l = l.Next { 1243 f += fmt.Sprintf(" %v:%v", Sconv(l.N.Left.Sym, obj.FmtShort|obj.FmtByte), l.N.Right) 1244 1245 if l.Next != nil { 1246 f += "," 1247 } else { 1248 f += " " 1249 } 1250 } 1251 1252 if !n.Implicit { 1253 f += "})" 1254 return f 1255 } 1256 f += "}" 1257 return f 1258 } 1259 fallthrough 1260 1261 case OARRAYLIT, OMAPLIT: 1262 if fmtmode == FErr { 1263 return fmt.Sprintf("%v literal", n.Type) 1264 } 1265 if fmtmode == FExp && n.Implicit { 1266 return fmt.Sprintf("{ %v }", Hconv(n.List, obj.FmtComma)) 1267 } 1268 return fmt.Sprintf("(%v{ %v })", n.Type, Hconv(n.List, obj.FmtComma)) 1269 1270 case OKEY: 1271 if n.Left != nil && n.Right != nil { 1272 if fmtmode == FExp && n.Left.Type != nil && n.Left.Type.Etype == TFIELD { 1273 // requires special handling of field names 1274 return fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), n.Right) 1275 } else { 1276 return fmt.Sprintf("%v:%v", n.Left, n.Right) 1277 } 1278 } 1279 1280 if n.Left == nil && n.Right != nil { 1281 return fmt.Sprintf(":%v", n.Right) 1282 } 1283 if n.Left != nil && n.Right == nil { 1284 return fmt.Sprintf("%v:", n.Left) 1285 } 1286 return ":" 1287 1288 case OXDOT, 1289 ODOT, 1290 ODOTPTR, 1291 ODOTINTER, 1292 ODOTMETH, 1293 OCALLPART: 1294 var f string 1295 f += exprfmt(n.Left, nprec) 1296 if n.Right == nil || n.Right.Sym == nil { 1297 f += ".<nil>" 1298 return f 1299 } 1300 f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte)) 1301 return f 1302 1303 case ODOTTYPE, ODOTTYPE2: 1304 var f string 1305 f += exprfmt(n.Left, nprec) 1306 if n.Right != nil { 1307 f += fmt.Sprintf(".(%v)", n.Right) 1308 return f 1309 } 1310 f += fmt.Sprintf(".(%v)", n.Type) 1311 return f 1312 1313 case OINDEX, 1314 OINDEXMAP, 1315 OSLICE, 1316 OSLICESTR, 1317 OSLICEARR, 1318 OSLICE3, 1319 OSLICE3ARR: 1320 var f string 1321 f += exprfmt(n.Left, nprec) 1322 f += fmt.Sprintf("[%v]", n.Right) 1323 return f 1324 1325 case OCOPY, OCOMPLEX: 1326 return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), n.Left, n.Right) 1327 1328 case OCONV, 1329 OCONVIFACE, 1330 OCONVNOP, 1331 OARRAYBYTESTR, 1332 OARRAYRUNESTR, 1333 OSTRARRAYBYTE, 1334 OSTRARRAYRUNE, 1335 ORUNESTR: 1336 if n.Type == nil || n.Type.Sym == nil { 1337 return fmt.Sprintf("(%v)(%v)", n.Type, n.Left) 1338 } 1339 if n.Left != nil { 1340 return fmt.Sprintf("%v(%v)", n.Type, n.Left) 1341 } 1342 return fmt.Sprintf("%v(%v)", n.Type, Hconv(n.List, obj.FmtComma)) 1343 1344 case OREAL, 1345 OIMAG, 1346 OAPPEND, 1347 OCAP, 1348 OCLOSE, 1349 ODELETE, 1350 OLEN, 1351 OMAKE, 1352 ONEW, 1353 OPANIC, 1354 ORECOVER, 1355 OPRINT, 1356 OPRINTN: 1357 if n.Left != nil { 1358 return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), n.Left) 1359 } 1360 if n.Isddd { 1361 return fmt.Sprintf("%v(%v...)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma)) 1362 } 1363 return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma)) 1364 1365 case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG: 1366 var f string 1367 f += exprfmt(n.Left, nprec) 1368 if n.Isddd { 1369 f += fmt.Sprintf("(%v...)", Hconv(n.List, obj.FmtComma)) 1370 return f 1371 } 1372 f += fmt.Sprintf("(%v)", Hconv(n.List, obj.FmtComma)) 1373 return f 1374 1375 case OMAKEMAP, OMAKECHAN, OMAKESLICE: 1376 if n.List != nil { // pre-typecheck 1377 return fmt.Sprintf("make(%v, %v)", n.Type, Hconv(n.List, obj.FmtComma)) 1378 } 1379 if n.Right != nil { 1380 return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right) 1381 } 1382 if n.Left != nil && (n.Op == OMAKESLICE || !isideal(n.Left.Type)) { 1383 return fmt.Sprintf("make(%v, %v)", n.Type, n.Left) 1384 } 1385 return fmt.Sprintf("make(%v)", n.Type) 1386 1387 // Unary 1388 case OPLUS, 1389 OMINUS, 1390 OADDR, 1391 OCOM, 1392 OIND, 1393 ONOT, 1394 ORECV: 1395 var f string 1396 if n.Left.Op == n.Op { 1397 f += fmt.Sprintf("%v ", Oconv(int(n.Op), obj.FmtSharp)) 1398 } else { 1399 f += Oconv(int(n.Op), obj.FmtSharp) 1400 } 1401 f += exprfmt(n.Left, nprec+1) 1402 return f 1403 1404 // Binary 1405 case OADD, 1406 OAND, 1407 OANDAND, 1408 OANDNOT, 1409 ODIV, 1410 OEQ, 1411 OGE, 1412 OGT, 1413 OLE, 1414 OLT, 1415 OLSH, 1416 OMOD, 1417 OMUL, 1418 ONE, 1419 OOR, 1420 OOROR, 1421 ORSH, 1422 OSEND, 1423 OSUB, 1424 OXOR: 1425 var f string 1426 f += exprfmt(n.Left, nprec) 1427 1428 f += fmt.Sprintf(" %v ", Oconv(int(n.Op), obj.FmtSharp)) 1429 f += exprfmt(n.Right, nprec+1) 1430 return f 1431 1432 case OADDSTR: 1433 var f string 1434 for l := n.List; l != nil; l = l.Next { 1435 if l != n.List { 1436 f += " + " 1437 } 1438 f += exprfmt(l.N, nprec) 1439 } 1440 1441 return f 1442 1443 case OCMPSTR, OCMPIFACE: 1444 var f string 1445 f += exprfmt(n.Left, nprec) 1446 f += fmt.Sprintf(" %v ", Oconv(int(n.Etype), obj.FmtSharp)) 1447 f += exprfmt(n.Right, nprec+1) 1448 return f 1449 } 1450 1451 return fmt.Sprintf("<node %v>", Oconv(int(n.Op), 0)) 1452 } 1453 1454 func nodefmt(n *Node, flag int) string { 1455 t := n.Type 1456 1457 // we almost always want the original, except in export mode for literals 1458 // this saves the importer some work, and avoids us having to redo some 1459 // special casing for package unsafe 1460 if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil { 1461 n = n.Orig 1462 } 1463 1464 if flag&obj.FmtLong != 0 && t != nil { 1465 if t.Etype == TNIL { 1466 return "nil" 1467 } else { 1468 return fmt.Sprintf("%v (type %v)", n, t) 1469 } 1470 } 1471 1472 // TODO inlining produces expressions with ninits. we can't print these yet. 1473 1474 if opprec[n.Op] < 0 { 1475 return stmtfmt(n) 1476 } 1477 1478 return exprfmt(n, 0) 1479 } 1480 1481 var dumpdepth int 1482 1483 func indent(buf *bytes.Buffer) { 1484 buf.WriteString("\n") 1485 for i := 0; i < dumpdepth; i++ { 1486 buf.WriteString(". ") 1487 } 1488 } 1489 1490 func nodedump(n *Node, flag int) string { 1491 if n == nil { 1492 return "" 1493 } 1494 1495 recur := flag&obj.FmtShort == 0 1496 1497 var buf bytes.Buffer 1498 if recur { 1499 indent(&buf) 1500 if dumpdepth > 10 { 1501 buf.WriteString("...") 1502 return buf.String() 1503 } 1504 1505 if n.Ninit != nil { 1506 fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), n.Ninit) 1507 indent(&buf) 1508 } 1509 } 1510 1511 switch n.Op { 1512 default: 1513 fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0)) 1514 1515 case OREGISTER, OINDREG: 1516 fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Reg)), Jconv(n, 0)) 1517 1518 case OLITERAL: 1519 fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Vconv(n.Val(), 0), Jconv(n, 0)) 1520 1521 case ONAME, ONONAME: 1522 if n.Sym != nil { 1523 fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0)) 1524 } else { 1525 fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0)) 1526 } 1527 if recur && n.Type == nil && n.Name.Param.Ntype != nil { 1528 indent(&buf) 1529 fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype) 1530 } 1531 1532 case OASOP: 1533 fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0)) 1534 1535 case OTYPE: 1536 fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0), n.Type) 1537 if recur && n.Type == nil && n.Name.Param.Ntype != nil { 1538 indent(&buf) 1539 fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype) 1540 } 1541 } 1542 1543 if n.Sym != nil && n.Op != ONAME { 1544 fmt.Fprintf(&buf, " %v", n.Sym) 1545 } 1546 1547 if n.Type != nil { 1548 fmt.Fprintf(&buf, " %v", n.Type) 1549 } 1550 1551 if recur { 1552 if n.Left != nil { 1553 buf.WriteString(Nconv(n.Left, 0)) 1554 } 1555 if n.Right != nil { 1556 buf.WriteString(Nconv(n.Right, 0)) 1557 } 1558 if n.List != nil { 1559 indent(&buf) 1560 fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), n.List) 1561 } 1562 1563 if n.Rlist != nil { 1564 indent(&buf) 1565 fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), n.Rlist) 1566 } 1567 1568 if n.Nbody != nil { 1569 indent(&buf) 1570 fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), n.Nbody) 1571 } 1572 } 1573 1574 return buf.String() 1575 } 1576 1577 func (s *Sym) String() string { 1578 return Sconv(s, 0) 1579 } 1580 1581 // Fmt "%S": syms 1582 // Flags: "%hS" suppresses qualifying with package 1583 func Sconv(s *Sym, flag int) string { 1584 if flag&obj.FmtLong != 0 { 1585 panic("linksymfmt") 1586 } 1587 1588 if s == nil { 1589 return "<S>" 1590 } 1591 1592 if s.Name == "_" { 1593 return "_" 1594 } 1595 1596 sf := flag 1597 sm := setfmode(&flag) 1598 var r int 1599 _ = r 1600 str := symfmt(s, flag) 1601 flag = sf 1602 fmtmode = sm 1603 return str 1604 } 1605 1606 func (t *Type) String() string { 1607 return Tconv(t, 0) 1608 } 1609 1610 // Fmt "%T": types. 1611 // Flags: 'l' print definition, not name 1612 // 'h' omit 'func' and receiver from function types, short type names 1613 // 'u' package name, not prefix (FTypeId mode, sticky) 1614 func Tconv(t *Type, flag int) string { 1615 if t == nil { 1616 return "<T>" 1617 } 1618 1619 if t.Trecur > 4 { 1620 return "<...>" 1621 } 1622 1623 t.Trecur++ 1624 sf := flag 1625 sm := setfmode(&flag) 1626 1627 if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) { 1628 fmtpkgpfx++ 1629 } 1630 if fmtpkgpfx != 0 { 1631 flag |= obj.FmtUnsigned 1632 } 1633 1634 var r int 1635 _ = r 1636 str := typefmt(t, flag) 1637 1638 if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) { 1639 fmtpkgpfx-- 1640 } 1641 1642 flag = sf 1643 fmtmode = sm 1644 t.Trecur-- 1645 return str 1646 } 1647 1648 func (n *Node) String() string { 1649 return Nconv(n, 0) 1650 } 1651 1652 // Fmt '%N': Nodes. 1653 // Flags: 'l' suffix with "(type %T)" where possible 1654 // '+h' in debug mode, don't recurse, no multiline output 1655 func Nconv(n *Node, flag int) string { 1656 if n == nil { 1657 return "<N>" 1658 } 1659 sf := flag 1660 sm := setfmode(&flag) 1661 1662 var r int 1663 _ = r 1664 var str string 1665 switch fmtmode { 1666 case FErr, FExp: 1667 str = nodefmt(n, flag) 1668 1669 case FDbg: 1670 dumpdepth++ 1671 str = nodedump(n, flag) 1672 dumpdepth-- 1673 1674 default: 1675 Fatal("unhandled %%N mode") 1676 } 1677 1678 flag = sf 1679 fmtmode = sm 1680 return str 1681 } 1682 1683 func (l *NodeList) String() string { 1684 return Hconv(l, 0) 1685 } 1686 1687 // Fmt '%H': NodeList. 1688 // Flags: all those of %N plus ',': separate with comma's instead of semicolons. 1689 func Hconv(l *NodeList, flag int) string { 1690 if l == nil && fmtmode == FDbg { 1691 return "<nil>" 1692 } 1693 1694 sf := flag 1695 sm := setfmode(&flag) 1696 var r int 1697 _ = r 1698 sep := "; " 1699 if fmtmode == FDbg { 1700 sep = "\n" 1701 } else if flag&obj.FmtComma != 0 { 1702 sep = ", " 1703 } 1704 1705 var buf bytes.Buffer 1706 for ; l != nil; l = l.Next { 1707 buf.WriteString(Nconv(l.N, 0)) 1708 if l.Next != nil { 1709 buf.WriteString(sep) 1710 } 1711 } 1712 1713 flag = sf 1714 fmtmode = sm 1715 return buf.String() 1716 } 1717 1718 func dumplist(s string, l *NodeList) { 1719 fmt.Printf("%s%v\n", s, Hconv(l, obj.FmtSign)) 1720 } 1721 1722 func Dump(s string, n *Node) { 1723 fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, obj.FmtSign)) 1724 }