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