3 // This file implements the String() methods for all Value and
13 func (id Id
) String() string {
17 return fmt
.Sprintf("%s/%s", id
.Pkg
.Path
, id
.Name
)
20 // relName returns the name of v relative to i.
21 // In most cases, this is identical to v.Name(), but for cross-package
22 // references to Functions (including methods) and Globals, the
23 // package-qualified FullName is used instead.
25 func relName(v Value
, i Instruction
) string {
26 switch v
:= v
.(type) {
28 if v
.Pkg
== i
.Block().Func
.Pkg
{
33 if v
.Pkg
== nil || v
.Pkg
== i
.Block().Func
.Pkg
{
43 // This method is provided only for debugging.
44 // It never appears in disassembly, which uses Value.Name().
46 func (v
*Literal
) String() string {
47 return fmt
.Sprintf("literal %s rep=%T", v
.Name(), v
.Value
)
50 func (v
*Parameter
) String() string {
51 return fmt
.Sprintf("parameter %s : %s", v
.Name(), v
.Type())
54 func (v
*Capture
) String() string {
55 return fmt
.Sprintf("capture %s : %s", v
.Name(), v
.Type())
58 func (v
*Global
) String() string {
59 return fmt
.Sprintf("global %s : %s", v
.Name(), v
.Type())
62 func (v
*Builtin
) String() string {
63 return fmt
.Sprintf("builtin %s : %s", v
.Name(), v
.Type())
66 func (r
*Function
) String() string {
67 return fmt
.Sprintf("function %s : %s", r
.Name(), r
.Type())
70 // FullName returns the name of this function qualified by the
71 // package name, unless it is anonymous or synthetic.
73 // TODO(adonovan): move to func.go when it's submitted.
75 func (f
*Function
) FullName() string {
76 if f
.Enclosing
!= nil || f
.Pkg
== nil {
77 return f
.Name_
// anonymous or synthetic
79 return fmt
.Sprintf("%s.%s", f
.Pkg
.ImportPath
, f
.Name_
)
82 // FullName returns g's package-qualified name.
83 func (g
*Global
) FullName() string {
84 return fmt
.Sprintf("%s.%s", g
.Pkg
.ImportPath
, g
.Name_
)
87 // Instruction.String()
89 func (v
*Alloc
) String() string {
94 return fmt
.Sprintf("%s %s", op
, indirectType(v
.Type()))
97 func (v
*Phi
) String() string {
99 b
.WriteString("phi [")
100 for i
, edge
:= range v
.Edges
{
104 // Be robust against malformed CFG.
106 if v
.Block_
!= nil && i
< len(v
.Block_
.Preds
) {
107 blockname
= v
.Block_
.Preds
[i
].Name
109 b
.WriteString(blockname
)
111 b
.WriteString(relName(edge
, v
))
117 func printCall(v
*CallCommon
, prefix
string, instr Instruction
) string {
119 b
.WriteString(prefix
)
121 b
.WriteString(relName(v
.Func
, instr
))
123 name
:= underlyingType(v
.Recv
.Type()).(*types
.Interface
).Methods
[v
.Method
].Name
124 fmt
.Fprintf(&b
, "invoke %s.%s [#%d]", relName(v
.Recv
, instr
), name
, v
.Method
)
127 for i
, arg
:= range v
.Args
{
131 b
.WriteString(relName(arg
, instr
))
140 func (v
*Call
) String() string {
141 return printCall(&v
.CallCommon
, "", v
)
144 func (v
*BinOp
) String() string {
145 return fmt
.Sprintf("%s %s %s", relName(v
.X
, v
), v
.Op
.String(), relName(v
.Y
, v
))
148 func (v
*UnOp
) String() string {
149 return fmt
.Sprintf("%s%s%s", v
.Op
, relName(v
.X
, v
), commaOk(v
.CommaOk
))
152 func (v
*Conv
) String() string {
153 return fmt
.Sprintf("convert %s <- %s (%s)", v
.Type(), v
.X
.Type(), relName(v
.X
, v
))
156 func (v
*ChangeInterface
) String() string {
157 return fmt
.Sprintf("change interface %s <- %s (%s)", v
.Type(), v
.X
.Type(), relName(v
.X
, v
))
160 func (v
*MakeInterface
) String() string {
161 return fmt
.Sprintf("make interface %s <- %s (%s)", v
.Type(), v
.X
.Type(), relName(v
.X
, v
))
164 func (v
*MakeClosure
) String() string {
166 fmt
.Fprintf(&b
, "make closure %s", relName(v
.Fn
, v
))
167 if v
.Bindings
!= nil {
169 for i
, c
:= range v
.Bindings
{
173 b
.WriteString(relName(c
, v
))
180 func (v
*MakeSlice
) String() string {
182 b
.WriteString("make slice ")
183 b
.WriteString(v
.Type().String())
185 b
.WriteString(relName(v
.Len
, v
))
187 b
.WriteString(relName(v
.Cap
, v
))
191 func (v
*Slice
) String() string {
193 b
.WriteString("slice ")
194 b
.WriteString(relName(v
.X
, v
))
197 b
.WriteString(relName(v
.Low
, v
))
201 b
.WriteString(relName(v
.High
, v
))
207 func (v
*MakeMap
) String() string {
209 if v
.Reserve
!= nil {
210 res
= relName(v
.Reserve
, v
)
212 return fmt
.Sprintf("make %s %s", v
.Type(), res
)
215 func (v
*MakeChan
) String() string {
216 return fmt
.Sprintf("make %s %s", v
.Type(), relName(v
.Size
, v
))
219 func (v
*FieldAddr
) String() string {
220 fields
:= underlyingType(indirectType(v
.X
.Type())).(*types
.Struct
).Fields
221 // Be robust against a bad index.
223 if v
.Field
>= 0 && v
.Field
< len(fields
) {
224 name
= fields
[v
.Field
].Name
226 return fmt
.Sprintf("&%s.%s [#%d]", relName(v
.X
, v
), name
, v
.Field
)
229 func (v
*Field
) String() string {
230 fields
:= underlyingType(v
.X
.Type()).(*types
.Struct
).Fields
231 // Be robust against a bad index.
233 if v
.Field
>= 0 && v
.Field
< len(fields
) {
234 name
= fields
[v
.Field
].Name
236 return fmt
.Sprintf("%s.%s [#%d]", relName(v
.X
, v
), name
, v
.Field
)
239 func (v
*IndexAddr
) String() string {
240 return fmt
.Sprintf("&%s[%s]", relName(v
.X
, v
), relName(v
.Index
, v
))
243 func (v
*Index
) String() string {
244 return fmt
.Sprintf("%s[%s]", relName(v
.X
, v
), relName(v
.Index
, v
))
247 func (v
*Lookup
) String() string {
248 return fmt
.Sprintf("%s[%s]%s", relName(v
.X
, v
), relName(v
.Index
, v
), commaOk(v
.CommaOk
))
251 func (v
*Range
) String() string {
252 return "range " + relName(v
.X
, v
)
255 func (v
*Next
) String() string {
256 return "next " + relName(v
.Iter
, v
)
259 func (v
*TypeAssert
) String() string {
260 return fmt
.Sprintf("typeassert%s %s.(%s)", commaOk(v
.CommaOk
), relName(v
.X
, v
), v
.AssertedType
)
263 func (v
*Extract
) String() string {
264 return fmt
.Sprintf("extract %s #%d", relName(v
.Tuple
, v
), v
.Index
)
267 func (s
*Jump
) String() string {
268 // Be robust against malformed CFG.
270 if s
.Block_
!= nil && len(s
.Block_
.Succs
) == 1 {
271 blockname
= s
.Block_
.Succs
[0].Name
273 return fmt
.Sprintf("jump %s", blockname
)
276 func (s
*If
) String() string {
277 // Be robust against malformed CFG.
278 tblockname
, fblockname
:= "?", "?"
279 if s
.Block_
!= nil && len(s
.Block_
.Succs
) == 2 {
280 tblockname
= s
.Block_
.Succs
[0].Name
281 fblockname
= s
.Block_
.Succs
[1].Name
283 return fmt
.Sprintf("if %s goto %s else %s", relName(s
.Cond
, s
), tblockname
, fblockname
)
286 func (s
*Go
) String() string {
287 return printCall(&s
.CallCommon
, "go ", s
)
290 func (s
*Ret
) String() string {
293 for i
, r
:= range s
.Results
{
299 b
.WriteString(relName(r
, s
))
304 func (s
*Send
) String() string {
305 return fmt
.Sprintf("send %s <- %s", relName(s
.Chan
, s
), relName(s
.X
, s
))
308 func (s
*Defer
) String() string {
309 return printCall(&s
.CallCommon
, "defer ", s
)
312 func (s
*Select
) String() string {
314 for i
, st
:= range s
.States
{
318 if st
.Dir
== ast
.RECV
{
320 b
.WriteString(relName(st
.Chan
, s
))
322 b
.WriteString(relName(st
.Chan
, s
))
324 b
.WriteString(relName(st
.Send
, s
))
331 return fmt
.Sprintf("select %sblocking [%s]", non
, b
.String())
334 func (s
*Store
) String() string {
335 return fmt
.Sprintf("*%s = %s", relName(s
.Addr
, s
), relName(s
.Val
, s
))
338 func (s
*MapUpdate
) String() string {
339 return fmt
.Sprintf("%s[%s] = %s", relName(s
.Map
, s
), relName(s
.Key
, s
), relName(s
.Value
, s
))
342 func (p
*Package
) String() string {
343 // TODO(adonovan): prettify output.
345 fmt
.Fprintf(&b
, "Package %s at %s:\n", p
.ImportPath
, p
.Prog
.Files
.File(p
.Pos
).Name())
347 // TODO(adonovan): make order deterministic.
349 for name
:= range p
.Members
{
350 if l
:= len(name
); l
> maxname
{
355 for name
, mem
:= range p
.Members
{
356 switch mem
:= mem
.(type) {
358 fmt
.Fprintf(&b
, " const %-*s %s\n", maxname
, name
, mem
.Name())
361 fmt
.Fprintf(&b
, " func %-*s %s\n", maxname
, name
, mem
.Type())
364 fmt
.Fprintf(&b
, " type %-*s %s\n", maxname
, name
, mem
.NamedType
.Underlying
)
365 // TODO(adonovan): make order deterministic.
366 for name
, method
:= range mem
.Methods
{
367 fmt
.Fprintf(&b
, " method %s %s\n", name
, method
.Signature
)
371 fmt
.Fprintf(&b
, " var %-*s %s\n", maxname
, name
, mem
.Type())
378 func commaOk(x
bool) string {