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