import copy class Matcher(object): matchers = [] def __init__(self, cls, name, children=(), toplevel=False): self.cls = cls self.name = name self.children = children self.toplevel = toplevel self.setName = None def __call__(self, *children): self = copy.deepcopy(self) if self.toplevel: self.matchers.append(self) self.children = list(self.children) for child in children: for i in range(len(self.matchers)): if self.matchers[i] == child: del self.matchers[i] break matcher = Matcher(child.cls, child.name, tuple(child.children), toplevel=False) matcher.set(child.setName) self.children.append(matcher) self.children = tuple(self.children) return self def match(self, pattern, tree): if not isinstance(tree, self.cls): return None if self.setName != None: value = pattern.setValue(self.setName) value.append(tree) if len(self.children) == 0: return tree else: ret = [] for branch in tree: for child in self.children: match = child.match(pattern, branch) if match != None: ret.append(match) return ret def set(self, name=None): self.setName = name return self def __getattr__(self, name): return Matcher(getattr(self.cls, name), self.name + '.' + name) def __repr__(self): return self.name + `self.children` class Pattern(object): def __init__(self, namespace=None): self.namespace = namespace def __call__(self, func): names = func.func_code.co_names for name in names: try: cls = getattr(self.namespace, name) func.func_globals[name] = Matcher(cls, name, toplevel=True) except: pass if func.func_code.co_argcount == 1: func(self) else: func() return Matcher.matchers[-1] def match(self, tree): return self.__pattern__.match(self, tree) def __getattr__(self, name): try: value = object.__getattr__(self, name) return value except: pass return name def setValue(self, name): try: return object.__getattribute__(self, name) except: pass value = [] setattr(self, name, value) return value