github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/fmt.go (about)

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