Source file src/cmd/compile/internal/ir/fmt.go

     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 ir
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/constant"
    11  	"io"
    12  	"math"
    13  	"os"
    14  	"path/filepath"
    15  	"reflect"
    16  	"strings"
    17  
    18  	"unicode/utf8"
    19  
    20  	"cmd/compile/internal/base"
    21  	"cmd/compile/internal/types"
    22  	"cmd/internal/src"
    23  )
    24  
    25  // Op
    26  
    27  var OpNames = []string{
    28  	OADDR:        "&",
    29  	OADD:         "+",
    30  	OADDSTR:      "+",
    31  	OALIGNOF:     "unsafe.Alignof",
    32  	OANDAND:      "&&",
    33  	OANDNOT:      "&^",
    34  	OAND:         "&",
    35  	OAPPEND:      "append",
    36  	OAS:          "=",
    37  	OAS2:         "=",
    38  	OBREAK:       "break",
    39  	OCALL:        "function call", // not actual syntax
    40  	OCAP:         "cap",
    41  	OCASE:        "case",
    42  	OCLOSE:       "close",
    43  	OCOMPLEX:     "complex",
    44  	OBITNOT:      "^",
    45  	OCONTINUE:    "continue",
    46  	OCOPY:        "copy",
    47  	ODELETE:      "delete",
    48  	ODEFER:       "defer",
    49  	ODIV:         "/",
    50  	OEQ:          "==",
    51  	OFALL:        "fallthrough",
    52  	OFOR:         "for",
    53  	OFORUNTIL:    "foruntil", // not actual syntax; used to avoid off-end pointer live on backedge.892
    54  	OGE:          ">=",
    55  	OGOTO:        "goto",
    56  	OGT:          ">",
    57  	OIF:          "if",
    58  	OIMAG:        "imag",
    59  	OINLMARK:     "inlmark",
    60  	ODEREF:       "*",
    61  	OLEN:         "len",
    62  	OLE:          "<=",
    63  	OLSH:         "<<",
    64  	OLT:          "<",
    65  	OMAKE:        "make",
    66  	ONEG:         "-",
    67  	OMOD:         "%",
    68  	OMUL:         "*",
    69  	ONEW:         "new",
    70  	ONE:          "!=",
    71  	ONOT:         "!",
    72  	OOFFSETOF:    "unsafe.Offsetof",
    73  	OOROR:        "||",
    74  	OOR:          "|",
    75  	OPANIC:       "panic",
    76  	OPLUS:        "+",
    77  	OPRINTN:      "println",
    78  	OPRINT:       "print",
    79  	ORANGE:       "range",
    80  	OREAL:        "real",
    81  	ORECV:        "<-",
    82  	ORECOVER:     "recover",
    83  	ORETURN:      "return",
    84  	ORSH:         ">>",
    85  	OSELECT:      "select",
    86  	OSEND:        "<-",
    87  	OSIZEOF:      "unsafe.Sizeof",
    88  	OSUB:         "-",
    89  	OSWITCH:      "switch",
    90  	OUNSAFEADD:   "unsafe.Add",
    91  	OUNSAFESLICE: "unsafe.Slice",
    92  	OXOR:         "^",
    93  }
    94  
    95  // GoString returns the Go syntax for the Op, or else its name.
    96  func (o Op) GoString() string {
    97  	if int(o) < len(OpNames) && OpNames[o] != "" {
    98  		return OpNames[o]
    99  	}
   100  	return o.String()
   101  }
   102  
   103  // Format implements formatting for an Op.
   104  // The valid formats are:
   105  //
   106  //	%v	Go syntax ("+", "<-", "print")
   107  //	%+v	Debug syntax ("ADD", "RECV", "PRINT")
   108  //
   109  func (o Op) Format(s fmt.State, verb rune) {
   110  	switch verb {
   111  	default:
   112  		fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))
   113  	case 'v':
   114  		if s.Flag('+') {
   115  			// %+v is OMUL instead of "*"
   116  			io.WriteString(s, o.String())
   117  			return
   118  		}
   119  		io.WriteString(s, o.GoString())
   120  	}
   121  }
   122  
   123  // Node
   124  
   125  // FmtNode implements formatting for a Node n.
   126  // Every Node implementation must define a Format method that calls FmtNode.
   127  // The valid formats are:
   128  //
   129  //	%v	Go syntax
   130  //	%L	Go syntax followed by " (type T)" if type is known.
   131  //	%+v	Debug syntax, as in Dump.
   132  //
   133  func fmtNode(n Node, s fmt.State, verb rune) {
   134  	// %+v prints Dump.
   135  	// Otherwise we print Go syntax.
   136  	if s.Flag('+') && verb == 'v' {
   137  		dumpNode(s, n, 1)
   138  		return
   139  	}
   140  
   141  	if verb != 'v' && verb != 'S' && verb != 'L' {
   142  		fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
   143  		return
   144  	}
   145  
   146  	if n == nil {
   147  		fmt.Fprint(s, "<nil>")
   148  		return
   149  	}
   150  
   151  	t := n.Type()
   152  	if verb == 'L' && t != nil {
   153  		if t.Kind() == types.TNIL {
   154  			fmt.Fprint(s, "nil")
   155  		} else if n.Op() == ONAME && n.Name().AutoTemp() {
   156  			fmt.Fprintf(s, "%v value", t)
   157  		} else {
   158  			fmt.Fprintf(s, "%v (type %v)", n, t)
   159  		}
   160  		return
   161  	}
   162  
   163  	// TODO inlining produces expressions with ninits. we can't print these yet.
   164  
   165  	if OpPrec[n.Op()] < 0 {
   166  		stmtFmt(n, s)
   167  		return
   168  	}
   169  
   170  	exprFmt(n, s, 0)
   171  }
   172  
   173  var OpPrec = []int{
   174  	OALIGNOF:       8,
   175  	OAPPEND:        8,
   176  	OBYTES2STR:     8,
   177  	OARRAYLIT:      8,
   178  	OSLICELIT:      8,
   179  	ORUNES2STR:     8,
   180  	OCALLFUNC:      8,
   181  	OCALLINTER:     8,
   182  	OCALLMETH:      8,
   183  	OCALL:          8,
   184  	OCAP:           8,
   185  	OCLOSE:         8,
   186  	OCOMPLIT:       8,
   187  	OCONVIFACE:     8,
   188  	OCONVIDATA:     8,
   189  	OCONVNOP:       8,
   190  	OCONV:          8,
   191  	OCOPY:          8,
   192  	ODELETE:        8,
   193  	OGETG:          8,
   194  	OLEN:           8,
   195  	OLITERAL:       8,
   196  	OMAKESLICE:     8,
   197  	OMAKESLICECOPY: 8,
   198  	OMAKE:          8,
   199  	OMAPLIT:        8,
   200  	ONAME:          8,
   201  	ONEW:           8,
   202  	ONIL:           8,
   203  	ONONAME:        8,
   204  	OOFFSETOF:      8,
   205  	OPACK:          8,
   206  	OPANIC:         8,
   207  	OPAREN:         8,
   208  	OPRINTN:        8,
   209  	OPRINT:         8,
   210  	ORUNESTR:       8,
   211  	OSIZEOF:        8,
   212  	OSLICE2ARRPTR:  8,
   213  	OSTR2BYTES:     8,
   214  	OSTR2RUNES:     8,
   215  	OSTRUCTLIT:     8,
   216  	OTARRAY:        8,
   217  	OTSLICE:        8,
   218  	OTCHAN:         8,
   219  	OTFUNC:         8,
   220  	OTINTER:        8,
   221  	OTMAP:          8,
   222  	OTSTRUCT:       8,
   223  	OTYPE:          8,
   224  	OUNSAFEADD:     8,
   225  	OUNSAFESLICE:   8,
   226  	OINDEXMAP:      8,
   227  	OINDEX:         8,
   228  	OSLICE:         8,
   229  	OSLICESTR:      8,
   230  	OSLICEARR:      8,
   231  	OSLICE3:        8,
   232  	OSLICE3ARR:     8,
   233  	OSLICEHEADER:   8,
   234  	ODOTINTER:      8,
   235  	ODOTMETH:       8,
   236  	ODOTPTR:        8,
   237  	ODOTTYPE2:      8,
   238  	ODOTTYPE:       8,
   239  	ODOT:           8,
   240  	OXDOT:          8,
   241  	OMETHVALUE:     8,
   242  	OMETHEXPR:      8,
   243  	OPLUS:          7,
   244  	ONOT:           7,
   245  	OBITNOT:        7,
   246  	ONEG:           7,
   247  	OADDR:          7,
   248  	ODEREF:         7,
   249  	ORECV:          7,
   250  	OMUL:           6,
   251  	ODIV:           6,
   252  	OMOD:           6,
   253  	OLSH:           6,
   254  	ORSH:           6,
   255  	OAND:           6,
   256  	OANDNOT:        6,
   257  	OADD:           5,
   258  	OSUB:           5,
   259  	OOR:            5,
   260  	OXOR:           5,
   261  	OEQ:            4,
   262  	OLT:            4,
   263  	OLE:            4,
   264  	OGE:            4,
   265  	OGT:            4,
   266  	ONE:            4,
   267  	OSEND:          3,
   268  	OANDAND:        2,
   269  	OOROR:          1,
   270  
   271  	// Statements handled by stmtfmt
   272  	OAS:         -1,
   273  	OAS2:        -1,
   274  	OAS2DOTTYPE: -1,
   275  	OAS2FUNC:    -1,
   276  	OAS2MAPR:    -1,
   277  	OAS2RECV:    -1,
   278  	OASOP:       -1,
   279  	OBLOCK:      -1,
   280  	OBREAK:      -1,
   281  	OCASE:       -1,
   282  	OCONTINUE:   -1,
   283  	ODCL:        -1,
   284  	ODEFER:      -1,
   285  	OFALL:       -1,
   286  	OFOR:        -1,
   287  	OFORUNTIL:   -1,
   288  	OGOTO:       -1,
   289  	OIF:         -1,
   290  	OLABEL:      -1,
   291  	OGO:         -1,
   292  	ORANGE:      -1,
   293  	ORETURN:     -1,
   294  	OSELECT:     -1,
   295  	OSWITCH:     -1,
   296  
   297  	OEND: 0,
   298  }
   299  
   300  // StmtWithInit reports whether op is a statement with an explicit init list.
   301  func StmtWithInit(op Op) bool {
   302  	switch op {
   303  	case OIF, OFOR, OFORUNTIL, OSWITCH:
   304  		return true
   305  	}
   306  	return false
   307  }
   308  
   309  func stmtFmt(n Node, s fmt.State) {
   310  	// NOTE(rsc): This code used to support the text-based
   311  	// which was more aggressive about printing full Go syntax
   312  	// (for example, an actual loop instead of "for loop").
   313  	// The code is preserved for now in case we want to expand
   314  	// any of those shortenings later. Or maybe we will delete
   315  	// the code. But for now, keep it.
   316  	const exportFormat = false
   317  
   318  	// some statements allow for an init, but at most one,
   319  	// but we may have an arbitrary number added, eg by typecheck
   320  	// and inlining. If it doesn't fit the syntax, emit an enclosing
   321  	// block starting with the init statements.
   322  
   323  	// if we can just say "for" n->ninit; ... then do so
   324  	simpleinit := len(n.Init()) == 1 && len(n.Init()[0].Init()) == 0 && StmtWithInit(n.Op())
   325  
   326  	// otherwise, print the inits as separate statements
   327  	complexinit := len(n.Init()) != 0 && !simpleinit && exportFormat
   328  
   329  	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
   330  	extrablock := complexinit && StmtWithInit(n.Op())
   331  
   332  	if extrablock {
   333  		fmt.Fprint(s, "{")
   334  	}
   335  
   336  	if complexinit {
   337  		fmt.Fprintf(s, " %v; ", n.Init())
   338  	}
   339  
   340  	switch n.Op() {
   341  	case ODCL:
   342  		n := n.(*Decl)
   343  		fmt.Fprintf(s, "var %v %v", n.X.Sym(), n.X.Type())
   344  
   345  	// Don't export "v = <N>" initializing statements, hope they're always
   346  	// preceded by the DCL which will be re-parsed and typechecked to reproduce
   347  	// the "v = <N>" again.
   348  	case OAS:
   349  		n := n.(*AssignStmt)
   350  		if n.Def && !complexinit {
   351  			fmt.Fprintf(s, "%v := %v", n.X, n.Y)
   352  		} else {
   353  			fmt.Fprintf(s, "%v = %v", n.X, n.Y)
   354  		}
   355  
   356  	case OASOP:
   357  		n := n.(*AssignOpStmt)
   358  		if n.IncDec {
   359  			if n.AsOp == OADD {
   360  				fmt.Fprintf(s, "%v++", n.X)
   361  			} else {
   362  				fmt.Fprintf(s, "%v--", n.X)
   363  			}
   364  			break
   365  		}
   366  
   367  		fmt.Fprintf(s, "%v %v= %v", n.X, n.AsOp, n.Y)
   368  
   369  	case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
   370  		n := n.(*AssignListStmt)
   371  		if n.Def && !complexinit {
   372  			fmt.Fprintf(s, "%.v := %.v", n.Lhs, n.Rhs)
   373  		} else {
   374  			fmt.Fprintf(s, "%.v = %.v", n.Lhs, n.Rhs)
   375  		}
   376  
   377  	case OBLOCK:
   378  		n := n.(*BlockStmt)
   379  		if len(n.List) != 0 {
   380  			fmt.Fprintf(s, "%v", n.List)
   381  		}
   382  
   383  	case ORETURN:
   384  		n := n.(*ReturnStmt)
   385  		fmt.Fprintf(s, "return %.v", n.Results)
   386  
   387  	case OTAILCALL:
   388  		n := n.(*TailCallStmt)
   389  		fmt.Fprintf(s, "tailcall %v", n.Call)
   390  
   391  	case OINLMARK:
   392  		n := n.(*InlineMarkStmt)
   393  		fmt.Fprintf(s, "inlmark %d", n.Index)
   394  
   395  	case OGO:
   396  		n := n.(*GoDeferStmt)
   397  		fmt.Fprintf(s, "go %v", n.Call)
   398  
   399  	case ODEFER:
   400  		n := n.(*GoDeferStmt)
   401  		fmt.Fprintf(s, "defer %v", n.Call)
   402  
   403  	case OIF:
   404  		n := n.(*IfStmt)
   405  		if simpleinit {
   406  			fmt.Fprintf(s, "if %v; %v { %v }", n.Init()[0], n.Cond, n.Body)
   407  		} else {
   408  			fmt.Fprintf(s, "if %v { %v }", n.Cond, n.Body)
   409  		}
   410  		if len(n.Else) != 0 {
   411  			fmt.Fprintf(s, " else { %v }", n.Else)
   412  		}
   413  
   414  	case OFOR, OFORUNTIL:
   415  		n := n.(*ForStmt)
   416  		opname := "for"
   417  		if n.Op() == OFORUNTIL {
   418  			opname = "foruntil"
   419  		}
   420  		if !exportFormat { // TODO maybe only if FmtShort, same below
   421  			fmt.Fprintf(s, "%s loop", opname)
   422  			break
   423  		}
   424  
   425  		fmt.Fprint(s, opname)
   426  		if simpleinit {
   427  			fmt.Fprintf(s, " %v;", n.Init()[0])
   428  		} else if n.Post != nil {
   429  			fmt.Fprint(s, " ;")
   430  		}
   431  
   432  		if n.Cond != nil {
   433  			fmt.Fprintf(s, " %v", n.Cond)
   434  		}
   435  
   436  		if n.Post != nil {
   437  			fmt.Fprintf(s, "; %v", n.Post)
   438  		} else if simpleinit {
   439  			fmt.Fprint(s, ";")
   440  		}
   441  
   442  		if n.Op() == OFORUNTIL && len(n.Late) != 0 {
   443  			fmt.Fprintf(s, "; %v", n.Late)
   444  		}
   445  
   446  		fmt.Fprintf(s, " { %v }", n.Body)
   447  
   448  	case ORANGE:
   449  		n := n.(*RangeStmt)
   450  		if !exportFormat {
   451  			fmt.Fprint(s, "for loop")
   452  			break
   453  		}
   454  
   455  		fmt.Fprint(s, "for")
   456  		if n.Key != nil {
   457  			fmt.Fprintf(s, " %v", n.Key)
   458  			if n.Value != nil {
   459  				fmt.Fprintf(s, ", %v", n.Value)
   460  			}
   461  			fmt.Fprint(s, " =")
   462  		}
   463  		fmt.Fprintf(s, " range %v { %v }", n.X, n.Body)
   464  
   465  	case OSELECT:
   466  		n := n.(*SelectStmt)
   467  		if !exportFormat {
   468  			fmt.Fprintf(s, "%v statement", n.Op())
   469  			break
   470  		}
   471  		fmt.Fprintf(s, "select { %v }", n.Cases)
   472  
   473  	case OSWITCH:
   474  		n := n.(*SwitchStmt)
   475  		if !exportFormat {
   476  			fmt.Fprintf(s, "%v statement", n.Op())
   477  			break
   478  		}
   479  		fmt.Fprintf(s, "switch")
   480  		if simpleinit {
   481  			fmt.Fprintf(s, " %v;", n.Init()[0])
   482  		}
   483  		if n.Tag != nil {
   484  			fmt.Fprintf(s, " %v ", n.Tag)
   485  		}
   486  		fmt.Fprintf(s, " { %v }", n.Cases)
   487  
   488  	case OCASE:
   489  		n := n.(*CaseClause)
   490  		if len(n.List) != 0 {
   491  			fmt.Fprintf(s, "case %.v", n.List)
   492  		} else {
   493  			fmt.Fprint(s, "default")
   494  		}
   495  		fmt.Fprintf(s, ": %v", n.Body)
   496  
   497  	case OBREAK, OCONTINUE, OGOTO, OFALL:
   498  		n := n.(*BranchStmt)
   499  		if n.Label != nil {
   500  			fmt.Fprintf(s, "%v %v", n.Op(), n.Label)
   501  		} else {
   502  			fmt.Fprintf(s, "%v", n.Op())
   503  		}
   504  
   505  	case OLABEL:
   506  		n := n.(*LabelStmt)
   507  		fmt.Fprintf(s, "%v: ", n.Label)
   508  	}
   509  
   510  	if extrablock {
   511  		fmt.Fprint(s, "}")
   512  	}
   513  }
   514  
   515  func exprFmt(n Node, s fmt.State, prec int) {
   516  	// NOTE(rsc): This code used to support the text-based
   517  	// which was more aggressive about printing full Go syntax
   518  	// (for example, an actual loop instead of "for loop").
   519  	// The code is preserved for now in case we want to expand
   520  	// any of those shortenings later. Or maybe we will delete
   521  	// the code. But for now, keep it.
   522  	const exportFormat = false
   523  
   524  	for {
   525  		if n == nil {
   526  			fmt.Fprint(s, "<nil>")
   527  			return
   528  		}
   529  
   530  		// We always want the original, if any.
   531  		if o := Orig(n); o != n {
   532  			n = o
   533  			continue
   534  		}
   535  
   536  		// Skip implicit operations introduced during typechecking.
   537  		switch nn := n; nn.Op() {
   538  		case OADDR:
   539  			nn := nn.(*AddrExpr)
   540  			if nn.Implicit() {
   541  				n = nn.X
   542  				continue
   543  			}
   544  		case ODEREF:
   545  			nn := nn.(*StarExpr)
   546  			if nn.Implicit() {
   547  				n = nn.X
   548  				continue
   549  			}
   550  		case OCONV, OCONVNOP, OCONVIFACE, OCONVIDATA:
   551  			nn := nn.(*ConvExpr)
   552  			if nn.Implicit() {
   553  				n = nn.X
   554  				continue
   555  			}
   556  		}
   557  
   558  		break
   559  	}
   560  
   561  	nprec := OpPrec[n.Op()]
   562  	if n.Op() == OTYPE && n.Type() != nil && n.Type().IsPtr() {
   563  		nprec = OpPrec[ODEREF]
   564  	}
   565  
   566  	if prec > nprec {
   567  		fmt.Fprintf(s, "(%v)", n)
   568  		return
   569  	}
   570  
   571  	if n, ok := n.(*RawOrigExpr); ok {
   572  		fmt.Fprint(s, n.Raw)
   573  		return
   574  	}
   575  
   576  	switch n.Op() {
   577  	case OPAREN:
   578  		n := n.(*ParenExpr)
   579  		fmt.Fprintf(s, "(%v)", n.X)
   580  
   581  	case ONIL:
   582  		fmt.Fprint(s, "nil")
   583  
   584  	case OLITERAL: // this is a bit of a mess
   585  		if !exportFormat && n.Sym() != nil {
   586  			fmt.Fprint(s, n.Sym())
   587  			return
   588  		}
   589  
   590  		needUnparen := false
   591  		if n.Type() != nil && !n.Type().IsUntyped() {
   592  			// Need parens when type begins with what might
   593  			// be misinterpreted as a unary operator: * or <-.
   594  			if n.Type().IsPtr() || (n.Type().IsChan() && n.Type().ChanDir() == types.Crecv) {
   595  				fmt.Fprintf(s, "(%v)(", n.Type())
   596  			} else {
   597  				fmt.Fprintf(s, "%v(", n.Type())
   598  			}
   599  			needUnparen = true
   600  		}
   601  
   602  		if n.Type() == types.UntypedRune {
   603  			switch x, ok := constant.Uint64Val(n.Val()); {
   604  			case !ok:
   605  				fallthrough
   606  			default:
   607  				fmt.Fprintf(s, "('\\x00' + %v)", n.Val())
   608  
   609  			case x < utf8.RuneSelf:
   610  				fmt.Fprintf(s, "%q", x)
   611  
   612  			case x < 1<<16:
   613  				fmt.Fprintf(s, "'\\u%04x'", x)
   614  
   615  			case x <= utf8.MaxRune:
   616  				fmt.Fprintf(s, "'\\U%08x'", x)
   617  			}
   618  		} else {
   619  			fmt.Fprint(s, types.FmtConst(n.Val(), s.Flag('#')))
   620  		}
   621  
   622  		if needUnparen {
   623  			fmt.Fprintf(s, ")")
   624  		}
   625  
   626  	case ODCLFUNC:
   627  		n := n.(*Func)
   628  		if sym := n.Sym(); sym != nil {
   629  			fmt.Fprint(s, sym)
   630  			return
   631  		}
   632  		fmt.Fprintf(s, "<unnamed Func>")
   633  
   634  	case ONAME:
   635  		n := n.(*Name)
   636  		// Special case: name used as local variable in export.
   637  		// _ becomes ~b%d internally; print as _ for export
   638  		if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' {
   639  			fmt.Fprint(s, "_")
   640  			return
   641  		}
   642  		fallthrough
   643  	case OPACK, ONONAME:
   644  		fmt.Fprint(s, n.Sym())
   645  
   646  	case OLINKSYMOFFSET:
   647  		n := n.(*LinksymOffsetExpr)
   648  		fmt.Fprintf(s, "(%v)(%s@%d)", n.Type(), n.Linksym.Name, n.Offset_)
   649  
   650  	case OTYPE:
   651  		if n.Type() == nil && n.Sym() != nil {
   652  			fmt.Fprint(s, n.Sym())
   653  			return
   654  		}
   655  		fmt.Fprintf(s, "%v", n.Type())
   656  
   657  	case OTSLICE:
   658  		n := n.(*SliceType)
   659  		if n.DDD {
   660  			fmt.Fprintf(s, "...%v", n.Elem)
   661  		} else {
   662  			fmt.Fprintf(s, "[]%v", n.Elem) // happens before typecheck
   663  		}
   664  
   665  	case OTARRAY:
   666  		n := n.(*ArrayType)
   667  		if n.Len == nil {
   668  			fmt.Fprintf(s, "[...]%v", n.Elem)
   669  		} else {
   670  			fmt.Fprintf(s, "[%v]%v", n.Len, n.Elem)
   671  		}
   672  
   673  	case OTMAP:
   674  		n := n.(*MapType)
   675  		fmt.Fprintf(s, "map[%v]%v", n.Key, n.Elem)
   676  
   677  	case OTCHAN:
   678  		n := n.(*ChanType)
   679  		switch n.Dir {
   680  		case types.Crecv:
   681  			fmt.Fprintf(s, "<-chan %v", n.Elem)
   682  
   683  		case types.Csend:
   684  			fmt.Fprintf(s, "chan<- %v", n.Elem)
   685  
   686  		default:
   687  			if n.Elem != nil && n.Elem.Op() == OTCHAN && n.Elem.(*ChanType).Dir == types.Crecv {
   688  				fmt.Fprintf(s, "chan (%v)", n.Elem)
   689  			} else {
   690  				fmt.Fprintf(s, "chan %v", n.Elem)
   691  			}
   692  		}
   693  
   694  	case OTSTRUCT:
   695  		fmt.Fprint(s, "<struct>")
   696  
   697  	case OTINTER:
   698  		fmt.Fprint(s, "<inter>")
   699  
   700  	case OTFUNC:
   701  		fmt.Fprint(s, "<func>")
   702  
   703  	case OCLOSURE:
   704  		n := n.(*ClosureExpr)
   705  		if !exportFormat {
   706  			fmt.Fprint(s, "func literal")
   707  			return
   708  		}
   709  		fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func.Body)
   710  
   711  	case OCOMPLIT:
   712  		n := n.(*CompLitExpr)
   713  		if !exportFormat {
   714  			if n.Implicit() {
   715  				fmt.Fprintf(s, "... argument")
   716  				return
   717  			}
   718  			if typ := n.Type(); typ != nil {
   719  				fmt.Fprintf(s, "%v{%s}", typ, ellipsisIf(len(n.List) != 0))
   720  				return
   721  			}
   722  			if n.Ntype != nil {
   723  				fmt.Fprintf(s, "%v{%s}", n.Ntype, ellipsisIf(len(n.List) != 0))
   724  				return
   725  			}
   726  
   727  			fmt.Fprint(s, "composite literal")
   728  			return
   729  		}
   730  		fmt.Fprintf(s, "(%v{ %.v })", n.Ntype, n.List)
   731  
   732  	case OPTRLIT:
   733  		n := n.(*AddrExpr)
   734  		fmt.Fprintf(s, "&%v", n.X)
   735  
   736  	case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
   737  		n := n.(*CompLitExpr)
   738  		if !exportFormat {
   739  			fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(len(n.List) != 0))
   740  			return
   741  		}
   742  		fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List)
   743  
   744  	case OKEY:
   745  		n := n.(*KeyExpr)
   746  		if n.Key != nil && n.Value != nil {
   747  			fmt.Fprintf(s, "%v:%v", n.Key, n.Value)
   748  			return
   749  		}
   750  
   751  		if n.Key == nil && n.Value != nil {
   752  			fmt.Fprintf(s, ":%v", n.Value)
   753  			return
   754  		}
   755  		if n.Key != nil && n.Value == nil {
   756  			fmt.Fprintf(s, "%v:", n.Key)
   757  			return
   758  		}
   759  		fmt.Fprint(s, ":")
   760  
   761  	case OSTRUCTKEY:
   762  		n := n.(*StructKeyExpr)
   763  		fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
   764  
   765  	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OMETHVALUE, OMETHEXPR:
   766  		n := n.(*SelectorExpr)
   767  		exprFmt(n.X, s, nprec)
   768  		if n.Sel == nil {
   769  			fmt.Fprint(s, ".<nil>")
   770  			return
   771  		}
   772  		fmt.Fprintf(s, ".%s", n.Sel.Name)
   773  
   774  	case ODOTTYPE, ODOTTYPE2:
   775  		n := n.(*TypeAssertExpr)
   776  		exprFmt(n.X, s, nprec)
   777  		if n.Ntype != nil {
   778  			fmt.Fprintf(s, ".(%v)", n.Ntype)
   779  			return
   780  		}
   781  		fmt.Fprintf(s, ".(%v)", n.Type())
   782  
   783  	case OINDEX, OINDEXMAP:
   784  		n := n.(*IndexExpr)
   785  		exprFmt(n.X, s, nprec)
   786  		fmt.Fprintf(s, "[%v]", n.Index)
   787  
   788  	case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
   789  		n := n.(*SliceExpr)
   790  		exprFmt(n.X, s, nprec)
   791  		fmt.Fprint(s, "[")
   792  		if n.Low != nil {
   793  			fmt.Fprint(s, n.Low)
   794  		}
   795  		fmt.Fprint(s, ":")
   796  		if n.High != nil {
   797  			fmt.Fprint(s, n.High)
   798  		}
   799  		if n.Op().IsSlice3() {
   800  			fmt.Fprint(s, ":")
   801  			if n.Max != nil {
   802  				fmt.Fprint(s, n.Max)
   803  			}
   804  		}
   805  		fmt.Fprint(s, "]")
   806  
   807  	case OSLICEHEADER:
   808  		n := n.(*SliceHeaderExpr)
   809  		fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.Len, n.Cap)
   810  
   811  	case OCOMPLEX, OCOPY, OUNSAFEADD, OUNSAFESLICE:
   812  		n := n.(*BinaryExpr)
   813  		fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.X, n.Y)
   814  
   815  	case OCONV,
   816  		OCONVIFACE,
   817  		OCONVIDATA,
   818  		OCONVNOP,
   819  		OBYTES2STR,
   820  		ORUNES2STR,
   821  		OSTR2BYTES,
   822  		OSTR2RUNES,
   823  		ORUNESTR,
   824  		OSLICE2ARRPTR:
   825  		n := n.(*ConvExpr)
   826  		if n.Type() == nil || n.Type().Sym() == nil {
   827  			fmt.Fprintf(s, "(%v)", n.Type())
   828  		} else {
   829  			fmt.Fprintf(s, "%v", n.Type())
   830  		}
   831  		fmt.Fprintf(s, "(%v)", n.X)
   832  
   833  	case OREAL,
   834  		OIMAG,
   835  		OCAP,
   836  		OCLOSE,
   837  		OLEN,
   838  		ONEW,
   839  		OPANIC,
   840  		OALIGNOF,
   841  		OOFFSETOF,
   842  		OSIZEOF:
   843  		n := n.(*UnaryExpr)
   844  		fmt.Fprintf(s, "%v(%v)", n.Op(), n.X)
   845  
   846  	case OAPPEND,
   847  		ODELETE,
   848  		OMAKE,
   849  		ORECOVER,
   850  		OPRINT,
   851  		OPRINTN:
   852  		n := n.(*CallExpr)
   853  		if n.IsDDD {
   854  			fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.Args)
   855  			return
   856  		}
   857  		fmt.Fprintf(s, "%v(%.v)", n.Op(), n.Args)
   858  
   859  	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
   860  		n := n.(*CallExpr)
   861  		exprFmt(n.X, s, nprec)
   862  		if n.IsDDD {
   863  			fmt.Fprintf(s, "(%.v...)", n.Args)
   864  			return
   865  		}
   866  		fmt.Fprintf(s, "(%.v)", n.Args)
   867  
   868  	case OINLCALL:
   869  		n := n.(*InlinedCallExpr)
   870  		// TODO(mdempsky): Print Init and/or Body?
   871  		if len(n.ReturnVars) == 1 {
   872  			fmt.Fprintf(s, "%v", n.ReturnVars[0])
   873  			return
   874  		}
   875  		fmt.Fprintf(s, "(.%v)", n.ReturnVars)
   876  
   877  	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
   878  		n := n.(*MakeExpr)
   879  		if n.Cap != nil {
   880  			fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Len, n.Cap)
   881  			return
   882  		}
   883  		if n.Len != nil && (n.Op() == OMAKESLICE || !n.Len.Type().IsUntyped()) {
   884  			fmt.Fprintf(s, "make(%v, %v)", n.Type(), n.Len)
   885  			return
   886  		}
   887  		fmt.Fprintf(s, "make(%v)", n.Type())
   888  
   889  	case OMAKESLICECOPY:
   890  		n := n.(*MakeExpr)
   891  		fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Len, n.Cap)
   892  
   893  	case OPLUS, ONEG, OBITNOT, ONOT, ORECV:
   894  		// Unary
   895  		n := n.(*UnaryExpr)
   896  		fmt.Fprintf(s, "%v", n.Op())
   897  		if n.X != nil && n.X.Op() == n.Op() {
   898  			fmt.Fprint(s, " ")
   899  		}
   900  		exprFmt(n.X, s, nprec+1)
   901  
   902  	case OADDR:
   903  		n := n.(*AddrExpr)
   904  		fmt.Fprintf(s, "%v", n.Op())
   905  		if n.X != nil && n.X.Op() == n.Op() {
   906  			fmt.Fprint(s, " ")
   907  		}
   908  		exprFmt(n.X, s, nprec+1)
   909  
   910  	case ODEREF:
   911  		n := n.(*StarExpr)
   912  		fmt.Fprintf(s, "%v", n.Op())
   913  		exprFmt(n.X, s, nprec+1)
   914  
   915  		// Binary
   916  	case OADD,
   917  		OAND,
   918  		OANDNOT,
   919  		ODIV,
   920  		OEQ,
   921  		OGE,
   922  		OGT,
   923  		OLE,
   924  		OLT,
   925  		OLSH,
   926  		OMOD,
   927  		OMUL,
   928  		ONE,
   929  		OOR,
   930  		ORSH,
   931  		OSUB,
   932  		OXOR:
   933  		n := n.(*BinaryExpr)
   934  		exprFmt(n.X, s, nprec)
   935  		fmt.Fprintf(s, " %v ", n.Op())
   936  		exprFmt(n.Y, s, nprec+1)
   937  
   938  	case OANDAND,
   939  		OOROR:
   940  		n := n.(*LogicalExpr)
   941  		exprFmt(n.X, s, nprec)
   942  		fmt.Fprintf(s, " %v ", n.Op())
   943  		exprFmt(n.Y, s, nprec+1)
   944  
   945  	case OSEND:
   946  		n := n.(*SendStmt)
   947  		exprFmt(n.Chan, s, nprec)
   948  		fmt.Fprintf(s, " <- ")
   949  		exprFmt(n.Value, s, nprec+1)
   950  
   951  	case OADDSTR:
   952  		n := n.(*AddStringExpr)
   953  		for i, n1 := range n.List {
   954  			if i != 0 {
   955  				fmt.Fprint(s, " + ")
   956  			}
   957  			exprFmt(n1, s, nprec)
   958  		}
   959  	default:
   960  		fmt.Fprintf(s, "<node %v>", n.Op())
   961  	}
   962  }
   963  
   964  func ellipsisIf(b bool) string {
   965  	if b {
   966  		return "..."
   967  	}
   968  	return ""
   969  }
   970  
   971  // Nodes
   972  
   973  // Format implements formatting for a Nodes.
   974  // The valid formats are:
   975  //
   976  //	%v	Go syntax, semicolon-separated
   977  //	%.v	Go syntax, comma-separated
   978  //	%+v	Debug syntax, as in DumpList.
   979  //
   980  func (l Nodes) Format(s fmt.State, verb rune) {
   981  	if s.Flag('+') && verb == 'v' {
   982  		// %+v is DumpList output
   983  		dumpNodes(s, l, 1)
   984  		return
   985  	}
   986  
   987  	if verb != 'v' {
   988  		fmt.Fprintf(s, "%%!%c(Nodes)", verb)
   989  		return
   990  	}
   991  
   992  	sep := "; "
   993  	if _, ok := s.Precision(); ok { // %.v is expr list
   994  		sep = ", "
   995  	}
   996  
   997  	for i, n := range l {
   998  		fmt.Fprint(s, n)
   999  		if i+1 < len(l) {
  1000  			fmt.Fprint(s, sep)
  1001  		}
  1002  	}
  1003  }
  1004  
  1005  // Dump
  1006  
  1007  // Dump prints the message s followed by a debug dump of n.
  1008  func Dump(s string, n Node) {
  1009  	fmt.Printf("%s%+v\n", s, n)
  1010  }
  1011  
  1012  // DumpList prints the message s followed by a debug dump of each node in the list.
  1013  func DumpList(s string, list Nodes) {
  1014  	var buf bytes.Buffer
  1015  	FDumpList(&buf, s, list)
  1016  	os.Stdout.Write(buf.Bytes())
  1017  }
  1018  
  1019  // FDumpList prints to w the message s followed by a debug dump of each node in the list.
  1020  func FDumpList(w io.Writer, s string, list Nodes) {
  1021  	io.WriteString(w, s)
  1022  	dumpNodes(w, list, 1)
  1023  	io.WriteString(w, "\n")
  1024  }
  1025  
  1026  // indent prints indentation to w.
  1027  func indent(w io.Writer, depth int) {
  1028  	fmt.Fprint(w, "\n")
  1029  	for i := 0; i < depth; i++ {
  1030  		fmt.Fprint(w, ".   ")
  1031  	}
  1032  }
  1033  
  1034  // EscFmt is set by the escape analysis code to add escape analysis details to the node print.
  1035  var EscFmt func(n Node) string
  1036  
  1037  // dumpNodeHeader prints the debug-format node header line to w.
  1038  func dumpNodeHeader(w io.Writer, n Node) {
  1039  	// Useful to see which nodes in an AST printout are actually identical
  1040  	if base.Debug.DumpPtrs != 0 {
  1041  		fmt.Fprintf(w, " p(%p)", n)
  1042  	}
  1043  
  1044  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil {
  1045  		// Useful to see where Defn is set and what node it points to
  1046  		fmt.Fprintf(w, " defn(%p)", n.Name().Defn)
  1047  	}
  1048  
  1049  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Curfn != nil {
  1050  		// Useful to see where Defn is set and what node it points to
  1051  		fmt.Fprintf(w, " curfn(%p)", n.Name().Curfn)
  1052  	}
  1053  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Outer != nil {
  1054  		// Useful to see where Defn is set and what node it points to
  1055  		fmt.Fprintf(w, " outer(%p)", n.Name().Outer)
  1056  	}
  1057  
  1058  	if EscFmt != nil {
  1059  		if esc := EscFmt(n); esc != "" {
  1060  			fmt.Fprintf(w, " %s", esc)
  1061  		}
  1062  	}
  1063  
  1064  	if n.Sym() != nil && n.Op() != ONAME && n.Op() != ONONAME && n.Op() != OTYPE {
  1065  		fmt.Fprintf(w, " %+v", n.Sym())
  1066  	}
  1067  
  1068  	// Print Node-specific fields of basic type in header line.
  1069  	v := reflect.ValueOf(n).Elem()
  1070  	t := v.Type()
  1071  	nf := t.NumField()
  1072  	for i := 0; i < nf; i++ {
  1073  		tf := t.Field(i)
  1074  		if tf.PkgPath != "" {
  1075  			// skip unexported field - Interface will fail
  1076  			continue
  1077  		}
  1078  		k := tf.Type.Kind()
  1079  		if reflect.Bool <= k && k <= reflect.Complex128 {
  1080  			name := strings.TrimSuffix(tf.Name, "_")
  1081  			vf := v.Field(i)
  1082  			vfi := vf.Interface()
  1083  			if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && isZero(vf) {
  1084  				continue
  1085  			}
  1086  			if vfi == true {
  1087  				fmt.Fprintf(w, " %s", name)
  1088  			} else {
  1089  				fmt.Fprintf(w, " %s:%+v", name, vf.Interface())
  1090  			}
  1091  		}
  1092  	}
  1093  
  1094  	// Print Node-specific booleans by looking for methods.
  1095  	// Different v, t from above - want *Struct not Struct, for methods.
  1096  	v = reflect.ValueOf(n)
  1097  	t = v.Type()
  1098  	nm := t.NumMethod()
  1099  	for i := 0; i < nm; i++ {
  1100  		tm := t.Method(i)
  1101  		if tm.PkgPath != "" {
  1102  			// skip unexported method - call will fail
  1103  			continue
  1104  		}
  1105  		m := v.Method(i)
  1106  		mt := m.Type()
  1107  		if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool {
  1108  			// TODO(rsc): Remove the func/defer/recover wrapping,
  1109  			// which is guarding against panics in miniExpr,
  1110  			// once we get down to the simpler state in which
  1111  			// nodes have no getter methods that aren't allowed to be called.
  1112  			func() {
  1113  				defer func() { recover() }()
  1114  				if m.Call(nil)[0].Bool() {
  1115  					name := strings.TrimSuffix(tm.Name, "_")
  1116  					fmt.Fprintf(w, " %s", name)
  1117  				}
  1118  			}()
  1119  		}
  1120  	}
  1121  
  1122  	if n.Op() == OCLOSURE {
  1123  		n := n.(*ClosureExpr)
  1124  		if fn := n.Func; fn != nil && fn.Nname.Sym() != nil {
  1125  			fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())
  1126  		}
  1127  	}
  1128  
  1129  	if n.Type() != nil {
  1130  		if n.Op() == OTYPE {
  1131  			fmt.Fprintf(w, " type")
  1132  		}
  1133  		fmt.Fprintf(w, " %+v", n.Type())
  1134  	}
  1135  	if n.Typecheck() != 0 {
  1136  		fmt.Fprintf(w, " tc(%d)", n.Typecheck())
  1137  	}
  1138  
  1139  	if n.Pos().IsKnown() {
  1140  		fmt.Fprint(w, " # ")
  1141  		switch n.Pos().IsStmt() {
  1142  		case src.PosNotStmt:
  1143  			fmt.Fprint(w, "_") // "-" would be confusing
  1144  		case src.PosIsStmt:
  1145  			fmt.Fprint(w, "+")
  1146  		}
  1147  		for i, pos := range base.Ctxt.AllPos(n.Pos(), nil) {
  1148  			if i > 0 {
  1149  				fmt.Fprint(w, ",")
  1150  			}
  1151  			// TODO(mdempsky): Print line pragma details too.
  1152  			file := filepath.Base(pos.Filename())
  1153  			// Note: this output will be parsed by ssa/html.go:(*HTMLWriter).WriteAST. Keep in sync.
  1154  			fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col())
  1155  		}
  1156  	}
  1157  }
  1158  
  1159  func dumpNode(w io.Writer, n Node, depth int) {
  1160  	indent(w, depth)
  1161  	if depth > 40 {
  1162  		fmt.Fprint(w, "...")
  1163  		return
  1164  	}
  1165  
  1166  	if n == nil {
  1167  		fmt.Fprint(w, "NilIrNode")
  1168  		return
  1169  	}
  1170  
  1171  	if len(n.Init()) != 0 {
  1172  		fmt.Fprintf(w, "%+v-init", n.Op())
  1173  		dumpNodes(w, n.Init(), depth+1)
  1174  		indent(w, depth)
  1175  	}
  1176  
  1177  	switch n.Op() {
  1178  	default:
  1179  		fmt.Fprintf(w, "%+v", n.Op())
  1180  		dumpNodeHeader(w, n)
  1181  
  1182  	case OLITERAL:
  1183  		fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val())
  1184  		dumpNodeHeader(w, n)
  1185  		return
  1186  
  1187  	case ONAME, ONONAME:
  1188  		if n.Sym() != nil {
  1189  			fmt.Fprintf(w, "%+v-%+v", n.Op(), n.Sym())
  1190  		} else {
  1191  			fmt.Fprintf(w, "%+v", n.Op())
  1192  		}
  1193  		dumpNodeHeader(w, n)
  1194  		if n.Type() == nil && n.Name() != nil && n.Name().Ntype != nil {
  1195  			indent(w, depth)
  1196  			fmt.Fprintf(w, "%+v-ntype", n.Op())
  1197  			dumpNode(w, n.Name().Ntype, depth+1)
  1198  		}
  1199  		return
  1200  
  1201  	case OASOP:
  1202  		n := n.(*AssignOpStmt)
  1203  		fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
  1204  		dumpNodeHeader(w, n)
  1205  
  1206  	case OTYPE:
  1207  		fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym())
  1208  		dumpNodeHeader(w, n)
  1209  		if n.Type() == nil && n.Name() != nil && n.Name().Ntype != nil {
  1210  			indent(w, depth)
  1211  			fmt.Fprintf(w, "%+v-ntype", n.Op())
  1212  			dumpNode(w, n.Name().Ntype, depth+1)
  1213  		}
  1214  		return
  1215  
  1216  	case OCLOSURE:
  1217  		fmt.Fprintf(w, "%+v", n.Op())
  1218  		dumpNodeHeader(w, n)
  1219  
  1220  	case ODCLFUNC:
  1221  		// Func has many fields we don't want to print.
  1222  		// Bypass reflection and just print what we want.
  1223  		n := n.(*Func)
  1224  		fmt.Fprintf(w, "%+v", n.Op())
  1225  		dumpNodeHeader(w, n)
  1226  		fn := n
  1227  		if len(fn.Dcl) > 0 {
  1228  			indent(w, depth)
  1229  			fmt.Fprintf(w, "%+v-Dcl", n.Op())
  1230  			for _, dcl := range n.Dcl {
  1231  				dumpNode(w, dcl, depth+1)
  1232  			}
  1233  		}
  1234  		if len(fn.ClosureVars) > 0 {
  1235  			indent(w, depth)
  1236  			fmt.Fprintf(w, "%+v-ClosureVars", n.Op())
  1237  			for _, cv := range fn.ClosureVars {
  1238  				dumpNode(w, cv, depth+1)
  1239  			}
  1240  		}
  1241  		if len(fn.Enter) > 0 {
  1242  			indent(w, depth)
  1243  			fmt.Fprintf(w, "%+v-Enter", n.Op())
  1244  			dumpNodes(w, fn.Enter, depth+1)
  1245  		}
  1246  		if len(fn.Body) > 0 {
  1247  			indent(w, depth)
  1248  			fmt.Fprintf(w, "%+v-body", n.Op())
  1249  			dumpNodes(w, fn.Body, depth+1)
  1250  		}
  1251  		return
  1252  	}
  1253  
  1254  	v := reflect.ValueOf(n).Elem()
  1255  	t := reflect.TypeOf(n).Elem()
  1256  	nf := t.NumField()
  1257  	for i := 0; i < nf; i++ {
  1258  		tf := t.Field(i)
  1259  		vf := v.Field(i)
  1260  		if tf.PkgPath != "" {
  1261  			// skip unexported field - Interface will fail
  1262  			continue
  1263  		}
  1264  		switch tf.Type.Kind() {
  1265  		case reflect.Interface, reflect.Ptr, reflect.Slice:
  1266  			if vf.IsNil() {
  1267  				continue
  1268  			}
  1269  		}
  1270  		name := strings.TrimSuffix(tf.Name, "_")
  1271  		// Do not bother with field name header lines for the
  1272  		// most common positional arguments: unary, binary expr,
  1273  		// index expr, send stmt, go and defer call expression.
  1274  		switch name {
  1275  		case "X", "Y", "Index", "Chan", "Value", "Call":
  1276  			name = ""
  1277  		}
  1278  		switch val := vf.Interface().(type) {
  1279  		case Node:
  1280  			if name != "" {
  1281  				indent(w, depth)
  1282  				fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1283  			}
  1284  			dumpNode(w, val, depth+1)
  1285  		case Nodes:
  1286  			if len(val) == 0 {
  1287  				continue
  1288  			}
  1289  			if name != "" {
  1290  				indent(w, depth)
  1291  				fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1292  			}
  1293  			dumpNodes(w, val, depth+1)
  1294  		default:
  1295  			if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) {
  1296  				if vf.Len() == 0 {
  1297  					continue
  1298  				}
  1299  				if name != "" {
  1300  					indent(w, depth)
  1301  					fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1302  				}
  1303  				for i, n := 0, vf.Len(); i < n; i++ {
  1304  					dumpNode(w, vf.Index(i).Interface().(Node), depth+1)
  1305  				}
  1306  			}
  1307  		}
  1308  	}
  1309  }
  1310  
  1311  var nodeType = reflect.TypeOf((*Node)(nil)).Elem()
  1312  
  1313  func dumpNodes(w io.Writer, list Nodes, depth int) {
  1314  	if len(list) == 0 {
  1315  		fmt.Fprintf(w, " <nil>")
  1316  		return
  1317  	}
  1318  
  1319  	for _, n := range list {
  1320  		dumpNode(w, n, depth)
  1321  	}
  1322  }
  1323  
  1324  // reflect.IsZero is not available in Go 1.4 (added in Go 1.13), so we use this copy instead.
  1325  func isZero(v reflect.Value) bool {
  1326  	switch v.Kind() {
  1327  	case reflect.Bool:
  1328  		return !v.Bool()
  1329  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  1330  		return v.Int() == 0
  1331  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  1332  		return v.Uint() == 0
  1333  	case reflect.Float32, reflect.Float64:
  1334  		return math.Float64bits(v.Float()) == 0
  1335  	case reflect.Complex64, reflect.Complex128:
  1336  		c := v.Complex()
  1337  		return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
  1338  	case reflect.Array:
  1339  		for i := 0; i < v.Len(); i++ {
  1340  			if !isZero(v.Index(i)) {
  1341  				return false
  1342  			}
  1343  		}
  1344  		return true
  1345  	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
  1346  		return v.IsNil()
  1347  	case reflect.String:
  1348  		return v.Len() == 0
  1349  	case reflect.Struct:
  1350  		for i := 0; i < v.NumField(); i++ {
  1351  			if !isZero(v.Field(i)) {
  1352  				return false
  1353  			}
  1354  		}
  1355  		return true
  1356  	default:
  1357  		return false
  1358  	}
  1359  }
  1360  

View as plain text