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