github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/compile/internal/gc/fmt.go (about)

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