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