github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/compile/internal/gc/fmt.go (about)

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