1// Copyright 2013 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// This file implements printing of expressions.
6
7package types
8
9import (
10	"bytes"
11	"go/ast"
12)
13
14// ExprString returns the (possibly simplified) string representation for x.
15func ExprString(x ast.Expr) string {
16	var buf bytes.Buffer
17	WriteExpr(&buf, x)
18	return buf.String()
19}
20
21// WriteExpr writes the (possibly simplified) string representation for x to buf.
22func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
23	// The AST preserves source-level parentheses so there is
24	// no need to introduce them here to correct for different
25	// operator precedences. (This assumes that the AST was
26	// generated by a Go parser.)
27
28	switch x := x.(type) {
29	default:
30		buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
31
32	case *ast.Ident:
33		buf.WriteString(x.Name)
34
35	case *ast.Ellipsis:
36		buf.WriteString("...")
37		if x.Elt != nil {
38			WriteExpr(buf, x.Elt)
39		}
40
41	case *ast.BasicLit:
42		buf.WriteString(x.Value)
43
44	case *ast.FuncLit:
45		buf.WriteByte('(')
46		WriteExpr(buf, x.Type)
47		buf.WriteString(" literal)") // simplified
48
49	case *ast.CompositeLit:
50		buf.WriteByte('(')
51		WriteExpr(buf, x.Type)
52		buf.WriteString(" literal)") // simplified
53
54	case *ast.ParenExpr:
55		buf.WriteByte('(')
56		WriteExpr(buf, x.X)
57		buf.WriteByte(')')
58
59	case *ast.SelectorExpr:
60		WriteExpr(buf, x.X)
61		buf.WriteByte('.')
62		buf.WriteString(x.Sel.Name)
63
64	case *ast.IndexExpr:
65		WriteExpr(buf, x.X)
66		buf.WriteByte('[')
67		WriteExpr(buf, x.Index)
68		buf.WriteByte(']')
69
70	case *ast.SliceExpr:
71		WriteExpr(buf, x.X)
72		buf.WriteByte('[')
73		if x.Low != nil {
74			WriteExpr(buf, x.Low)
75		}
76		buf.WriteByte(':')
77		if x.High != nil {
78			WriteExpr(buf, x.High)
79		}
80		if x.Slice3 {
81			buf.WriteByte(':')
82			if x.Max != nil {
83				WriteExpr(buf, x.Max)
84			}
85		}
86		buf.WriteByte(']')
87
88	case *ast.TypeAssertExpr:
89		WriteExpr(buf, x.X)
90		buf.WriteString(".(")
91		WriteExpr(buf, x.Type)
92		buf.WriteByte(')')
93
94	case *ast.CallExpr:
95		WriteExpr(buf, x.Fun)
96		buf.WriteByte('(')
97		for i, arg := range x.Args {
98			if i > 0 {
99				buf.WriteString(", ")
100			}
101			WriteExpr(buf, arg)
102		}
103		if x.Ellipsis.IsValid() {
104			buf.WriteString("...")
105		}
106		buf.WriteByte(')')
107
108	case *ast.StarExpr:
109		buf.WriteByte('*')
110		WriteExpr(buf, x.X)
111
112	case *ast.UnaryExpr:
113		buf.WriteString(x.Op.String())
114		WriteExpr(buf, x.X)
115
116	case *ast.BinaryExpr:
117		WriteExpr(buf, x.X)
118		buf.WriteByte(' ')
119		buf.WriteString(x.Op.String())
120		buf.WriteByte(' ')
121		WriteExpr(buf, x.Y)
122
123	case *ast.ArrayType:
124		buf.WriteByte('[')
125		if x.Len != nil {
126			WriteExpr(buf, x.Len)
127		}
128		buf.WriteByte(']')
129		WriteExpr(buf, x.Elt)
130
131	case *ast.StructType:
132		buf.WriteString("struct{")
133		writeFieldList(buf, x.Fields, "; ", false)
134		buf.WriteByte('}')
135
136	case *ast.FuncType:
137		buf.WriteString("func")
138		writeSigExpr(buf, x)
139
140	case *ast.InterfaceType:
141		buf.WriteString("interface{")
142		writeFieldList(buf, x.Methods, "; ", true)
143		buf.WriteByte('}')
144
145	case *ast.MapType:
146		buf.WriteString("map[")
147		WriteExpr(buf, x.Key)
148		buf.WriteByte(']')
149		WriteExpr(buf, x.Value)
150
151	case *ast.ChanType:
152		var s string
153		switch x.Dir {
154		case ast.SEND:
155			s = "chan<- "
156		case ast.RECV:
157			s = "<-chan "
158		default:
159			s = "chan "
160		}
161		buf.WriteString(s)
162		WriteExpr(buf, x.Value)
163	}
164}
165
166func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
167	buf.WriteByte('(')
168	writeFieldList(buf, sig.Params, ", ", false)
169	buf.WriteByte(')')
170
171	res := sig.Results
172	n := res.NumFields()
173	if n == 0 {
174		// no result
175		return
176	}
177
178	buf.WriteByte(' ')
179	if n == 1 && len(res.List[0].Names) == 0 {
180		// single unnamed result
181		WriteExpr(buf, res.List[0].Type)
182		return
183	}
184
185	// multiple or named result(s)
186	buf.WriteByte('(')
187	writeFieldList(buf, res, ", ", false)
188	buf.WriteByte(')')
189}
190
191func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
192	for i, f := range fields.List {
193		if i > 0 {
194			buf.WriteString(sep)
195		}
196
197		// field list names
198		for i, name := range f.Names {
199			if i > 0 {
200				buf.WriteString(", ")
201			}
202			buf.WriteString(name.Name)
203		}
204
205		// types of interface methods consist of signatures only
206		if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
207			writeSigExpr(buf, sig)
208			continue
209		}
210
211		// named fields are separated with a blank from the field type
212		if len(f.Names) > 0 {
213			buf.WriteByte(' ')
214		}
215
216		WriteExpr(buf, f.Type)
217
218		// ignore tag
219	}
220}
221