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