1
2
3
4
5 package eg
6
7 import (
8 "fmt"
9 "go/ast"
10 "go/constant"
11 "go/token"
12 "go/types"
13 "log"
14 "os"
15 "reflect"
16
17 "golang.org/x/tools/go/ast/astutil"
18 )
19
20
21
22
23
24
25
26
27
28
29
30 func (tr *Transformer) matchExpr(x, y ast.Expr) bool {
31 if x == nil && y == nil {
32 return true
33 }
34 if x == nil || y == nil {
35 return false
36 }
37 x = unparen(x)
38 y = unparen(y)
39
40
41 if xobj, ok := tr.wildcardObj(x); ok {
42 return tr.matchWildcard(xobj, y)
43 }
44
45
46
47 xobj := isRef(x, tr.info)
48 yobj := isRef(y, tr.info)
49 if xobj != nil {
50 return xobj == yobj
51 }
52 if yobj != nil {
53 return false
54 }
55
56
57
58
59
60 if reflect.TypeOf(x) != reflect.TypeOf(y) {
61 return false
62 }
63 switch x := x.(type) {
64 case *ast.Ident:
65 log.Fatalf("unexpected Ident: %s", astString(tr.fset, x))
66
67 case *ast.BasicLit:
68 y := y.(*ast.BasicLit)
69 xval := constant.MakeFromLiteral(x.Value, x.Kind, 0)
70 yval := constant.MakeFromLiteral(y.Value, y.Kind, 0)
71 return constant.Compare(xval, token.EQL, yval)
72
73 case *ast.FuncLit:
74
75 return false
76
77 case *ast.CompositeLit:
78 y := y.(*ast.CompositeLit)
79 return (x.Type == nil) == (y.Type == nil) &&
80 (x.Type == nil || tr.matchType(x.Type, y.Type)) &&
81 tr.matchExprs(x.Elts, y.Elts)
82
83 case *ast.SelectorExpr:
84 y := y.(*ast.SelectorExpr)
85 return tr.matchSelectorExpr(x, y) &&
86 tr.info.Selections[x].Obj() == tr.info.Selections[y].Obj()
87
88 case *ast.IndexExpr:
89 y := y.(*ast.IndexExpr)
90 return tr.matchExpr(x.X, y.X) &&
91 tr.matchExpr(x.Index, y.Index)
92
93 case *ast.SliceExpr:
94 y := y.(*ast.SliceExpr)
95 return tr.matchExpr(x.X, y.X) &&
96 tr.matchExpr(x.Low, y.Low) &&
97 tr.matchExpr(x.High, y.High) &&
98 tr.matchExpr(x.Max, y.Max) &&
99 x.Slice3 == y.Slice3
100
101 case *ast.TypeAssertExpr:
102 y := y.(*ast.TypeAssertExpr)
103 return tr.matchExpr(x.X, y.X) &&
104 tr.matchType(x.Type, y.Type)
105
106 case *ast.CallExpr:
107 y := y.(*ast.CallExpr)
108 match := tr.matchExpr
109 if tr.info.Types[x.Fun].IsType() {
110 match = tr.matchType
111 }
112 return x.Ellipsis.IsValid() == y.Ellipsis.IsValid() &&
113 match(x.Fun, y.Fun) &&
114 tr.matchExprs(x.Args, y.Args)
115
116 case *ast.StarExpr:
117 y := y.(*ast.StarExpr)
118 return tr.matchExpr(x.X, y.X)
119
120 case *ast.UnaryExpr:
121 y := y.(*ast.UnaryExpr)
122 return x.Op == y.Op &&
123 tr.matchExpr(x.X, y.X)
124
125 case *ast.BinaryExpr:
126 y := y.(*ast.BinaryExpr)
127 return x.Op == y.Op &&
128 tr.matchExpr(x.X, y.X) &&
129 tr.matchExpr(x.Y, y.Y)
130
131 case *ast.KeyValueExpr:
132 y := y.(*ast.KeyValueExpr)
133 return tr.matchExpr(x.Key, y.Key) &&
134 tr.matchExpr(x.Value, y.Value)
135 }
136
137 panic(fmt.Sprintf("unhandled AST node type: %T", x))
138 }
139
140 func (tr *Transformer) matchExprs(xx, yy []ast.Expr) bool {
141 if len(xx) != len(yy) {
142 return false
143 }
144 for i := range xx {
145 if !tr.matchExpr(xx[i], yy[i]) {
146 return false
147 }
148 }
149 return true
150 }
151
152
153 func (tr *Transformer) matchType(x, y ast.Expr) bool {
154 tx := tr.info.Types[x].Type
155 ty := tr.info.Types[y].Type
156 return types.Identical(tx, ty)
157 }
158
159 func (tr *Transformer) wildcardObj(x ast.Expr) (*types.Var, bool) {
160 if x, ok := x.(*ast.Ident); ok && x != nil && tr.allowWildcards {
161 if xobj, ok := tr.info.Uses[x].(*types.Var); ok && tr.wildcards[xobj] {
162 return xobj, true
163 }
164 }
165 return nil, false
166 }
167
168 func (tr *Transformer) matchSelectorExpr(x, y *ast.SelectorExpr) bool {
169 if xobj, ok := tr.wildcardObj(x.X); ok {
170 field := x.Sel.Name
171 yt := tr.info.TypeOf(y.X)
172 o, _, _ := types.LookupFieldOrMethod(yt, true, tr.currentPkg, field)
173 if o != nil {
174 tr.env[xobj.Name()] = y.X
175 return true
176 }
177 }
178 return tr.matchExpr(x.X, y.X)
179 }
180
181 func (tr *Transformer) matchWildcard(xobj *types.Var, y ast.Expr) bool {
182 name := xobj.Name()
183
184 if tr.verbose {
185 fmt.Fprintf(os.Stderr, "%s: wildcard %s -> %s?: ",
186 tr.fset.Position(y.Pos()), name, astString(tr.fset, y))
187 }
188
189
190 yt := tr.info.TypeOf(y)
191 if yt == nil {
192
193
194
195
196
197
198 return false
199 }
200 if !types.AssignableTo(yt, xobj.Type()) {
201 if tr.verbose {
202 fmt.Fprintf(os.Stderr, "%s not assignable to %s\n", yt, xobj.Type())
203 }
204 return false
205 }
206
207
208
209
210 if old, ok := tr.env[name]; ok {
211
212 tr.allowWildcards = false
213 r := tr.matchExpr(old, y)
214 if tr.verbose {
215 fmt.Fprintf(os.Stderr, "%t secondary match, primary was %s\n",
216 r, astString(tr.fset, old))
217 }
218 tr.allowWildcards = true
219 return r
220 }
221
222 if tr.verbose {
223 fmt.Fprintf(os.Stderr, "primary match\n")
224 }
225
226 tr.env[name] = y
227 return true
228 }
229
230
231
232 func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
233
234
235
236 func isRef(n ast.Node, info *types.Info) types.Object {
237 switch n := n.(type) {
238 case *ast.Ident:
239 return info.Uses[n]
240
241 case *ast.SelectorExpr:
242 if _, ok := info.Selections[n]; !ok {
243
244 return info.Uses[n.Sel]
245 }
246 }
247 return nil
248 }
249
View as plain text