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
5package ir
6
7import (
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
26var 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.
97func (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")
109func (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.
132func 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
172var 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.
295func StmtWithInit(op Op) bool {
296	switch op {
297	case OIF, OFOR, OSWITCH:
298		return true
299	}
300	return false
301}
302
303func 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
507func 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
857func 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.
872func (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.
900func 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.
905func 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.
912func 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.
919func 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.
927var EscFmt func(n Node) string
928
929// dumpNodeHeader prints the debug-format node header line to w.
930func 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
1051func 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
1197var nodeType = reflect.TypeOf((*Node)(nil)).Elem()
1198
1199func 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}
1209