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