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