11 var tokensByString = map[string]Token{
12 "INT": Token(token.INT),
13 "FLOAT": Token(token.FLOAT),
14 "IMAG": Token(token.IMAG),
15 "CHAR": Token(token.CHAR),
16 "STRING": Token(token.STRING),
17 "+": Token(token.ADD),
18 "-": Token(token.SUB),
19 "*": Token(token.MUL),
20 "/": Token(token.QUO),
21 "%": Token(token.REM),
22 "&": Token(token.AND),
24 "^": Token(token.XOR),
25 "<<": Token(token.SHL),
26 ">>": Token(token.SHR),
27 "&^": Token(token.AND_NOT),
28 "+=": Token(token.ADD_ASSIGN),
29 "-=": Token(token.SUB_ASSIGN),
30 "*=": Token(token.MUL_ASSIGN),
31 "/=": Token(token.QUO_ASSIGN),
32 "%=": Token(token.REM_ASSIGN),
33 "&=": Token(token.AND_ASSIGN),
34 "|=": Token(token.OR_ASSIGN),
35 "^=": Token(token.XOR_ASSIGN),
36 "<<=": Token(token.SHL_ASSIGN),
37 ">>=": Token(token.SHR_ASSIGN),
38 "&^=": Token(token.AND_NOT_ASSIGN),
39 "&&": Token(token.LAND),
40 "||": Token(token.LOR),
41 "<-": Token(token.ARROW),
42 "++": Token(token.INC),
43 "--": Token(token.DEC),
44 "==": Token(token.EQL),
45 "<": Token(token.LSS),
46 ">": Token(token.GTR),
47 "=": Token(token.ASSIGN),
48 "!": Token(token.NOT),
49 "!=": Token(token.NEQ),
50 "<=": Token(token.LEQ),
51 ">=": Token(token.GEQ),
52 ":=": Token(token.DEFINE),
53 "...": Token(token.ELLIPSIS),
54 "IMPORT": Token(token.IMPORT),
55 "VAR": Token(token.VAR),
56 "TYPE": Token(token.TYPE),
57 "CONST": Token(token.CONST),
60 func maybeToken(node Node) (Node, bool) {
61 if node, ok := node.(String); ok {
62 if tok, ok := tokensByString[string(node)]; ok {
70 func isNil(v interface{}) bool {
74 if _, ok := v.(Nil); ok {
80 type matcher interface {
81 Match(*Matcher, interface{}) (interface{}, bool)
84 type State = map[string]interface{}
91 func (m *Matcher) fork() *Matcher {
92 state := make(State, len(m.State))
93 for k, v := range m.State {
97 TypesInfo: m.TypesInfo,
102 func (m *Matcher) merge(mc *Matcher) {
106 func (m *Matcher) Match(a Node, b ast.Node) bool {
108 _, ok := match(m, a, b)
112 func Match(a Node, b ast.Node) (*Matcher, bool) {
118 // Match two items, which may be (Node, AST) or (AST, AST)
119 func match(m *Matcher, l, r interface{}) (interface{}, bool) {
120 if _, ok := r.(Node); ok {
121 panic("Node mustn't be on right side of match")
124 switch l := l.(type) {
126 return match(m, l.X, r)
128 return match(m, l.X, r)
130 return match(m, l.Decl, r)
131 case *ast.LabeledStmt:
132 return match(m, l.Stmt, r)
134 return match(m, l.List, r)
136 return match(m, l.List, r)
139 switch r := r.(type) {
141 return match(m, l, r.X)
143 return match(m, l, r.X)
145 return match(m, l, r.Decl)
146 case *ast.LabeledStmt:
147 return match(m, l, r.Stmt)
150 return match(m, l, nil)
152 return match(m, l, r.List)
155 return match(m, l, nil)
157 return match(m, l, r.List)
160 return match(m, l, nil)
164 if l, ok := l.(matcher); ok {
168 if l, ok := l.(Node); ok {
169 // Matching of pattern with concrete value
170 return matchNodeAST(m, l, r)
173 if l == nil || r == nil {
178 ln, ok1 := l.(ast.Node)
179 rn, ok2 := r.(ast.Node)
181 return matchAST(m, ln, rn)
186 obj, ok := l.(types.Object)
188 switch r := r.(type) {
190 return obj, obj == m.TypesInfo.ObjectOf(r)
191 case *ast.SelectorExpr:
192 return obj, obj == m.TypesInfo.ObjectOf(r.Sel)
200 ln, ok1 := l.([]ast.Expr)
201 rn, ok2 := r.([]ast.Expr)
204 rn = []ast.Expr{r.(ast.Expr)}
205 } else if !ok1 && ok2 {
206 ln = []ast.Expr{l.(ast.Expr)}
209 if len(ln) != len(rn) {
212 for i, ll := range ln {
213 if _, ok := match(m, ll, rn[i]); !ok {
222 ln, ok1 := l.([]ast.Stmt)
223 rn, ok2 := r.([]ast.Stmt)
226 rn = []ast.Stmt{r.(ast.Stmt)}
227 } else if !ok1 && ok2 {
228 ln = []ast.Stmt{l.(ast.Stmt)}
231 if len(ln) != len(rn) {
234 for i, ll := range ln {
235 if _, ok := match(m, ll, rn[i]); !ok {
244 ln, ok1 := l.([]*ast.Field)
245 rn, ok2 := r.([]*ast.Field)
248 rn = []*ast.Field{r.(*ast.Field)}
249 } else if !ok1 && ok2 {
250 ln = []*ast.Field{l.(*ast.Field)}
253 if len(ln) != len(rn) {
256 for i, ll := range ln {
257 if _, ok := match(m, ll, rn[i]); !ok {
265 panic(fmt.Sprintf("unsupported comparison: %T and %T", l, r))
268 // Match a Node with an AST node
269 func matchNodeAST(m *Matcher, a Node, b interface{}) (interface{}, bool) {
270 switch b := b.(type) {
272 // 'a' is not a List or we'd be using its Match
278 return match(m, a, b[0])
280 // 'a' is not a List or we'd be using its Match
286 return match(m, a, b[0])
288 ra := reflect.ValueOf(a)
289 rb := reflect.ValueOf(b).Elem()
291 if ra.Type().Name() != rb.Type().Name() {
295 for i := 0; i < ra.NumField(); i++ {
297 fieldName := ra.Type().Field(i).Name
298 bf := rb.FieldByName(fieldName)
299 if (bf == reflect.Value{}) {
300 panic(fmt.Sprintf("internal error: could not find field %s in type %t when comparing with %T", fieldName, b, a))
307 if _, ok := match(m, ai.(Node), bi); !ok {
313 return nil, a == Nil{}
315 panic(fmt.Sprintf("unhandled type %T", b))
319 // Match two AST nodes
320 func matchAST(m *Matcher, a, b ast.Node) (interface{}, bool) {
321 ra := reflect.ValueOf(a)
322 rb := reflect.ValueOf(b)
324 if ra.Type() != rb.Type() {
327 if ra.IsNil() || rb.IsNil() {
328 return rb, ra.IsNil() == rb.IsNil()
333 for i := 0; i < ra.NumField(); i++ {
336 if af.Type() == rtTokPos || af.Type() == rtObject || af.Type() == rtCommentGroup {
342 if af.Len() != bf.Len() {
345 for j := 0; j < af.Len(); j++ {
346 if _, ok := match(m, af.Index(j).Interface().(ast.Node), bf.Index(j).Interface().(ast.Node)); !ok {
351 if af.String() != bf.String() {
355 if af.Int() != bf.Int() {
359 if af.Bool() != bf.Bool() {
362 case reflect.Ptr, reflect.Interface:
363 if _, ok := match(m, af.Interface(), bf.Interface()); !ok {
367 panic(fmt.Sprintf("internal error: unhandled kind %s (%T)", af.Kind(), af.Interface()))
373 func (b Binding) Match(m *Matcher, node interface{}) (interface{}, bool) {
375 v, ok := m.State[b.Name]
378 return match(m, v, node)
385 if _, ok := m.State[b.Name]; ok {
386 panic(fmt.Sprintf("binding already created: %s", b.Name))
388 new, ret := match(m, b.Node, node)
390 m.State[b.Name] = new
395 func (Any) Match(m *Matcher, node interface{}) (interface{}, bool) {
399 func (l List) Match(m *Matcher, node interface{}) (interface{}, bool) {
400 v := reflect.ValueOf(node)
401 if v.Kind() == reflect.Slice {
403 return node, v.Len() == 0
408 // OPT(dh): don't check the entire tail if head didn't match
409 _, ok1 := match(m, l.Head, v.Index(0).Interface())
410 _, ok2 := match(m, l.Tail, v.Slice(1, v.Len()).Interface())
411 return node, ok1 && ok2
413 // Our empty list does not equal an untyped Go nil. This way, we can
414 // tell apart an if with no else and an if with an empty else.
418 func (s String) Match(m *Matcher, node interface{}) (interface{}, bool) {
419 switch o := node.(type) {
421 if tok, ok := maybeToken(s); ok {
422 return match(m, tok, node)
426 return o, string(s) == o
432 func (tok Token) Match(m *Matcher, node interface{}) (interface{}, bool) {
433 o, ok := node.(token.Token)
437 return o, token.Token(tok) == o
440 func (Nil) Match(m *Matcher, node interface{}) (interface{}, bool) {
441 return nil, isNil(node)
444 func (builtin Builtin) Match(m *Matcher, node interface{}) (interface{}, bool) {
445 ident, ok := node.(*ast.Ident)
449 obj := m.TypesInfo.ObjectOf(ident)
450 if obj != types.Universe.Lookup(ident.Name) {
453 return match(m, builtin.Name, ident.Name)
456 func (obj Object) Match(m *Matcher, node interface{}) (interface{}, bool) {
457 ident, ok := node.(*ast.Ident)
462 id := m.TypesInfo.ObjectOf(ident)
463 _, ok = match(m, obj.Name, ident.Name)
467 func (fn Function) Match(m *Matcher, node interface{}) (interface{}, bool) {
470 switch node := node.(type) {
472 obj = m.TypesInfo.ObjectOf(node)
473 switch obj := obj.(type) {
475 // OPT(dh): optimize this similar to code.FuncName
476 name = obj.FullName()
482 case *ast.SelectorExpr:
484 obj, ok = m.TypesInfo.ObjectOf(node.Sel).(*types.Func)
488 // OPT(dh): optimize this similar to code.FuncName
489 name = obj.(*types.Func).FullName()
493 _, ok := match(m, fn.Name, name)
497 func (or Or) Match(m *Matcher, node interface{}) (interface{}, bool) {
498 for _, opt := range or.Nodes {
500 if ret, ok := match(mc, opt, node); ok {
508 func (not Not) Match(m *Matcher, node interface{}) (interface{}, bool) {
509 _, ok := match(m, not.Node, node)
517 // Types of fields in go/ast structs that we want to skip
518 rtTokPos = reflect.TypeOf(token.Pos(0))
519 rtObject = reflect.TypeOf((*ast.Object)(nil))
520 rtCommentGroup = reflect.TypeOf((*ast.CommentGroup)(nil))
524 _ matcher = Binding{}
527 _ matcher = String("")
530 _ matcher = Builtin{}
532 _ matcher = Function{}