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