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