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