github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/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  			switch {
   583  			case t1.Sym == nil:
   584  				// Check first that a symbol is defined for this type.
   585  				// Wrong interface definitions may have types lacking a symbol.
   586  				break
   587  			case exportname(t1.Sym.Name):
   588  				buf.WriteString(Sconv(t1.Sym, obj.FmtShort))
   589  			default:
   590  				buf.WriteString(Sconv(t1.Sym, obj.FmtUnsigned))
   591  			}
   592  			buf.WriteString(Tconv(t1.Type, obj.FmtShort))
   593  			if t1.Down != nil {
   594  				buf.WriteString(";")
   595  			}
   596  		}
   597  		if t.Type != nil {
   598  			buf.WriteString(" ")
   599  		}
   600  		buf.WriteString("}")
   601  		return buf.String()
   602  
   603  	case TFUNC:
   604  		var buf bytes.Buffer
   605  		if flag&obj.FmtShort != 0 {
   606  			// no leading func
   607  		} else {
   608  			if t.Thistuple != 0 {
   609  				buf.WriteString("method")
   610  				buf.WriteString(Tconv(getthisx(t), 0))
   611  				buf.WriteString(" ")
   612  			}
   613  			buf.WriteString("func")
   614  		}
   615  		buf.WriteString(Tconv(getinargx(t), 0))
   616  
   617  		switch t.Outtuple {
   618  		case 0:
   619  			break
   620  
   621  		case 1:
   622  			if fmtmode != FExp {
   623  				buf.WriteString(" ")
   624  				buf.WriteString(Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type
   625  				break
   626  			}
   627  			fallthrough
   628  
   629  		default:
   630  			buf.WriteString(" ")
   631  			buf.WriteString(Tconv(getoutargx(t), 0))
   632  		}
   633  		return buf.String()
   634  
   635  	case TSTRUCT:
   636  		if t.Map != nil {
   637  			// Format the bucket struct for map[x]y as map.bucket[x]y.
   638  			// This avoids a recursive print that generates very long names.
   639  			if t.Map.Bucket == t {
   640  				return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type)
   641  			}
   642  
   643  			if t.Map.Hmap == t {
   644  				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type)
   645  			}
   646  
   647  			if t.Map.Hiter == t {
   648  				return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type)
   649  			}
   650  
   651  			Yyerror("unknown internal map type")
   652  		}
   653  
   654  		var buf bytes.Buffer
   655  		if t.Funarg {
   656  			buf.WriteString("(")
   657  			if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
   658  				for t1 := t.Type; t1 != nil; t1 = t1.Down {
   659  					buf.WriteString(Tconv(t1, obj.FmtShort))
   660  					if t1.Down != nil {
   661  						buf.WriteString(", ")
   662  					}
   663  				}
   664  			} else {
   665  				for t1 := t.Type; t1 != nil; t1 = t1.Down {
   666  					buf.WriteString(Tconv(t1, 0))
   667  					if t1.Down != nil {
   668  						buf.WriteString(", ")
   669  					}
   670  				}
   671  			}
   672  			buf.WriteString(")")
   673  		} else {
   674  			buf.WriteString("struct {")
   675  			for t1 := t.Type; t1 != nil; t1 = t1.Down {
   676  				buf.WriteString(" ")
   677  				buf.WriteString(Tconv(t1, obj.FmtLong))
   678  				if t1.Down != nil {
   679  					buf.WriteString(";")
   680  				}
   681  			}
   682  			if t.Type != nil {
   683  				buf.WriteString(" ")
   684  			}
   685  			buf.WriteString("}")
   686  		}
   687  		return buf.String()
   688  
   689  	case TFIELD:
   690  		var name string
   691  		if flag&obj.FmtShort == 0 {
   692  			s := t.Sym
   693  
   694  			// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
   695  			// ~r%d is a (formerly) unnamed result.
   696  			if (fmtmode == FErr || fmtmode == FExp) && t.Nname != nil {
   697  				if t.Nname.Orig != nil {
   698  					s = t.Nname.Orig.Sym
   699  					if s != nil && s.Name[0] == '~' {
   700  						if s.Name[1] == 'r' { // originally an unnamed result
   701  							s = nil
   702  						} else if s.Name[1] == 'b' { // originally the blank identifier _
   703  							s = Lookup("_")
   704  						}
   705  					}
   706  				} else {
   707  					s = nil
   708  				}
   709  			}
   710  
   711  			if s != nil && t.Embedded == 0 {
   712  				if t.Funarg {
   713  					name = Nconv(t.Nname, 0)
   714  				} else if flag&obj.FmtLong != 0 {
   715  					name = Sconv(s, obj.FmtShort|obj.FmtByte) // qualify non-exported names (used on structs, not on funarg)
   716  				} else {
   717  					name = Sconv(s, 0)
   718  				}
   719  			} else if fmtmode == FExp {
   720  				// TODO(rsc) this breaks on the eliding of unused arguments in the backend
   721  				// when this is fixed, the special case in dcl.go checkarglist can go.
   722  				//if(t->funarg)
   723  				//	fmtstrcpy(fp, "_ ");
   724  				//else
   725  				if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
   726  					name = fmt.Sprintf("@%q.?", s.Pkg.Path)
   727  				} else {
   728  					name = "?"
   729  				}
   730  			}
   731  		}
   732  
   733  		var typ string
   734  		if t.Isddd {
   735  			typ = "..." + Tconv(t.Type.Type, 0)
   736  		} else {
   737  			typ = Tconv(t.Type, 0)
   738  		}
   739  
   740  		str := typ
   741  		if name != "" {
   742  			str = name + " " + typ
   743  		}
   744  		if flag&obj.FmtShort == 0 && t.Note != nil {
   745  			str += " " + strconv.Quote(*t.Note)
   746  		}
   747  		return str
   748  
   749  	case TFORW:
   750  		if t.Sym != nil {
   751  			return fmt.Sprintf("undefined %v", t.Sym)
   752  		}
   753  		return "undefined"
   754  
   755  	case TUNSAFEPTR:
   756  		if fmtmode == FExp {
   757  			return "@\"unsafe\".Pointer"
   758  		}
   759  		return "unsafe.Pointer"
   760  	}
   761  
   762  	if fmtmode == FExp {
   763  		Fatalf("missing %v case during export", Econv(t.Etype))
   764  	}
   765  
   766  	// Don't know how to handle - fall back to detailed prints.
   767  	return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Type)
   768  }
   769  
   770  // Statements which may be rendered with a simplestmt as init.
   771  func stmtwithinit(op Op) bool {
   772  	switch op {
   773  	case OIF, OFOR, OSWITCH:
   774  		return true
   775  	}
   776  
   777  	return false
   778  }
   779  
   780  func stmtfmt(n *Node) string {
   781  	var f string
   782  
   783  	// some statements allow for an init, but at most one,
   784  	// but we may have an arbitrary number added, eg by typecheck
   785  	// and inlining.  If it doesn't fit the syntax, emit an enclosing
   786  	// block starting with the init statements.
   787  
   788  	// if we can just say "for" n->ninit; ... then do so
   789  	simpleinit := n.Ninit != nil && n.Ninit.Next == nil && n.Ninit.N.Ninit == nil && stmtwithinit(n.Op)
   790  
   791  	// otherwise, print the inits as separate statements
   792  	complexinit := n.Ninit != nil && !simpleinit && (fmtmode != FErr)
   793  
   794  	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
   795  	extrablock := complexinit && stmtwithinit(n.Op)
   796  
   797  	if extrablock {
   798  		f += "{"
   799  	}
   800  
   801  	if complexinit {
   802  		f += fmt.Sprintf(" %v; ", n.Ninit)
   803  	}
   804  
   805  	switch n.Op {
   806  	case ODCL:
   807  		if fmtmode == FExp {
   808  			switch n.Left.Class &^ PHEAP {
   809  			case PPARAM, PPARAMOUT, PAUTO:
   810  				f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
   811  				goto ret
   812  			}
   813  		}
   814  
   815  		f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type)
   816  
   817  	case ODCLFIELD:
   818  		if n.Left != nil {
   819  			f += fmt.Sprintf("%v %v", n.Left, n.Right)
   820  		} else {
   821  			f += Nconv(n.Right, 0)
   822  		}
   823  
   824  	// Don't export "v = <N>" initializing statements, hope they're always
   825  	// preceded by the DCL which will be re-parsed and typecheck to reproduce
   826  	// the "v = <N>" again.
   827  	case OAS, OASWB:
   828  		if fmtmode == FExp && n.Right == nil {
   829  			break
   830  		}
   831  
   832  		if n.Colas && !complexinit {
   833  			f += fmt.Sprintf("%v := %v", n.Left, n.Right)
   834  		} else {
   835  			f += fmt.Sprintf("%v = %v", n.Left, n.Right)
   836  		}
   837  
   838  	case OASOP:
   839  		if n.Implicit {
   840  			if Op(n.Etype) == OADD {
   841  				f += fmt.Sprintf("%v++", n.Left)
   842  			} else {
   843  				f += fmt.Sprintf("%v--", n.Left)
   844  			}
   845  			break
   846  		}
   847  
   848  		f += fmt.Sprintf("%v %v= %v", n.Left, Oconv(int(n.Etype), obj.FmtSharp), n.Right)
   849  
   850  	case OAS2:
   851  		if n.Colas && !complexinit {
   852  			f += fmt.Sprintf("%v := %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
   853  			break
   854  		}
   855  		fallthrough
   856  
   857  	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
   858  		f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
   859  
   860  	case ORETURN:
   861  		f += fmt.Sprintf("return %v", Hconv(n.List, obj.FmtComma))
   862  
   863  	case ORETJMP:
   864  		f += fmt.Sprintf("retjmp %v", n.Sym)
   865  
   866  	case OPROC:
   867  		f += fmt.Sprintf("go %v", n.Left)
   868  
   869  	case ODEFER:
   870  		f += fmt.Sprintf("defer %v", n.Left)
   871  
   872  	case OIF:
   873  		if simpleinit {
   874  			f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.N, n.Left, n.Nbody)
   875  		} else {
   876  			f += fmt.Sprintf("if %v { %v }", n.Left, n.Nbody)
   877  		}
   878  		if n.Rlist != nil {
   879  			f += fmt.Sprintf(" else { %v }", n.Rlist)
   880  		}
   881  
   882  	case OFOR:
   883  		if fmtmode == FErr { // TODO maybe only if FmtShort, same below
   884  			f += "for loop"
   885  			break
   886  		}
   887  
   888  		f += "for"
   889  		if simpleinit {
   890  			f += fmt.Sprintf(" %v;", n.Ninit.N)
   891  		} else if n.Right != nil {
   892  			f += " ;"
   893  		}
   894  
   895  		if n.Left != nil {
   896  			f += fmt.Sprintf(" %v", n.Left)
   897  		}
   898  
   899  		if n.Right != nil {
   900  			f += fmt.Sprintf("; %v", n.Right)
   901  		} else if simpleinit {
   902  			f += ";"
   903  		}
   904  
   905  		f += fmt.Sprintf(" { %v }", n.Nbody)
   906  
   907  	case ORANGE:
   908  		if fmtmode == FErr {
   909  			f += "for loop"
   910  			break
   911  		}
   912  
   913  		if n.List == nil {
   914  			f += fmt.Sprintf("for range %v { %v }", n.Right, n.Nbody)
   915  			break
   916  		}
   917  
   918  		f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), n.Right, n.Nbody)
   919  
   920  	case OSELECT, OSWITCH:
   921  		if fmtmode == FErr {
   922  			f += fmt.Sprintf("%v statement", Oconv(int(n.Op), 0))
   923  			break
   924  		}
   925  
   926  		f += Oconv(int(n.Op), obj.FmtSharp)
   927  		if simpleinit {
   928  			f += fmt.Sprintf(" %v;", n.Ninit.N)
   929  		}
   930  		if n.Left != nil {
   931  			f += Nconv(n.Left, 0)
   932  		}
   933  
   934  		f += fmt.Sprintf(" { %v }", n.List)
   935  
   936  	case OCASE, OXCASE:
   937  		if n.List != nil {
   938  			f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), n.Nbody)
   939  		} else {
   940  			f += fmt.Sprintf("default: %v", n.Nbody)
   941  		}
   942  
   943  	case OBREAK,
   944  		OCONTINUE,
   945  		OGOTO,
   946  		OFALL,
   947  		OXFALL:
   948  		if n.Left != nil {
   949  			f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), n.Left)
   950  		} else {
   951  			f += Oconv(int(n.Op), obj.FmtSharp)
   952  		}
   953  
   954  	case OEMPTY:
   955  		break
   956  
   957  	case OLABEL:
   958  		f += fmt.Sprintf("%v: ", n.Left)
   959  	}
   960  
   961  ret:
   962  	if extrablock {
   963  		f += "}"
   964  	}
   965  
   966  	return f
   967  }
   968  
   969  var opprec = []int{
   970  	OAPPEND:       8,
   971  	OARRAYBYTESTR: 8,
   972  	OARRAYLIT:     8,
   973  	OARRAYRUNESTR: 8,
   974  	OCALLFUNC:     8,
   975  	OCALLINTER:    8,
   976  	OCALLMETH:     8,
   977  	OCALL:         8,
   978  	OCAP:          8,
   979  	OCLOSE:        8,
   980  	OCONVIFACE:    8,
   981  	OCONVNOP:      8,
   982  	OCONV:         8,
   983  	OCOPY:         8,
   984  	ODELETE:       8,
   985  	OGETG:         8,
   986  	OLEN:          8,
   987  	OLITERAL:      8,
   988  	OMAKESLICE:    8,
   989  	OMAKE:         8,
   990  	OMAPLIT:       8,
   991  	ONAME:         8,
   992  	ONEW:          8,
   993  	ONONAME:       8,
   994  	OPACK:         8,
   995  	OPANIC:        8,
   996  	OPAREN:        8,
   997  	OPRINTN:       8,
   998  	OPRINT:        8,
   999  	ORUNESTR:      8,
  1000  	OSTRARRAYBYTE: 8,
  1001  	OSTRARRAYRUNE: 8,
  1002  	OSTRUCTLIT:    8,
  1003  	OTARRAY:       8,
  1004  	OTCHAN:        8,
  1005  	OTFUNC:        8,
  1006  	OTINTER:       8,
  1007  	OTMAP:         8,
  1008  	OTSTRUCT:      8,
  1009  	OINDEXMAP:     8,
  1010  	OINDEX:        8,
  1011  	OSLICE:        8,
  1012  	OSLICESTR:     8,
  1013  	OSLICEARR:     8,
  1014  	OSLICE3:       8,
  1015  	OSLICE3ARR:    8,
  1016  	ODOTINTER:     8,
  1017  	ODOTMETH:      8,
  1018  	ODOTPTR:       8,
  1019  	ODOTTYPE2:     8,
  1020  	ODOTTYPE:      8,
  1021  	ODOT:          8,
  1022  	OXDOT:         8,
  1023  	OCALLPART:     8,
  1024  	OPLUS:         7,
  1025  	ONOT:          7,
  1026  	OCOM:          7,
  1027  	OMINUS:        7,
  1028  	OADDR:         7,
  1029  	OIND:          7,
  1030  	ORECV:         7,
  1031  	OMUL:          6,
  1032  	ODIV:          6,
  1033  	OMOD:          6,
  1034  	OLSH:          6,
  1035  	ORSH:          6,
  1036  	OAND:          6,
  1037  	OANDNOT:       6,
  1038  	OADD:          5,
  1039  	OSUB:          5,
  1040  	OOR:           5,
  1041  	OXOR:          5,
  1042  	OEQ:           4,
  1043  	OLT:           4,
  1044  	OLE:           4,
  1045  	OGE:           4,
  1046  	OGT:           4,
  1047  	ONE:           4,
  1048  	OCMPSTR:       4,
  1049  	OCMPIFACE:     4,
  1050  	OSEND:         3,
  1051  	OANDAND:       2,
  1052  	OOROR:         1,
  1053  	// Statements handled by stmtfmt
  1054  	OAS:         -1,
  1055  	OAS2:        -1,
  1056  	OAS2DOTTYPE: -1,
  1057  	OAS2FUNC:    -1,
  1058  	OAS2MAPR:    -1,
  1059  	OAS2RECV:    -1,
  1060  	OASOP:       -1,
  1061  	OBREAK:      -1,
  1062  	OCASE:       -1,
  1063  	OCONTINUE:   -1,
  1064  	ODCL:        -1,
  1065  	ODCLFIELD:   -1,
  1066  	ODEFER:      -1,
  1067  	OEMPTY:      -1,
  1068  	OFALL:       -1,
  1069  	OFOR:        -1,
  1070  	OGOTO:       -1,
  1071  	OIF:         -1,
  1072  	OLABEL:      -1,
  1073  	OPROC:       -1,
  1074  	ORANGE:      -1,
  1075  	ORETURN:     -1,
  1076  	OSELECT:     -1,
  1077  	OSWITCH:     -1,
  1078  	OXCASE:      -1,
  1079  	OXFALL:      -1,
  1080  	OEND:        0,
  1081  }
  1082  
  1083  func exprfmt(n *Node, prec int) string {
  1084  	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
  1085  		n = n.Left
  1086  	}
  1087  
  1088  	if n == nil {
  1089  		return "<N>"
  1090  	}
  1091  
  1092  	nprec := opprec[n.Op]
  1093  	if n.Op == OTYPE && n.Sym != nil {
  1094  		nprec = 8
  1095  	}
  1096  
  1097  	if prec > nprec {
  1098  		return fmt.Sprintf("(%v)", n)
  1099  	}
  1100  
  1101  	switch n.Op {
  1102  	case OPAREN:
  1103  		return fmt.Sprintf("(%v)", n.Left)
  1104  
  1105  	case ODDDARG:
  1106  		return "... argument"
  1107  
  1108  	case OREGISTER:
  1109  		return obj.Rconv(int(n.Reg))
  1110  
  1111  	case OLITERAL: // this is a bit of a mess
  1112  		if fmtmode == FErr {
  1113  			if n.Orig != nil && n.Orig != n {
  1114  				return exprfmt(n.Orig, prec)
  1115  			}
  1116  			if n.Sym != nil {
  1117  				return Sconv(n.Sym, 0)
  1118  			}
  1119  		}
  1120  		if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
  1121  			return exprfmt(n.Orig, prec)
  1122  		}
  1123  		if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != idealbool && n.Type != idealstring {
  1124  			// Need parens when type begins with what might
  1125  			// be misinterpreted as a unary operator: * or <-.
  1126  			if Isptr[n.Type.Etype] || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) {
  1127  				return fmt.Sprintf("(%v)(%v)", n.Type, Vconv(n.Val(), 0))
  1128  			} else {
  1129  				return fmt.Sprintf("%v(%v)", n.Type, Vconv(n.Val(), 0))
  1130  			}
  1131  		}
  1132  
  1133  		return Vconv(n.Val(), 0)
  1134  
  1135  	// Special case: name used as local variable in export.
  1136  	// _ becomes ~b%d internally; print as _ for export
  1137  	case ONAME:
  1138  		if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
  1139  			return "_"
  1140  		}
  1141  		if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
  1142  			return fmt.Sprintf("%v·%d", n.Sym, n.Name.Vargen)
  1143  		}
  1144  
  1145  		// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
  1146  		// but for export, this should be rendered as (*pkg.T).meth.
  1147  		// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
  1148  		if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
  1149  			if Isptr[n.Left.Type.Etype] {
  1150  				return fmt.Sprintf("(%v).%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
  1151  			} else {
  1152  				return fmt.Sprintf("%v.%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
  1153  			}
  1154  		}
  1155  		fallthrough
  1156  
  1157  	case OPACK, ONONAME:
  1158  		return Sconv(n.Sym, 0)
  1159  
  1160  	case OTYPE:
  1161  		if n.Type == nil && n.Sym != nil {
  1162  			return Sconv(n.Sym, 0)
  1163  		}
  1164  		return Tconv(n.Type, 0)
  1165  
  1166  	case OTARRAY:
  1167  		if n.Left != nil {
  1168  			return fmt.Sprintf("[]%v", n.Left)
  1169  		}
  1170  		var f string
  1171  		f += fmt.Sprintf("[]%v", n.Right)
  1172  		return f // happens before typecheck
  1173  
  1174  	case OTMAP:
  1175  		return fmt.Sprintf("map[%v]%v", n.Left, n.Right)
  1176  
  1177  	case OTCHAN:
  1178  		switch n.Etype {
  1179  		case Crecv:
  1180  			return fmt.Sprintf("<-chan %v", n.Left)
  1181  
  1182  		case Csend:
  1183  			return fmt.Sprintf("chan<- %v", n.Left)
  1184  
  1185  		default:
  1186  			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv {
  1187  				return fmt.Sprintf("chan (%v)", n.Left)
  1188  			} else {
  1189  				return fmt.Sprintf("chan %v", n.Left)
  1190  			}
  1191  		}
  1192  
  1193  	case OTSTRUCT:
  1194  		return "<struct>"
  1195  
  1196  	case OTINTER:
  1197  		return "<inter>"
  1198  
  1199  	case OTFUNC:
  1200  		return "<func>"
  1201  
  1202  	case OCLOSURE:
  1203  		if fmtmode == FErr {
  1204  			return "func literal"
  1205  		}
  1206  		if n.Nbody != nil {
  1207  			return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
  1208  		}
  1209  		return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody)
  1210  
  1211  	case OCOMPLIT:
  1212  		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype]
  1213  		if fmtmode == FErr {
  1214  			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
  1215  				if ptrlit {
  1216  					return fmt.Sprintf("&%v literal", n.Right.Type.Type)
  1217  				} else {
  1218  					return fmt.Sprintf("%v literal", n.Right.Type)
  1219  				}
  1220  			}
  1221  
  1222  			return "composite literal"
  1223  		}
  1224  
  1225  		if fmtmode == FExp && ptrlit {
  1226  			// typecheck has overwritten OIND by OTYPE with pointer type.
  1227  			return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Type, Hconv(n.List, obj.FmtComma))
  1228  		}
  1229  
  1230  		return fmt.Sprintf("(%v{ %v })", n.Right, Hconv(n.List, obj.FmtComma))
  1231  
  1232  	case OPTRLIT:
  1233  		if fmtmode == FExp && n.Left.Implicit {
  1234  			return Nconv(n.Left, 0)
  1235  		}
  1236  		return fmt.Sprintf("&%v", n.Left)
  1237  
  1238  	case OSTRUCTLIT:
  1239  		if fmtmode == FExp { // requires special handling of field names
  1240  			var f string
  1241  			if n.Implicit {
  1242  				f += "{"
  1243  			} else {
  1244  				f += fmt.Sprintf("(%v{", n.Type)
  1245  			}
  1246  			for l := n.List; l != nil; l = l.Next {
  1247  				f += fmt.Sprintf(" %v:%v", Sconv(l.N.Left.Sym, obj.FmtShort|obj.FmtByte), l.N.Right)
  1248  
  1249  				if l.Next != nil {
  1250  					f += ","
  1251  				} else {
  1252  					f += " "
  1253  				}
  1254  			}
  1255  
  1256  			if !n.Implicit {
  1257  				f += "})"
  1258  				return f
  1259  			}
  1260  			f += "}"
  1261  			return f
  1262  		}
  1263  		fallthrough
  1264  
  1265  	case OARRAYLIT, OMAPLIT:
  1266  		if fmtmode == FErr {
  1267  			return fmt.Sprintf("%v literal", n.Type)
  1268  		}
  1269  		if fmtmode == FExp && n.Implicit {
  1270  			return fmt.Sprintf("{ %v }", Hconv(n.List, obj.FmtComma))
  1271  		}
  1272  		return fmt.Sprintf("(%v{ %v })", n.Type, Hconv(n.List, obj.FmtComma))
  1273  
  1274  	case OKEY:
  1275  		if n.Left != nil && n.Right != nil {
  1276  			if fmtmode == FExp && n.Left.Type != nil && n.Left.Type.Etype == TFIELD {
  1277  				// requires special handling of field names
  1278  				return fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), n.Right)
  1279  			} else {
  1280  				return fmt.Sprintf("%v:%v", n.Left, n.Right)
  1281  			}
  1282  		}
  1283  
  1284  		if n.Left == nil && n.Right != nil {
  1285  			return fmt.Sprintf(":%v", n.Right)
  1286  		}
  1287  		if n.Left != nil && n.Right == nil {
  1288  			return fmt.Sprintf("%v:", n.Left)
  1289  		}
  1290  		return ":"
  1291  
  1292  	case OXDOT,
  1293  		ODOT,
  1294  		ODOTPTR,
  1295  		ODOTINTER,
  1296  		ODOTMETH,
  1297  		OCALLPART:
  1298  		var f string
  1299  		f += exprfmt(n.Left, nprec)
  1300  		if n.Right == nil || n.Right.Sym == nil {
  1301  			f += ".<nil>"
  1302  			return f
  1303  		}
  1304  		f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
  1305  		return f
  1306  
  1307  	case ODOTTYPE, ODOTTYPE2:
  1308  		var f string
  1309  		f += exprfmt(n.Left, nprec)
  1310  		if n.Right != nil {
  1311  			f += fmt.Sprintf(".(%v)", n.Right)
  1312  			return f
  1313  		}
  1314  		f += fmt.Sprintf(".(%v)", n.Type)
  1315  		return f
  1316  
  1317  	case OINDEX,
  1318  		OINDEXMAP,
  1319  		OSLICE,
  1320  		OSLICESTR,
  1321  		OSLICEARR,
  1322  		OSLICE3,
  1323  		OSLICE3ARR:
  1324  		var f string
  1325  		f += exprfmt(n.Left, nprec)
  1326  		f += fmt.Sprintf("[%v]", n.Right)
  1327  		return f
  1328  
  1329  	case OCOPY, OCOMPLEX:
  1330  		return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), n.Left, n.Right)
  1331  
  1332  	case OCONV,
  1333  		OCONVIFACE,
  1334  		OCONVNOP,
  1335  		OARRAYBYTESTR,
  1336  		OARRAYRUNESTR,
  1337  		OSTRARRAYBYTE,
  1338  		OSTRARRAYRUNE,
  1339  		ORUNESTR:
  1340  		if n.Type == nil || n.Type.Sym == nil {
  1341  			return fmt.Sprintf("(%v)(%v)", n.Type, n.Left)
  1342  		}
  1343  		if n.Left != nil {
  1344  			return fmt.Sprintf("%v(%v)", n.Type, n.Left)
  1345  		}
  1346  		return fmt.Sprintf("%v(%v)", n.Type, Hconv(n.List, obj.FmtComma))
  1347  
  1348  	case OREAL,
  1349  		OIMAG,
  1350  		OAPPEND,
  1351  		OCAP,
  1352  		OCLOSE,
  1353  		ODELETE,
  1354  		OLEN,
  1355  		OMAKE,
  1356  		ONEW,
  1357  		OPANIC,
  1358  		ORECOVER,
  1359  		OPRINT,
  1360  		OPRINTN:
  1361  		if n.Left != nil {
  1362  			return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), n.Left)
  1363  		}
  1364  		if n.Isddd {
  1365  			return fmt.Sprintf("%v(%v...)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
  1366  		}
  1367  		return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
  1368  
  1369  	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
  1370  		var f string
  1371  		f += exprfmt(n.Left, nprec)
  1372  		if n.Isddd {
  1373  			f += fmt.Sprintf("(%v...)", Hconv(n.List, obj.FmtComma))
  1374  			return f
  1375  		}
  1376  		f += fmt.Sprintf("(%v)", Hconv(n.List, obj.FmtComma))
  1377  		return f
  1378  
  1379  	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
  1380  		if n.List != nil { // pre-typecheck
  1381  			return fmt.Sprintf("make(%v, %v)", n.Type, Hconv(n.List, obj.FmtComma))
  1382  		}
  1383  		if n.Right != nil {
  1384  			return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right)
  1385  		}
  1386  		if n.Left != nil && (n.Op == OMAKESLICE || !isideal(n.Left.Type)) {
  1387  			return fmt.Sprintf("make(%v, %v)", n.Type, n.Left)
  1388  		}
  1389  		return fmt.Sprintf("make(%v)", n.Type)
  1390  
  1391  		// Unary
  1392  	case OPLUS,
  1393  		OMINUS,
  1394  		OADDR,
  1395  		OCOM,
  1396  		OIND,
  1397  		ONOT,
  1398  		ORECV:
  1399  		var f string
  1400  		if n.Left.Op == n.Op {
  1401  			f += fmt.Sprintf("%v ", Oconv(int(n.Op), obj.FmtSharp))
  1402  		} else {
  1403  			f += Oconv(int(n.Op), obj.FmtSharp)
  1404  		}
  1405  		f += exprfmt(n.Left, nprec+1)
  1406  		return f
  1407  
  1408  		// Binary
  1409  	case OADD,
  1410  		OAND,
  1411  		OANDAND,
  1412  		OANDNOT,
  1413  		ODIV,
  1414  		OEQ,
  1415  		OGE,
  1416  		OGT,
  1417  		OLE,
  1418  		OLT,
  1419  		OLSH,
  1420  		OMOD,
  1421  		OMUL,
  1422  		ONE,
  1423  		OOR,
  1424  		OOROR,
  1425  		ORSH,
  1426  		OSEND,
  1427  		OSUB,
  1428  		OXOR:
  1429  		var f string
  1430  		f += exprfmt(n.Left, nprec)
  1431  
  1432  		f += fmt.Sprintf(" %v ", Oconv(int(n.Op), obj.FmtSharp))
  1433  		f += exprfmt(n.Right, nprec+1)
  1434  		return f
  1435  
  1436  	case OADDSTR:
  1437  		var f string
  1438  		for l := n.List; l != nil; l = l.Next {
  1439  			if l != n.List {
  1440  				f += " + "
  1441  			}
  1442  			f += exprfmt(l.N, nprec)
  1443  		}
  1444  
  1445  		return f
  1446  
  1447  	case OCMPSTR, OCMPIFACE:
  1448  		var f string
  1449  		f += exprfmt(n.Left, nprec)
  1450  		// TODO(marvin): Fix Node.EType type union.
  1451  		f += fmt.Sprintf(" %v ", Oconv(int(n.Etype), obj.FmtSharp))
  1452  		f += exprfmt(n.Right, nprec+1)
  1453  		return f
  1454  	}
  1455  
  1456  	return fmt.Sprintf("<node %v>", Oconv(int(n.Op), 0))
  1457  }
  1458  
  1459  func nodefmt(n *Node, flag int) string {
  1460  	t := n.Type
  1461  
  1462  	// we almost always want the original, except in export mode for literals
  1463  	// this saves the importer some work, and avoids us having to redo some
  1464  	// special casing for package unsafe
  1465  	if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
  1466  		n = n.Orig
  1467  	}
  1468  
  1469  	if flag&obj.FmtLong != 0 && t != nil {
  1470  		if t.Etype == TNIL {
  1471  			return "nil"
  1472  		} else {
  1473  			return fmt.Sprintf("%v (type %v)", n, t)
  1474  		}
  1475  	}
  1476  
  1477  	// TODO inlining produces expressions with ninits. we can't print these yet.
  1478  
  1479  	if opprec[n.Op] < 0 {
  1480  		return stmtfmt(n)
  1481  	}
  1482  
  1483  	return exprfmt(n, 0)
  1484  }
  1485  
  1486  var dumpdepth int
  1487  
  1488  func indent(buf *bytes.Buffer) {
  1489  	buf.WriteString("\n")
  1490  	for i := 0; i < dumpdepth; i++ {
  1491  		buf.WriteString(".   ")
  1492  	}
  1493  }
  1494  
  1495  func nodedump(n *Node, flag int) string {
  1496  	if n == nil {
  1497  		return ""
  1498  	}
  1499  
  1500  	recur := flag&obj.FmtShort == 0
  1501  
  1502  	var buf bytes.Buffer
  1503  	if recur {
  1504  		indent(&buf)
  1505  		if dumpdepth > 10 {
  1506  			buf.WriteString("...")
  1507  			return buf.String()
  1508  		}
  1509  
  1510  		if n.Ninit != nil {
  1511  			fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), n.Ninit)
  1512  			indent(&buf)
  1513  		}
  1514  	}
  1515  
  1516  	switch n.Op {
  1517  	default:
  1518  		fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
  1519  
  1520  	case OREGISTER, OINDREG:
  1521  		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Reg)), Jconv(n, 0))
  1522  
  1523  	case OLITERAL:
  1524  		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Vconv(n.Val(), 0), Jconv(n, 0))
  1525  
  1526  	case ONAME, ONONAME:
  1527  		if n.Sym != nil {
  1528  			fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0))
  1529  		} else {
  1530  			fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
  1531  		}
  1532  		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
  1533  			indent(&buf)
  1534  			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
  1535  		}
  1536  
  1537  	case OASOP:
  1538  		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0))
  1539  
  1540  	case OTYPE:
  1541  		fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0), n.Type)
  1542  		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
  1543  			indent(&buf)
  1544  			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
  1545  		}
  1546  	}
  1547  
  1548  	if n.Sym != nil && n.Op != ONAME {
  1549  		fmt.Fprintf(&buf, " %v", n.Sym)
  1550  	}
  1551  
  1552  	if n.Type != nil {
  1553  		fmt.Fprintf(&buf, " %v", n.Type)
  1554  	}
  1555  
  1556  	if recur {
  1557  		if n.Left != nil {
  1558  			buf.WriteString(Nconv(n.Left, 0))
  1559  		}
  1560  		if n.Right != nil {
  1561  			buf.WriteString(Nconv(n.Right, 0))
  1562  		}
  1563  		if n.List != nil {
  1564  			indent(&buf)
  1565  			fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), n.List)
  1566  		}
  1567  
  1568  		if n.Rlist != nil {
  1569  			indent(&buf)
  1570  			fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), n.Rlist)
  1571  		}
  1572  
  1573  		if n.Nbody != nil {
  1574  			indent(&buf)
  1575  			fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), n.Nbody)
  1576  		}
  1577  	}
  1578  
  1579  	return buf.String()
  1580  }
  1581  
  1582  func (s *Sym) String() string {
  1583  	return Sconv(s, 0)
  1584  }
  1585  
  1586  // Fmt "%S": syms
  1587  // Flags:  "%hS" suppresses qualifying with package
  1588  func Sconv(s *Sym, flag int) string {
  1589  	if flag&obj.FmtLong != 0 {
  1590  		panic("linksymfmt")
  1591  	}
  1592  
  1593  	if s == nil {
  1594  		return "<S>"
  1595  	}
  1596  
  1597  	if s.Name == "_" {
  1598  		return "_"
  1599  	}
  1600  
  1601  	sf := flag
  1602  	sm := setfmode(&flag)
  1603  	str := symfmt(s, flag)
  1604  	flag = sf
  1605  	fmtmode = sm
  1606  	return str
  1607  }
  1608  
  1609  func (t *Type) String() string {
  1610  	return Tconv(t, 0)
  1611  }
  1612  
  1613  // Fmt "%T": types.
  1614  // Flags: 'l' print definition, not name
  1615  //	  'h' omit 'func' and receiver from function types, short type names
  1616  //	  'u' package name, not prefix (FTypeId mode, sticky)
  1617  func Tconv(t *Type, flag int) string {
  1618  	if t == nil {
  1619  		return "<T>"
  1620  	}
  1621  
  1622  	if t.Trecur > 4 {
  1623  		return "<...>"
  1624  	}
  1625  
  1626  	t.Trecur++
  1627  	sf := flag
  1628  	sm := setfmode(&flag)
  1629  
  1630  	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
  1631  		fmtpkgpfx++
  1632  	}
  1633  	if fmtpkgpfx != 0 {
  1634  		flag |= obj.FmtUnsigned
  1635  	}
  1636  
  1637  	str := typefmt(t, flag)
  1638  
  1639  	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
  1640  		fmtpkgpfx--
  1641  	}
  1642  
  1643  	flag = sf
  1644  	fmtmode = sm
  1645  	t.Trecur--
  1646  	return str
  1647  }
  1648  
  1649  func (n *Node) String() string {
  1650  	return Nconv(n, 0)
  1651  }
  1652  
  1653  // Fmt '%N': Nodes.
  1654  // Flags: 'l' suffix with "(type %T)" where possible
  1655  //	  '+h' in debug mode, don't recurse, no multiline output
  1656  func Nconv(n *Node, flag int) string {
  1657  	if n == nil {
  1658  		return "<N>"
  1659  	}
  1660  	sf := flag
  1661  	sm := setfmode(&flag)
  1662  
  1663  	var str string
  1664  	switch fmtmode {
  1665  	case FErr, FExp:
  1666  		str = nodefmt(n, flag)
  1667  
  1668  	case FDbg:
  1669  		dumpdepth++
  1670  		str = nodedump(n, flag)
  1671  		dumpdepth--
  1672  
  1673  	default:
  1674  		Fatalf("unhandled %%N mode")
  1675  	}
  1676  
  1677  	flag = sf
  1678  	fmtmode = sm
  1679  	return str
  1680  }
  1681  
  1682  func (l *NodeList) String() string {
  1683  	return Hconv(l, 0)
  1684  }
  1685  
  1686  // Fmt '%H': NodeList.
  1687  // Flags: all those of %N plus ',': separate with comma's instead of semicolons.
  1688  func Hconv(l *NodeList, flag int) string {
  1689  	if l == nil && fmtmode == FDbg {
  1690  		return "<nil>"
  1691  	}
  1692  
  1693  	sf := flag
  1694  	sm := setfmode(&flag)
  1695  	sep := "; "
  1696  	if fmtmode == FDbg {
  1697  		sep = "\n"
  1698  	} else if flag&obj.FmtComma != 0 {
  1699  		sep = ", "
  1700  	}
  1701  
  1702  	var buf bytes.Buffer
  1703  	for ; l != nil; l = l.Next {
  1704  		buf.WriteString(Nconv(l.N, 0))
  1705  		if l.Next != nil {
  1706  			buf.WriteString(sep)
  1707  		}
  1708  	}
  1709  
  1710  	flag = sf
  1711  	fmtmode = sm
  1712  	return buf.String()
  1713  }
  1714  
  1715  func dumplist(s string, l *NodeList) {
  1716  	fmt.Printf("%s%v\n", s, Hconv(l, obj.FmtSign))
  1717  }
  1718  
  1719  func Dump(s string, n *Node) {
  1720  	fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, obj.FmtSign))
  1721  }