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