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