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  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"strings"
    16  
    17  	"unicode/utf8"
    18  
    19  	"cmd/compile/internal/base"
    20  	"cmd/compile/internal/types"
    21  	"cmd/internal/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", rune(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  // This includes all the recursive structure under n.
   901  func Dump(s string, n Node) {
   902  	fmt.Printf("%s%+v\n", s, n)
   903  }
   904  
   905  // FDump prints to w the message s followed by a debug dump of n.
   906  // This includes all the recursive structure under n.
   907  func FDump(w io.Writer, s string, n Node) {
   908  	fmt.Fprintf(w, "%s%+v\n", s, n)
   909  }
   910  
   911  // DumpList prints the message s followed by a debug dump of each node in the list.
   912  // This includes all the recursive structure under each node in the list.
   913  func DumpList(s string, list Nodes) {
   914  	var buf bytes.Buffer
   915  	FDumpList(&buf, s, list)
   916  	os.Stdout.Write(buf.Bytes())
   917  }
   918  
   919  // FDumpList prints to w the message s followed by a debug dump of each node in the list.
   920  // This includes all the recursive structure under each node in the list.
   921  func FDumpList(w io.Writer, s string, list Nodes) {
   922  	io.WriteString(w, s)
   923  	dumpNodes(w, list, 1)
   924  	io.WriteString(w, "\n")
   925  }
   926  
   927  // indent prints indentation to w.
   928  func indent(w io.Writer, depth int) {
   929  	fmt.Fprint(w, "\n")
   930  	for i := 0; i < depth; i++ {
   931  		fmt.Fprint(w, ".   ")
   932  	}
   933  }
   934  
   935  // EscFmt is set by the escape analysis code to add escape analysis details to the node print.
   936  var EscFmt func(n Node) string
   937  
   938  // dumpNodeHeader prints the debug-format node header line to w.
   939  func dumpNodeHeader(w io.Writer, n Node) {
   940  	// Useful to see which nodes in an AST printout are actually identical
   941  	if base.Debug.DumpPtrs != 0 {
   942  		fmt.Fprintf(w, " p(%p)", n)
   943  	}
   944  
   945  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil {
   946  		// Useful to see where Defn is set and what node it points to
   947  		fmt.Fprintf(w, " defn(%p)", n.Name().Defn)
   948  	}
   949  
   950  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Curfn != nil {
   951  		// Useful to see where Defn is set and what node it points to
   952  		fmt.Fprintf(w, " curfn(%p)", n.Name().Curfn)
   953  	}
   954  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Outer != nil {
   955  		// Useful to see where Defn is set and what node it points to
   956  		fmt.Fprintf(w, " outer(%p)", n.Name().Outer)
   957  	}
   958  
   959  	if EscFmt != nil {
   960  		if esc := EscFmt(n); esc != "" {
   961  			fmt.Fprintf(w, " %s", esc)
   962  		}
   963  	}
   964  
   965  	if n.Sym() != nil && n.Op() != ONAME && n.Op() != ONONAME && n.Op() != OTYPE {
   966  		fmt.Fprintf(w, " %+v", n.Sym())
   967  	}
   968  
   969  	// Print Node-specific fields of basic type in header line.
   970  	v := reflect.ValueOf(n).Elem()
   971  	t := v.Type()
   972  	nf := t.NumField()
   973  	for i := 0; i < nf; i++ {
   974  		tf := t.Field(i)
   975  		if tf.PkgPath != "" {
   976  			// skip unexported field - Interface will fail
   977  			continue
   978  		}
   979  		k := tf.Type.Kind()
   980  		if reflect.Bool <= k && k <= reflect.Complex128 {
   981  			name := strings.TrimSuffix(tf.Name, "_")
   982  			vf := v.Field(i)
   983  			vfi := vf.Interface()
   984  			if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && vf.IsZero() {
   985  				continue
   986  			}
   987  			if vfi == true {
   988  				fmt.Fprintf(w, " %s", name)
   989  			} else {
   990  				fmt.Fprintf(w, " %s:%+v", name, vf.Interface())
   991  			}
   992  		}
   993  	}
   994  
   995  	// Print Node-specific booleans by looking for methods.
   996  	// Different v, t from above - want *Struct not Struct, for methods.
   997  	v = reflect.ValueOf(n)
   998  	t = v.Type()
   999  	nm := t.NumMethod()
  1000  	for i := 0; i < nm; i++ {
  1001  		tm := t.Method(i)
  1002  		if tm.PkgPath != "" {
  1003  			// skip unexported method - call will fail
  1004  			continue
  1005  		}
  1006  		m := v.Method(i)
  1007  		mt := m.Type()
  1008  		if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool {
  1009  			// TODO(rsc): Remove the func/defer/recover wrapping,
  1010  			// which is guarding against panics in miniExpr,
  1011  			// once we get down to the simpler state in which
  1012  			// nodes have no getter methods that aren't allowed to be called.
  1013  			func() {
  1014  				defer func() { recover() }()
  1015  				if m.Call(nil)[0].Bool() {
  1016  					name := strings.TrimSuffix(tm.Name, "_")
  1017  					fmt.Fprintf(w, " %s", name)
  1018  				}
  1019  			}()
  1020  		}
  1021  	}
  1022  
  1023  	if n.Op() == OCLOSURE {
  1024  		n := n.(*ClosureExpr)
  1025  		if fn := n.Func; fn != nil && fn.Nname.Sym() != nil {
  1026  			fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())
  1027  		}
  1028  	}
  1029  
  1030  	if n.Type() != nil {
  1031  		if n.Op() == OTYPE {
  1032  			fmt.Fprintf(w, " type")
  1033  		}
  1034  		fmt.Fprintf(w, " %+v", n.Type())
  1035  	}
  1036  	if n.Typecheck() != 0 {
  1037  		fmt.Fprintf(w, " tc(%d)", n.Typecheck())
  1038  	}
  1039  
  1040  	if n.Pos().IsKnown() {
  1041  		fmt.Fprint(w, " # ")
  1042  		switch n.Pos().IsStmt() {
  1043  		case src.PosNotStmt:
  1044  			fmt.Fprint(w, "_") // "-" would be confusing
  1045  		case src.PosIsStmt:
  1046  			fmt.Fprint(w, "+")
  1047  		}
  1048  		sep := ""
  1049  		base.Ctxt.AllPos(n.Pos(), func(pos src.Pos) {
  1050  			fmt.Fprint(w, sep)
  1051  			sep = " "
  1052  			// TODO(mdempsky): Print line pragma details too.
  1053  			file := filepath.Base(pos.Filename())
  1054  			// Note: this output will be parsed by ssa/html.go:(*HTMLWriter).WriteAST. Keep in sync.
  1055  			fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col())
  1056  		})
  1057  	}
  1058  }
  1059  
  1060  func dumpNode(w io.Writer, n Node, depth int) {
  1061  	indent(w, depth)
  1062  	if depth > 40 {
  1063  		fmt.Fprint(w, "...")
  1064  		return
  1065  	}
  1066  
  1067  	if n == nil {
  1068  		fmt.Fprint(w, "NilIrNode")
  1069  		return
  1070  	}
  1071  
  1072  	if len(n.Init()) != 0 {
  1073  		fmt.Fprintf(w, "%+v-init", n.Op())
  1074  		dumpNodes(w, n.Init(), depth+1)
  1075  		indent(w, depth)
  1076  	}
  1077  
  1078  	switch n.Op() {
  1079  	default:
  1080  		fmt.Fprintf(w, "%+v", n.Op())
  1081  		dumpNodeHeader(w, n)
  1082  
  1083  	case OLITERAL:
  1084  		fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val())
  1085  		dumpNodeHeader(w, n)
  1086  		return
  1087  
  1088  	case ONAME, ONONAME:
  1089  		if n.Sym() != nil {
  1090  			fmt.Fprintf(w, "%+v-%+v", n.Op(), n.Sym())
  1091  		} else {
  1092  			fmt.Fprintf(w, "%+v", n.Op())
  1093  		}
  1094  		dumpNodeHeader(w, n)
  1095  		return
  1096  
  1097  	case OLINKSYMOFFSET:
  1098  		n := n.(*LinksymOffsetExpr)
  1099  		fmt.Fprintf(w, "%+v-%v", n.Op(), n.Linksym)
  1100  		// Offset is almost always 0, so only print when it's interesting.
  1101  		if n.Offset_ != 0 {
  1102  			fmt.Fprintf(w, "%+v", n.Offset_)
  1103  		}
  1104  		dumpNodeHeader(w, n)
  1105  
  1106  	case OASOP:
  1107  		n := n.(*AssignOpStmt)
  1108  		fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
  1109  		dumpNodeHeader(w, n)
  1110  
  1111  	case OTYPE:
  1112  		fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym())
  1113  		dumpNodeHeader(w, n)
  1114  		return
  1115  
  1116  	case OCLOSURE:
  1117  		fmt.Fprintf(w, "%+v", n.Op())
  1118  		dumpNodeHeader(w, n)
  1119  
  1120  	case ODCLFUNC:
  1121  		// Func has many fields we don't want to print.
  1122  		// Bypass reflection and just print what we want.
  1123  		n := n.(*Func)
  1124  		fmt.Fprintf(w, "%+v", n.Op())
  1125  		dumpNodeHeader(w, n)
  1126  		fn := n
  1127  		if len(fn.Dcl) > 0 {
  1128  			indent(w, depth)
  1129  			fmt.Fprintf(w, "%+v-Dcl", n.Op())
  1130  			for _, dcl := range n.Dcl {
  1131  				dumpNode(w, dcl, depth+1)
  1132  			}
  1133  		}
  1134  		if len(fn.ClosureVars) > 0 {
  1135  			indent(w, depth)
  1136  			fmt.Fprintf(w, "%+v-ClosureVars", n.Op())
  1137  			for _, cv := range fn.ClosureVars {
  1138  				dumpNode(w, cv, depth+1)
  1139  			}
  1140  		}
  1141  		if len(fn.Body) > 0 {
  1142  			indent(w, depth)
  1143  			fmt.Fprintf(w, "%+v-body", n.Op())
  1144  			dumpNodes(w, fn.Body, depth+1)
  1145  		}
  1146  		return
  1147  	}
  1148  
  1149  	v := reflect.ValueOf(n).Elem()
  1150  	t := reflect.TypeOf(n).Elem()
  1151  	nf := t.NumField()
  1152  	for i := 0; i < nf; i++ {
  1153  		tf := t.Field(i)
  1154  		vf := v.Field(i)
  1155  		if tf.PkgPath != "" {
  1156  			// skip unexported field - Interface will fail
  1157  			continue
  1158  		}
  1159  		switch tf.Type.Kind() {
  1160  		case reflect.Interface, reflect.Ptr, reflect.Slice:
  1161  			if vf.IsNil() {
  1162  				continue
  1163  			}
  1164  		}
  1165  		name := strings.TrimSuffix(tf.Name, "_")
  1166  		// Do not bother with field name header lines for the
  1167  		// most common positional arguments: unary, binary expr,
  1168  		// index expr, send stmt, go and defer call expression.
  1169  		switch name {
  1170  		case "X", "Y", "Index", "Chan", "Value", "Call":
  1171  			name = ""
  1172  		}
  1173  		switch val := vf.Interface().(type) {
  1174  		case Node:
  1175  			if name != "" {
  1176  				indent(w, depth)
  1177  				fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1178  			}
  1179  			dumpNode(w, val, depth+1)
  1180  		case Nodes:
  1181  			if len(val) == 0 {
  1182  				continue
  1183  			}
  1184  			if name != "" {
  1185  				indent(w, depth)
  1186  				fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1187  			}
  1188  			dumpNodes(w, val, depth+1)
  1189  		default:
  1190  			if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) {
  1191  				if vf.Len() == 0 {
  1192  					continue
  1193  				}
  1194  				if name != "" {
  1195  					indent(w, depth)
  1196  					fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1197  				}
  1198  				for i, n := 0, vf.Len(); i < n; i++ {
  1199  					dumpNode(w, vf.Index(i).Interface().(Node), depth+1)
  1200  				}
  1201  			}
  1202  		}
  1203  	}
  1204  }
  1205  
  1206  var nodeType = reflect.TypeFor[Node]()
  1207  
  1208  func dumpNodes(w io.Writer, list Nodes, depth int) {
  1209  	if len(list) == 0 {
  1210  		fmt.Fprintf(w, " <nil>")
  1211  		return
  1212  	}
  1213  
  1214  	for _, n := range list {
  1215  		dumpNode(w, n, depth)
  1216  	}
  1217  }
  1218  

View as plain text