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