1
2
3
4
5 package astutil
6
7 import (
8 "go/ast"
9 "go/token"
10 "reflect"
11 )
12
13
14
15
16
17
18
19
20
21
22 func Equal(x, y ast.Node, identical func(x, y *ast.Ident) bool) bool {
23 if x == nil || y == nil {
24 return x == y
25 }
26 return equal(reflect.ValueOf(x), reflect.ValueOf(y), identical)
27 }
28
29 func equal(x, y reflect.Value, identical func(x, y *ast.Ident) bool) bool {
30
31 if x.Type() != y.Type() {
32 return false
33 }
34 switch x.Kind() {
35 case reflect.Pointer:
36 if x.IsNil() || y.IsNil() {
37 return x.IsNil() == y.IsNil()
38 }
39 switch t := x.Interface().(type) {
40
41 case *ast.Object, *ast.Scope, *ast.CommentGroup:
42 return true
43 case *ast.Ident:
44 return identical(t, y.Interface().(*ast.Ident))
45 default:
46 return equal(x.Elem(), y.Elem(), identical)
47 }
48
49 case reflect.Interface:
50 if x.IsNil() || y.IsNil() {
51 return x.IsNil() == y.IsNil()
52 }
53 return equal(x.Elem(), y.Elem(), identical)
54
55 case reflect.Struct:
56 for i := range x.NumField() {
57 xf := x.Field(i)
58 yf := y.Field(i)
59
60 if xpos, ok := xf.Interface().(token.Pos); ok {
61 ypos := yf.Interface().(token.Pos)
62
63
64 if xpos.IsValid() != ypos.IsValid() {
65 return false
66 }
67 } else if !equal(xf, yf, identical) {
68 return false
69 }
70 }
71 return true
72
73 case reflect.Slice:
74 if x.IsNil() || y.IsNil() {
75 return x.IsNil() == y.IsNil()
76 }
77 if x.Len() != y.Len() {
78 return false
79 }
80 for i := range x.Len() {
81 if !equal(x.Index(i), y.Index(i), identical) {
82 return false
83 }
84 }
85 return true
86
87 case reflect.String:
88 return x.String() == y.String()
89
90 case reflect.Bool:
91 return x.Bool() == y.Bool()
92
93 case reflect.Int:
94 return x.Int() == y.Int()
95
96 default:
97 panic(x)
98 }
99 }
100
View as plain text