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
30
31
32 func EqualSyntax(x, y ast.Expr) bool {
33 sameName := func(x, y *ast.Ident) bool { return x.Name == y.Name }
34 return Equal(x, y, sameName)
35 }
36
37 func equal(x, y reflect.Value, identical func(x, y *ast.Ident) bool) bool {
38
39 if x.Type() != y.Type() {
40 return false
41 }
42 switch x.Kind() {
43 case reflect.Pointer:
44 if x.IsNil() || y.IsNil() {
45 return x.IsNil() == y.IsNil()
46 }
47 switch t := x.Interface().(type) {
48
49 case *ast.Object, *ast.Scope, *ast.CommentGroup:
50 return true
51 case *ast.Ident:
52 return identical(t, y.Interface().(*ast.Ident))
53 default:
54 return equal(x.Elem(), y.Elem(), identical)
55 }
56
57 case reflect.Interface:
58 if x.IsNil() || y.IsNil() {
59 return x.IsNil() == y.IsNil()
60 }
61 return equal(x.Elem(), y.Elem(), identical)
62
63 case reflect.Struct:
64 for i := range x.NumField() {
65 xf := x.Field(i)
66 yf := y.Field(i)
67
68 if xpos, ok := xf.Interface().(token.Pos); ok {
69 ypos := yf.Interface().(token.Pos)
70
71
72 if xpos.IsValid() != ypos.IsValid() {
73 return false
74 }
75 } else if !equal(xf, yf, identical) {
76 return false
77 }
78 }
79 return true
80
81 case reflect.Slice:
82 if x.IsNil() || y.IsNil() {
83 return x.IsNil() == y.IsNil()
84 }
85 if x.Len() != y.Len() {
86 return false
87 }
88 for i := range x.Len() {
89 if !equal(x.Index(i), y.Index(i), identical) {
90 return false
91 }
92 }
93 return true
94
95 case reflect.String:
96 return x.String() == y.String()
97
98 case reflect.Bool:
99 return x.Bool() == y.Bool()
100
101 case reflect.Int:
102 return x.Int() == y.Int()
103
104 default:
105 panic(x)
106 }
107 }
108
View as plain text