github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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  	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.Lineno != 0 {
   287  		fmt.Fprintf(s, " l(%d)", n.Lineno)
   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  	// Statements handled by stmtfmt
  1081  	OAS:         -1,
  1082  	OAS2:        -1,
  1083  	OAS2DOTTYPE: -1,
  1084  	OAS2FUNC:    -1,
  1085  	OAS2MAPR:    -1,
  1086  	OAS2RECV:    -1,
  1087  	OASOP:       -1,
  1088  	OBREAK:      -1,
  1089  	OCASE:       -1,
  1090  	OCONTINUE:   -1,
  1091  	ODCL:        -1,
  1092  	ODCLFIELD:   -1,
  1093  	ODEFER:      -1,
  1094  	OEMPTY:      -1,
  1095  	OFALL:       -1,
  1096  	OFOR:        -1,
  1097  	OGOTO:       -1,
  1098  	OIF:         -1,
  1099  	OLABEL:      -1,
  1100  	OPROC:       -1,
  1101  	ORANGE:      -1,
  1102  	ORETURN:     -1,
  1103  	OSELECT:     -1,
  1104  	OSWITCH:     -1,
  1105  	OXCASE:      -1,
  1106  	OXFALL:      -1,
  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)(%v)", n.Type, n.Left)
  1337  			return
  1338  		}
  1339  		if n.Left != nil {
  1340  			fmt.Fprintf(s, "%v(%v)", n.Type, n.Left)
  1341  			return
  1342  		}
  1343  		fmt.Fprintf(s, "%v(%.v)", n.Type, n.List)
  1344  
  1345  	case OREAL,
  1346  		OIMAG,
  1347  		OAPPEND,
  1348  		OCAP,
  1349  		OCLOSE,
  1350  		ODELETE,
  1351  		OLEN,
  1352  		OMAKE,
  1353  		ONEW,
  1354  		OPANIC,
  1355  		ORECOVER,
  1356  		OALIGNOF,
  1357  		OOFFSETOF,
  1358  		OSIZEOF,
  1359  		OPRINT,
  1360  		OPRINTN:
  1361  		if n.Left != nil {
  1362  			fmt.Fprintf(s, "%#v(%v)", n.Op, n.Left)
  1363  			return
  1364  		}
  1365  		if n.Isddd {
  1366  			fmt.Fprintf(s, "%#v(%.v...)", n.Op, n.List)
  1367  			return
  1368  		}
  1369  		fmt.Fprintf(s, "%#v(%.v)", n.Op, n.List)
  1370  
  1371  	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
  1372  		n.Left.exprfmt(s, nprec)
  1373  		if n.Isddd {
  1374  			fmt.Fprintf(s, "(%.v...)", n.List)
  1375  			return
  1376  		}
  1377  		fmt.Fprintf(s, "(%.v)", n.List)
  1378  
  1379  	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
  1380  		if n.List.Len() != 0 { // pre-typecheck
  1381  			fmt.Fprintf(s, "make(%v, %.v)", n.Type, n.List)
  1382  			return
  1383  		}
  1384  		if n.Right != nil {
  1385  			fmt.Fprintf(s, "make(%v, %v, %v)", n.Type, n.Left, n.Right)
  1386  			return
  1387  		}
  1388  		if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
  1389  			fmt.Fprintf(s, "make(%v, %v)", n.Type, n.Left)
  1390  			return
  1391  		}
  1392  		fmt.Fprintf(s, "make(%v)", n.Type)
  1393  
  1394  		// Unary
  1395  	case OPLUS,
  1396  		OMINUS,
  1397  		OADDR,
  1398  		OCOM,
  1399  		OIND,
  1400  		ONOT,
  1401  		ORECV:
  1402  		fmt.Fprint(s, n.Op.GoString()) // %#v
  1403  		if n.Left.Op == n.Op {
  1404  			fmt.Fprint(s, " ")
  1405  		}
  1406  		n.Left.exprfmt(s, nprec+1)
  1407  
  1408  		// Binary
  1409  	case OADD,
  1410  		OAND,
  1411  		OANDAND,
  1412  		OANDNOT,
  1413  		ODIV,
  1414  		OEQ,
  1415  		OGE,
  1416  		OGT,
  1417  		OLE,
  1418  		OLT,
  1419  		OLSH,
  1420  		OMOD,
  1421  		OMUL,
  1422  		ONE,
  1423  		OOR,
  1424  		OOROR,
  1425  		ORSH,
  1426  		OSEND,
  1427  		OSUB,
  1428  		OXOR:
  1429  		n.Left.exprfmt(s, nprec)
  1430  		fmt.Fprintf(s, " %#v ", n.Op)
  1431  		n.Right.exprfmt(s, nprec+1)
  1432  
  1433  	case OADDSTR:
  1434  		i := 0
  1435  		for _, n1 := range n.List.Slice() {
  1436  			if i != 0 {
  1437  				fmt.Fprint(s, " + ")
  1438  			}
  1439  			n1.exprfmt(s, nprec)
  1440  			i++
  1441  		}
  1442  
  1443  	case OCMPSTR, OCMPIFACE:
  1444  		n.Left.exprfmt(s, nprec)
  1445  		// TODO(marvin): Fix Node.EType type union.
  1446  		fmt.Fprintf(s, " %#v ", Op(n.Etype))
  1447  		n.Right.exprfmt(s, nprec+1)
  1448  
  1449  	default:
  1450  		fmt.Fprintf(s, "<node %v>", n.Op)
  1451  	}
  1452  }
  1453  
  1454  func (n *Node) nodefmt(s fmt.State, flag FmtFlag) {
  1455  	t := n.Type
  1456  
  1457  	// we almost always want the original, except in export mode for literals
  1458  	// this saves the importer some work, and avoids us having to redo some
  1459  	// special casing for package unsafe
  1460  	if n.Op != OLITERAL && n.Orig != nil {
  1461  		n = n.Orig
  1462  	}
  1463  
  1464  	if flag&FmtLong != 0 && t != nil {
  1465  		if t.Etype == TNIL {
  1466  			fmt.Fprint(s, "nil")
  1467  		} else {
  1468  			fmt.Fprintf(s, "%v (type %v)", n, t)
  1469  		}
  1470  		return
  1471  	}
  1472  
  1473  	// TODO inlining produces expressions with ninits. we can't print these yet.
  1474  
  1475  	if opprec[n.Op] < 0 {
  1476  		n.stmtfmt(s)
  1477  		return
  1478  	}
  1479  
  1480  	n.exprfmt(s, 0)
  1481  }
  1482  
  1483  func (n *Node) nodedump(s fmt.State, flag FmtFlag) {
  1484  	if n == nil {
  1485  		return
  1486  	}
  1487  
  1488  	recur := flag&FmtShort == 0
  1489  
  1490  	if recur {
  1491  		indent(s)
  1492  		if dumpdepth > 10 {
  1493  			fmt.Fprint(s, "...")
  1494  			return
  1495  		}
  1496  
  1497  		if n.Ninit.Len() != 0 {
  1498  			fmt.Fprintf(s, "%v-init%v", n.Op, n.Ninit)
  1499  			indent(s)
  1500  		}
  1501  	}
  1502  
  1503  	switch n.Op {
  1504  	default:
  1505  		fmt.Fprintf(s, "%v%j", n.Op, n)
  1506  
  1507  	case OINDREGSP:
  1508  		fmt.Fprintf(s, "%v-SP%j", n.Op, n)
  1509  
  1510  	case OLITERAL:
  1511  		fmt.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
  1512  
  1513  	case ONAME, ONONAME:
  1514  		if n.Sym != nil {
  1515  			fmt.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
  1516  		} else {
  1517  			fmt.Fprintf(s, "%v%j", n.Op, n)
  1518  		}
  1519  		if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
  1520  			indent(s)
  1521  			fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
  1522  		}
  1523  
  1524  	case OASOP:
  1525  		fmt.Fprintf(s, "%v-%v%j", n.Op, Op(n.Etype), n)
  1526  
  1527  	case OTYPE:
  1528  		fmt.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type)
  1529  		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
  1530  			indent(s)
  1531  			fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
  1532  		}
  1533  	}
  1534  
  1535  	if n.Sym != nil && n.Op != ONAME {
  1536  		fmt.Fprintf(s, " %v", n.Sym)
  1537  	}
  1538  
  1539  	if n.Type != nil {
  1540  		fmt.Fprintf(s, " %v", n.Type)
  1541  	}
  1542  
  1543  	if recur {
  1544  		if n.Left != nil {
  1545  			fmt.Fprintf(s, "%v", n.Left)
  1546  		}
  1547  		if n.Right != nil {
  1548  			fmt.Fprintf(s, "%v", n.Right)
  1549  		}
  1550  		if n.List.Len() != 0 {
  1551  			indent(s)
  1552  			fmt.Fprintf(s, "%v-list%v", n.Op, n.List)
  1553  		}
  1554  
  1555  		if n.Rlist.Len() != 0 {
  1556  			indent(s)
  1557  			fmt.Fprintf(s, "%v-rlist%v", n.Op, n.Rlist)
  1558  		}
  1559  
  1560  		if n.Nbody.Len() != 0 {
  1561  			indent(s)
  1562  			fmt.Fprintf(s, "%v-body%v", n.Op, n.Nbody)
  1563  		}
  1564  	}
  1565  }
  1566  
  1567  // "%S" suppresses qualifying with package
  1568  func (s *Sym) Format(f fmt.State, verb rune) {
  1569  	switch verb {
  1570  	case 'v', 'S':
  1571  		fmt.Fprint(f, s.sconv(fmtFlag(f, verb)))
  1572  
  1573  	default:
  1574  		fmt.Fprintf(f, "%%!%c(*Sym=%p)", verb, s)
  1575  	}
  1576  }
  1577  
  1578  func (s *Sym) String() string {
  1579  	return s.sconv(0)
  1580  }
  1581  
  1582  // See #16897 before changing the implementation of sconv.
  1583  func (s *Sym) sconv(flag FmtFlag) string {
  1584  	if flag&FmtLong != 0 {
  1585  		panic("linksymfmt")
  1586  	}
  1587  
  1588  	if s == nil {
  1589  		return "<S>"
  1590  	}
  1591  
  1592  	if s.Name == "_" {
  1593  		return "_"
  1594  	}
  1595  
  1596  	sf := flag
  1597  	sm := setfmode(&flag)
  1598  	str := s.symfmt(flag)
  1599  	flag = sf
  1600  	fmtmode = sm
  1601  	return str
  1602  }
  1603  
  1604  func (t *Type) String() string {
  1605  	return t.tconv(0)
  1606  }
  1607  
  1608  func fldconv(f *Field, flag FmtFlag) string {
  1609  	if f == nil {
  1610  		return "<T>"
  1611  	}
  1612  
  1613  	sf := flag
  1614  	sm := setfmode(&flag)
  1615  
  1616  	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
  1617  		fmtpkgpfx++
  1618  	}
  1619  	if fmtpkgpfx != 0 {
  1620  		flag |= FmtUnsigned
  1621  	}
  1622  
  1623  	var name string
  1624  	if flag&FmtShort == 0 {
  1625  		s := f.Sym
  1626  
  1627  		// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
  1628  		// ~r%d is a (formerly) unnamed result.
  1629  		if fmtmode == FErr && f.Nname != nil {
  1630  			if f.Nname.Orig != nil {
  1631  				s = f.Nname.Orig.Sym
  1632  				if s != nil && s.Name[0] == '~' {
  1633  					if s.Name[1] == 'r' { // originally an unnamed result
  1634  						s = nil
  1635  					} else if s.Name[1] == 'b' { // originally the blank identifier _
  1636  						s = lookup("_")
  1637  					}
  1638  				}
  1639  			} else {
  1640  				s = nil
  1641  			}
  1642  		}
  1643  
  1644  		if s != nil && f.Embedded == 0 {
  1645  			if f.Funarg != FunargNone {
  1646  				name = f.Nname.String()
  1647  			} else if flag&FmtLong != 0 {
  1648  				name = fmt.Sprintf("%0S", s)
  1649  				if !exportname(name) && flag&FmtUnsigned == 0 {
  1650  					name = s.String() // qualify non-exported names (used on structs, not on funarg)
  1651  				}
  1652  			} else {
  1653  				name = s.String()
  1654  			}
  1655  		}
  1656  	}
  1657  
  1658  	var typ string
  1659  	if f.Isddd {
  1660  		typ = fmt.Sprintf("...%v", f.Type.Elem())
  1661  	} else {
  1662  		typ = fmt.Sprintf("%v", f.Type)
  1663  	}
  1664  
  1665  	str := typ
  1666  	if name != "" {
  1667  		str = name + " " + typ
  1668  	}
  1669  
  1670  	if flag&FmtShort == 0 && f.Funarg == FunargNone && f.Note != "" {
  1671  		str += " " + strconv.Quote(f.Note)
  1672  	}
  1673  
  1674  	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
  1675  		fmtpkgpfx--
  1676  	}
  1677  
  1678  	flag = sf
  1679  	fmtmode = sm
  1680  	return str
  1681  }
  1682  
  1683  // "%L"  print definition, not name
  1684  // "%S"  omit 'func' and receiver from function types, short type names
  1685  // "% v" package name, not prefix (FTypeId mode, sticky)
  1686  func (t *Type) Format(s fmt.State, verb rune) {
  1687  	switch verb {
  1688  	case 'v', 'S', 'L':
  1689  		fmt.Fprint(s, t.tconv(fmtFlag(s, verb)))
  1690  
  1691  	default:
  1692  		fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
  1693  	}
  1694  }
  1695  
  1696  // See #16897 before changing the implementation of tconv.
  1697  func (t *Type) tconv(flag FmtFlag) string {
  1698  	if t == nil {
  1699  		return "<T>"
  1700  	}
  1701  
  1702  	if t.Trecur > 4 {
  1703  		return "<...>"
  1704  	}
  1705  
  1706  	t.Trecur++
  1707  	sf := flag
  1708  	sm := setfmode(&flag)
  1709  
  1710  	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
  1711  		fmtpkgpfx++
  1712  	}
  1713  	if fmtpkgpfx != 0 {
  1714  		flag |= FmtUnsigned
  1715  	}
  1716  
  1717  	str := t.typefmt(flag)
  1718  
  1719  	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
  1720  		fmtpkgpfx--
  1721  	}
  1722  
  1723  	flag = sf
  1724  	fmtmode = sm
  1725  	t.Trecur--
  1726  	return str
  1727  }
  1728  
  1729  func (n *Node) String() string {
  1730  	return fmt.Sprint(n)
  1731  }
  1732  
  1733  // "%L"  suffix with "(type %T)" where possible
  1734  // "%+S" in debug mode, don't recurse, no multiline output
  1735  func (n *Node) Nconv(s fmt.State, flag FmtFlag) {
  1736  	if n == nil {
  1737  		fmt.Fprint(s, "<N>")
  1738  		return
  1739  	}
  1740  
  1741  	sf := flag
  1742  	sm := setfmode(&flag)
  1743  
  1744  	switch fmtmode {
  1745  	case FErr:
  1746  		n.nodefmt(s, flag)
  1747  
  1748  	case FDbg:
  1749  		dumpdepth++
  1750  		n.nodedump(s, flag)
  1751  		dumpdepth--
  1752  
  1753  	default:
  1754  		Fatalf("unhandled %%N mode: %d", fmtmode)
  1755  	}
  1756  
  1757  	flag = sf
  1758  	fmtmode = sm
  1759  }
  1760  
  1761  func (l Nodes) Format(s fmt.State, verb rune) {
  1762  	switch verb {
  1763  	case 'v':
  1764  		l.hconv(s, fmtFlag(s, verb))
  1765  
  1766  	default:
  1767  		fmt.Fprintf(s, "%%!%c(Nodes)", verb)
  1768  	}
  1769  }
  1770  
  1771  func (n Nodes) String() string {
  1772  	return fmt.Sprint(n)
  1773  }
  1774  
  1775  // Flags: all those of %N plus '.': separate with comma's instead of semicolons.
  1776  func (l Nodes) hconv(s fmt.State, flag FmtFlag) {
  1777  	if l.Len() == 0 && fmtmode == FDbg {
  1778  		fmt.Fprint(s, "<nil>")
  1779  		return
  1780  	}
  1781  
  1782  	sf := flag
  1783  	sm := setfmode(&flag)
  1784  	sep := "; "
  1785  	if fmtmode == FDbg {
  1786  		sep = "\n"
  1787  	} else if flag&FmtComma != 0 {
  1788  		sep = ", "
  1789  	}
  1790  
  1791  	for i, n := range l.Slice() {
  1792  		fmt.Fprint(s, n)
  1793  		if i+1 < l.Len() {
  1794  			fmt.Fprint(s, sep)
  1795  		}
  1796  	}
  1797  
  1798  	flag = sf
  1799  	fmtmode = sm
  1800  }
  1801  
  1802  func dumplist(s string, l Nodes) {
  1803  	fmt.Printf("%s%+v\n", s, l)
  1804  }
  1805  
  1806  func Dump(s string, n *Node) {
  1807  	fmt.Printf("%s [%p]%+v\n", s, n, n)
  1808  }
  1809  
  1810  // TODO(gri) make variable local somehow
  1811  var dumpdepth int
  1812  
  1813  // indent prints indentation to s.
  1814  func indent(s fmt.State) {
  1815  	fmt.Fprint(s, "\n")
  1816  	for i := 0; i < dumpdepth; i++ {
  1817  		fmt.Fprint(s, ".   ")
  1818  	}
  1819  }