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