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