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