183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright 2006 Google, Inc. All Rights Reserved. 283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Licensed to PSF under a Contributor Agreement. 383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh""" 583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehPython parse tree definitions. 683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehThis is a very concrete parse tree; we need to keep every token and 883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieheven the comments and whitespace between tokens. 983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehThere's also a pattern matching implementation here. 1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh""" 1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh__author__ = "Guido van Rossum <guido@python.org>" 1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport sys 1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport warnings 1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom StringIO import StringIO 1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehHUGE = 0x7FFFFFFF # maximum repeat count, default max 2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh_type_reprs = {} 2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef type_repr(type_num): 2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh global _type_reprs 2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not _type_reprs: 2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh from .pygram import python_symbols 2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # printing tokens is possible but not as useful 2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # from .pgen2 import token // token.__dict__.items(): 2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for name, val in python_symbols.__dict__.items(): 2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type(val) == int: _type_reprs[val] = name 3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _type_reprs.setdefault(type_num, type_num) 3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Base(object): 3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Abstract base class for Node and Leaf. 3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This provides some default functionality and boilerplate using the 3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh template pattern. 3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh A node may be a subnode of at most one parent. 4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Default values for instance variables 4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh type = None # int: token number (< 256) or symbol number (>= 256) 4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parent = None # Parent node pointer, or None 4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh children = () # Tuple of subnodes 4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh was_changed = False 4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh was_checked = False 4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __new__(cls, *args, **kwds): 5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Constructor that prevents Base from being instantiated.""" 5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert cls is not Base, "Cannot instantiate Base" 5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return object.__new__(cls) 5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __eq__(self, other): 5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Compare two nodes for equality. 5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This calls the method _eq(). 6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.__class__ is not other.__class__: 6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return NotImplemented 6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._eq(other) 6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __hash__ = None # For Py3 compatibility. 6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __ne__(self, other): 6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Compare two nodes for inequality. 7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This calls the method _eq(). 7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.__class__ is not other.__class__: 7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return NotImplemented 7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return not self._eq(other) 7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _eq(self, other): 7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Compare two nodes for equality. 8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This is called by __eq__ and __ne__. It is only called if the two nodes 8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh have the same type. This must be implemented by the concrete subclass. 8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Nodes should be considered equal if they have the same structure, 8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ignoring the prefix string and other context information. 8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError 8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def clone(self): 8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Return a cloned (deep) copy of self. 9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This must be implemented by the concrete subclass. 9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError 9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def post_order(self): 9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Return a post-order iterator for the tree. 9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This must be implemented by the concrete subclass. 10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError 10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def pre_order(self): 10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Return a pre-order iterator for the tree. 10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This must be implemented by the concrete subclass. 10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError 11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def set_prefix(self, prefix): 11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Set the prefix for the node (see Leaf class). 11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh DEPRECATED; use the prefix property directly. 11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh warnings.warn("set_prefix() is deprecated; use the prefix property", 11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh DeprecationWarning, stacklevel=2) 12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.prefix = prefix 12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def get_prefix(self): 12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Return the prefix for the node (see Leaf class). 12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh DEPRECATED; use the prefix property directly. 12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh warnings.warn("get_prefix() is deprecated; use the prefix property", 12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh DeprecationWarning, stacklevel=2) 13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.prefix 13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def replace(self, new): 13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Replace this node with a new one in the parent.""" 13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert self.parent is not None, str(self) 13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert new is not None 13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not isinstance(new, list): 13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new = [new] 13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh l_children = [] 13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh found = False 14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for ch in self.parent.children: 14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if ch is self: 14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert not found, (self.parent.children, self, new) 14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if new is not None: 14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh l_children.extend(new) 14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh found = True 14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh l_children.append(ch) 14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert found, (self.children, self, new) 14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.parent.changed() 15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.parent.children = l_children 15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for x in new: 15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh x.parent = self.parent 15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.parent = None 15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def get_lineno(self): 15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return the line number which generated the invocant node.""" 15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh node = self 15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while not isinstance(node, Leaf): 15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not node.children: 16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return 16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh node = node.children[0] 16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return node.lineno 16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def changed(self): 16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.parent: 16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.parent.changed() 16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.was_changed = True 16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def remove(self): 17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Remove the node from the tree. Returns the position of the node in its 17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parent's children before it was removed. 17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.parent: 17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for i, node in enumerate(self.parent.children): 17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if node is self: 17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.parent.changed() 17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self.parent.children[i] 17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.parent = None 18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return i 18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh @property 18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def next_sibling(self): 18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The node immediately following the invocant in their parent's children 18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh list. If the invocant does not have a next sibling, it is None 18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.parent is None: 18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return None 19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Can't use index(); we need to test by identity 19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for i, child in enumerate(self.parent.children): 19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if child is self: 19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.parent.children[i+1] 19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except IndexError: 19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return None 19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh @property 20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def prev_sibling(self): 20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The node immediately preceding the invocant in their parent's children 20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh list. If the invocant does not have a previous sibling, it is None. 20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.parent is None: 20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return None 20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Can't use index(); we need to test by identity 20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for i, child in enumerate(self.parent.children): 21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if child is self: 21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if i == 0: 21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return None 21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.parent.children[i-1] 21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def leaves(self): 21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for child in self.children: 21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for x in child.leaves(): 21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield x 21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def depth(self): 22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.parent is None: 22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return 0 22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return 1 + self.parent.depth() 22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def get_suffix(self): 22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Return the string immediately following the invocant node. This is 22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh effectively equivalent to node.next_sibling.prefix 22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh next_sib = self.next_sibling 23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if next_sib is None: 23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return u"" 23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return next_sib.prefix 23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if sys.version_info < (3, 0): 23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __str__(self): 23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return unicode(self).encode("ascii") 23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Node(Base): 24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Concrete implementation for interior nodes.""" 24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self,type, children, 24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh context=None, 24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh prefix=None, 24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh fixers_applied=None): 24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Initializer. 24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Takes a type constant (a symbol number >= 256), a sequence of 25183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh child nodes, and an optional context keyword argument. 25283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh As a side effect, the parent pointers of the children are updated. 25483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 25583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert type >= 256, type 25683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.type = type 25783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.children = list(children) 25883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for ch in self.children: 25983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert ch.parent is None, repr(ch) 26083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ch.parent = self 26183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if prefix is not None: 26283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.prefix = prefix 26383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if fixers_applied: 26483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.fixers_applied = fixers_applied[:] 26583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 26683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.fixers_applied = None 26783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 26883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 26983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a canonical string representation.""" 27083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "%s(%s, %r)" % (self.__class__.__name__, 27183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh type_repr(self.type), 27283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.children) 27383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 27483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __unicode__(self): 27583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 27683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Return a pretty string representation. 27783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 27883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This reproduces the input source exactly. 27983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 28083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return u"".join(map(unicode, self.children)) 28183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 28283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if sys.version_info > (3, 0): 28383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __str__ = __unicode__ 28483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 28583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _eq(self, other): 28683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Compare two nodes for equality.""" 28783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return (self.type, self.children) == (other.type, other.children) 28883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 28983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def clone(self): 29083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a cloned (deep) copy of self.""" 29183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return Node(self.type, [ch.clone() for ch in self.children], 29283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh fixers_applied=self.fixers_applied) 29383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 29483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def post_order(self): 29583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a post-order iterator for the tree.""" 29683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for child in self.children: 29783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for node in child.post_order(): 29883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield node 29983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield self 30083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 30183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def pre_order(self): 30283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a pre-order iterator for the tree.""" 30383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield self 30483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for child in self.children: 30583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for node in child.pre_order(): 30683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield node 30783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 30883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _prefix_getter(self): 30983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 31083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The whitespace and comments preceding this node in the input. 31183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 31283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not self.children: 31383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "" 31483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.children[0].prefix 31583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 31683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _prefix_setter(self, prefix): 31783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.children: 31883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.children[0].prefix = prefix 31983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 32083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh prefix = property(_prefix_getter, _prefix_setter) 32183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 32283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def set_child(self, i, child): 32383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 32483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Equivalent to 'node.children[i] = child'. This method also sets the 32583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh child's parent attribute appropriately. 32683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 32783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh child.parent = self 32883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.children[i].parent = None 32983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.children[i] = child 33083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.changed() 33183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 33283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def insert_child(self, i, child): 33383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 33483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Equivalent to 'node.children.insert(i, child)'. This method also sets 33583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh the child's parent attribute appropriately. 33683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 33783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh child.parent = self 33883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.children.insert(i, child) 33983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.changed() 34083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 34183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def append_child(self, child): 34283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 34383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Equivalent to 'node.children.append(child)'. This method also sets the 34483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh child's parent attribute appropriately. 34583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 34683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh child.parent = self 34783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.children.append(child) 34883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.changed() 34983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 35083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 35183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Leaf(Base): 35283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 35383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Concrete implementation for leaf nodes.""" 35483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 35583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Default values for instance variables 35683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh _prefix = "" # Whitespace and comments preceding this token in the input 35783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh lineno = 0 # Line where this token starts in the input 35883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh column = 0 # Column where this token tarts in the input 35983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 36083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, type, value, 36183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh context=None, 36283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh prefix=None, 36383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh fixers_applied=[]): 36483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 36583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Initializer. 36683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 36783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Takes a type constant (a token number < 256), a string value, and an 36883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh optional context keyword argument. 36983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 37083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert 0 <= type < 256, type 37183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if context is not None: 37283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._prefix, (self.lineno, self.column) = context 37383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.type = type 37483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.value = value 37583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if prefix is not None: 37683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._prefix = prefix 37783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.fixers_applied = fixers_applied[:] 37883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 37983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 38083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a canonical string representation.""" 38183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "%s(%r, %r)" % (self.__class__.__name__, 38283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.type, 38383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.value) 38483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 38583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __unicode__(self): 38683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 38783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Return a pretty string representation. 38883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 38983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This reproduces the input source exactly. 39083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 39183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.prefix + unicode(self.value) 39283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 39383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if sys.version_info > (3, 0): 39483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __str__ = __unicode__ 39583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 39683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _eq(self, other): 39783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Compare two nodes for equality.""" 39883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return (self.type, self.value) == (other.type, other.value) 39983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 40083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def clone(self): 40183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a cloned (deep) copy of self.""" 40283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return Leaf(self.type, self.value, 40383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (self.prefix, (self.lineno, self.column)), 40483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh fixers_applied=self.fixers_applied) 40583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 40683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def leaves(self): 40783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield self 40883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 40983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def post_order(self): 41083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a post-order iterator for the tree.""" 41183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield self 41283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 41383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def pre_order(self): 41483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a pre-order iterator for the tree.""" 41583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield self 41683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 41783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _prefix_getter(self): 41883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 41983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The whitespace and comments preceding this token in the input. 42083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 42183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._prefix 42283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 42383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _prefix_setter(self, prefix): 42483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.changed() 42583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._prefix = prefix 42683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 42783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh prefix = property(_prefix_getter, _prefix_setter) 42883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 42983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef convert(gr, raw_node): 43083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 43183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Convert raw node information to a Node or Leaf instance. 43283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 43383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This is passed to the parser driver which calls it whenever a reduction of a 43483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh grammar rule produces a new complete node, so that the tree is build 43583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh strictly bottom-up. 43683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 43783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh type, value, context, children = raw_node 43883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if children or type in gr.number2symbol: 43983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # If there's exactly one child, return that child instead of 44083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # creating a new node. 44183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(children) == 1: 44283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return children[0] 44383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return Node(type, children, context=context) 44483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 44583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return Leaf(type, value, context=context) 44683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 44783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 44883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass BasePattern(object): 44983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 45083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 45183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh A pattern is a tree matching pattern. 45283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 45383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh It looks for a specific node type (token or symbol), and 45483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh optionally for a specific content. 45583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 45683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This is an abstract base class. There are three concrete 45783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh subclasses: 45883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 45983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh - LeafPattern matches a single leaf node; 46083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh - NodePattern matches a single node (usually non-leaf); 46183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh - WildcardPattern matches a sequence of nodes of variable length. 46283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 46383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 46483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Defaults for instance variables 46583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh type = None # Node type (token if < 256, symbol if >= 256) 46683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh content = None # Optional content matching pattern 46783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name = None # Optional name used to store match in results dict 46883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 46983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __new__(cls, *args, **kwds): 47083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Constructor that prevents BasePattern from being instantiated.""" 47183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert cls is not BasePattern, "Cannot instantiate BasePattern" 47283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return object.__new__(cls) 47383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 47483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 47583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh args = [type_repr(self.type), self.content, self.name] 47683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while args and args[-1] is None: 47783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del args[-1] 47883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "%s(%s)" % (self.__class__.__name__, ", ".join(map(repr, args))) 47983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 48083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def optimize(self): 48183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 48283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh A subclass can define this as a hook for optimizations. 48383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 48483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Returns either self or another node with the same effect. 48583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 48683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self 48783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 48883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def match(self, node, results=None): 48983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 49083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Does this pattern exactly match a node? 49183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 49283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Returns True if it matches, False if not. 49383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 49483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If results is not None, it must be a dict which will be 49583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh updated with the nodes matching named subpatterns. 49683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 49783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Default implementation for non-wildcard patterns. 49883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 49983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.type is not None and node.type != self.type: 50083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 50183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.content is not None: 50283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = None 50383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if results is not None: 50483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = {} 50583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not self._submatch(node, r): 50683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 50783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if r: 50883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results.update(r) 50983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if results is not None and self.name: 51083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results[self.name] = node 51183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return True 51283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 51383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def match_seq(self, nodes, results=None): 51483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 51583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Does this pattern exactly match a sequence of nodes? 51683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 51783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Default implementation for non-wildcard patterns. 51883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 51983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(nodes) != 1: 52083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 52183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.match(nodes[0], results) 52283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 52383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def generate_matches(self, nodes): 52483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 52583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Generator yielding all matches for this pattern. 52683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 52783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Default implementation for non-wildcard patterns. 52883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 52983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = {} 53083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if nodes and self.match(nodes[0], r): 53183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield 1, r 53283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 53383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 53483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass LeafPattern(BasePattern): 53583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 53683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, type=None, content=None, name=None): 53783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 53883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Initializer. Takes optional type, content, and name. 53983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 54083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The type, if given must be a token type (< 256). If not given, 54183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh this matches any *leaf* node; the content may still be required. 54283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 54383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The content, if given, must be a string. 54483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 54583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If a name is given, the matching node is stored in the results 54683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dict under that key. 54783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 54883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type is not None: 54983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert 0 <= type < 256, type 55083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if content is not None: 55183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert isinstance(content, basestring), repr(content) 55283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.type = type 55383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.content = content 55483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.name = name 55583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 55683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def match(self, node, results=None): 55783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Override match() to insist on a leaf node.""" 55883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not isinstance(node, Leaf): 55983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 56083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return BasePattern.match(self, node, results) 56183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 56283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _submatch(self, node, results=None): 56383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 56483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Match the pattern's content to the node's children. 56583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 56683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This assumes the node type matches and self.content is not None. 56783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 56883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Returns True if it matches, False if not. 56983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 57083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If results is not None, it must be a dict which will be 57183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh updated with the nodes matching named subpatterns. 57283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 57383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh When returning False, the results dict may still be updated. 57483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 57583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.content == node.value 57683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 57783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 57883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass NodePattern(BasePattern): 57983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 58083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh wildcards = False 58183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 58283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, type=None, content=None, name=None): 58383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 58483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Initializer. Takes optional type, content, and name. 58583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 58683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The type, if given, must be a symbol type (>= 256). If the 58783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh type is None this matches *any* single node (leaf or not), 58883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except if content is not None, in which it only matches 58983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh non-leaf nodes that also match the content pattern. 59083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 59183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The content, if not None, must be a sequence of Patterns that 59283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh must match the node's children exactly. If the content is 59383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh given, the type must not be None. 59483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 59583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If a name is given, the matching node is stored in the results 59683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dict under that key. 59783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 59883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type is not None: 59983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert type >= 256, type 60083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if content is not None: 60183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert not isinstance(content, basestring), repr(content) 60283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh content = list(content) 60383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for i, item in enumerate(content): 60483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert isinstance(item, BasePattern), (i, item) 60583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(item, WildcardPattern): 60683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.wildcards = True 60783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.type = type 60883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.content = content 60983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.name = name 61083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 61183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _submatch(self, node, results=None): 61283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 61383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Match the pattern's content to the node's children. 61483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 61583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This assumes the node type matches and self.content is not None. 61683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 61783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Returns True if it matches, False if not. 61883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 61983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If results is not None, it must be a dict which will be 62083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh updated with the nodes matching named subpatterns. 62183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 62283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh When returning False, the results dict may still be updated. 62383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 62483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.wildcards: 62583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c, r in generate_matches(self.content, node.children): 62683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if c == len(node.children): 62783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if results is not None: 62883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results.update(r) 62983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return True 63083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 63183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(self.content) != len(node.children): 63283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 63383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for subpattern, child in zip(self.content, node.children): 63483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not subpattern.match(child, results): 63583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 63683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return True 63783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 63883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 63983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass WildcardPattern(BasePattern): 64083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 64183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 64283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh A wildcard pattern can match zero or more nodes. 64383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 64483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This has all the flexibility needed to implement patterns like: 64583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 64683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh .* .+ .? .{m,n} 64783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (a b c | d e | f) 64883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (...)* (...)+ (...)? (...){m,n} 64983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 65083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except it always uses non-greedy matching. 65183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 65283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 65383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, content=None, min=0, max=HUGE, name=None): 65483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 65583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Initializer. 65683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 65783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Args: 65883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh content: optional sequence of subsequences of patterns; 65983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if absent, matches one node; 66083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if present, each subsequence is an alternative [*] 66183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh min: optional minimum number of times to match, default 0 66283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh max: optional maximum number of times to match, default HUGE 66383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name: optional name assigned to this match 66483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 66583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh [*] Thus, if content is [[a, b, c], [d, e], [f, g, h]] this is 66683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh equivalent to (a b c | d e | f g h); if content is None, 66783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh this is equivalent to '.' in regular expression terms. 66883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The min and max parameters work as follows: 66983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh min=0, max=maxint: .* 67083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh min=1, max=maxint: .+ 67183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh min=0, max=1: .? 67283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh min=1, max=1: . 67383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If content is not None, replace the dot with the parenthesized 67483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh list of alternatives, e.g. (a b c | d e | f g h)* 67583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 67683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert 0 <= min <= max <= HUGE, (min, max) 67783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if content is not None: 67883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh content = tuple(map(tuple, content)) # Protect against alterations 67983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Check sanity of alternatives 68083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert len(content), repr(content) # Can't have zero alternatives 68183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for alt in content: 68283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert len(alt), repr(alt) # Can have empty alternatives 68383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.content = content 68483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.min = min 68583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.max = max 68683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.name = name 68783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 68883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def optimize(self): 68983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Optimize certain stacked wildcard patterns.""" 69083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh subpattern = None 69183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if (self.content is not None and 69283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh len(self.content) == 1 and len(self.content[0]) == 1): 69383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh subpattern = self.content[0][0] 69483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.min == 1 and self.max == 1: 69583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.content is None: 69683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return NodePattern(name=self.name) 69783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if subpattern is not None and self.name == subpattern.name: 69883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return subpattern.optimize() 69983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if (self.min <= 1 and isinstance(subpattern, WildcardPattern) and 70083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh subpattern.min <= 1 and self.name == subpattern.name): 70183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return WildcardPattern(subpattern.content, 70283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.min*subpattern.min, 70383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.max*subpattern.max, 70483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh subpattern.name) 70583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self 70683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 70783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def match(self, node, results=None): 70883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Does this pattern exactly match a node?""" 70983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.match_seq([node], results) 71083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 71183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def match_seq(self, nodes, results=None): 71283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Does this pattern exactly match a sequence of nodes?""" 71383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c, r in self.generate_matches(nodes): 71483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if c == len(nodes): 71583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if results is not None: 71683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results.update(r) 71783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.name: 71883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results[self.name] = list(nodes) 71983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return True 72083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 72183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 72283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def generate_matches(self, nodes): 72383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 72483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Generator yielding matches for a sequence of nodes. 72583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 72683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Args: 72783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh nodes: sequence of nodes 72883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 72983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Yields: 73083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (count, results) tuples where: 73183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh count: the match comprises nodes[:count]; 73283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results: dict containing named submatches. 73383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 73483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.content is None: 73583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Shortcut for special case (see __init__.__doc__) 73683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for count in xrange(self.min, 1 + min(len(nodes), self.max)): 73783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = {} 73883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.name: 73983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r[self.name] = nodes[:count] 74083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield count, r 74183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif self.name == "bare_name": 74283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield self._bare_name_matches(nodes) 74383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 74483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # The reason for this is that hitting the recursion limit usually 74583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # results in some ugly messages about how RuntimeErrors are being 74683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # ignored. We don't do this on non-CPython implementation because 74783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # they don't have this problem. 74883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if hasattr(sys, "getrefcount"): 74983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh save_stderr = sys.stderr 75083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh sys.stderr = StringIO() 75183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 75283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for count, r in self._recursive_matches(nodes, 0): 75383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.name: 75483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r[self.name] = nodes[:count] 75583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield count, r 75683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except RuntimeError: 75783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # We fall back to the iterative pattern matching scheme if the recursive 75883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # scheme hits the recursion limit. 75983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for count, r in self._iterative_matches(nodes): 76083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.name: 76183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r[self.name] = nodes[:count] 76283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield count, r 76383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh finally: 76483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if hasattr(sys, "getrefcount"): 76583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh sys.stderr = save_stderr 76683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 76783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _iterative_matches(self, nodes): 76883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Helper to iteratively yield the matches.""" 76983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh nodelen = len(nodes) 77083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if 0 >= self.min: 77183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield 0, {} 77283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 77383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results = [] 77483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # generate matches that use just one alt from self.content 77583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for alt in self.content: 77683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c, r in generate_matches(alt, nodes): 77783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield c, r 77883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results.append((c, r)) 77983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 78083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # for each match, iterate down the nodes 78183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while results: 78283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new_results = [] 78383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c0, r0 in results: 78483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # stop if the entire set of nodes has been matched 78583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if c0 < nodelen and c0 <= self.max: 78683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for alt in self.content: 78783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c1, r1 in generate_matches(alt, nodes[c0:]): 78883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if c1 > 0: 78983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = {} 79083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r.update(r0) 79183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r.update(r1) 79283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield c0 + c1, r 79383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new_results.append((c0 + c1, r)) 79483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results = new_results 79583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 79683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _bare_name_matches(self, nodes): 79783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Special optimized matcher for bare_name.""" 79883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh count = 0 79983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = {} 80083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh done = False 80183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh max = len(nodes) 80283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while not done and count < max: 80383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh done = True 80483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for leaf in self.content: 80583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if leaf[0].match(nodes[count], r): 80683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh count += 1 80783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh done = False 80883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh break 80983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r[self.name] = nodes[:count] 81083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return count, r 81183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 81283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _recursive_matches(self, nodes, count): 81383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Helper to recursively yield the matches.""" 81483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert self.content is not None 81583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if count >= self.min: 81683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield 0, {} 81783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if count < self.max: 81883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for alt in self.content: 81983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c0, r0 in generate_matches(alt, nodes): 82083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c1, r1 in self._recursive_matches(nodes[c0:], count+1): 82183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = {} 82283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r.update(r0) 82383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r.update(r1) 82483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield c0 + c1, r 82583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 82683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 82783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass NegatedPattern(BasePattern): 82883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 82983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, content=None): 83083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 83183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Initializer. 83283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 83383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The argument is either a pattern or None. If it is None, this 83483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh only matches an empty sequence (effectively '$' in regex 83583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh lingo). If it is not None, this matches whenever the argument 83683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pattern doesn't have any matches. 83783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 83883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if content is not None: 83983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert isinstance(content, BasePattern), repr(content) 84083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.content = content 84183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 84283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def match(self, node): 84383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # We never match a node in its entirety 84483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return False 84583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 84683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def match_seq(self, nodes): 84783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # We only match an empty sequence of nodes in its entirety 84883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return len(nodes) == 0 84983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 85083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def generate_matches(self, nodes): 85183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.content is None: 85283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Return a match if there is an empty sequence 85383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(nodes) == 0: 85483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield 0, {} 85583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 85683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Return a match if the argument pattern has no matches 85783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c, r in self.content.generate_matches(nodes): 85883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return 85983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield 0, {} 86083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 86183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 86283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef generate_matches(patterns, nodes): 86383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 86483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Generator yielding matches for a sequence of patterns and nodes. 86583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 86683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Args: 86783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh patterns: a sequence of patterns 86883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh nodes: a sequence of nodes 86983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 87083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Yields: 87183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (count, results) tuples where: 87283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh count: the entire sequence of patterns matches nodes[:count]; 87383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh results: dict containing named submatches. 87483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 87583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not patterns: 87683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield 0, {} 87783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 87883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh p, rest = patterns[0], patterns[1:] 87983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c0, r0 in p.generate_matches(nodes): 88083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not rest: 88183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield c0, r0 88283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 88383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for c1, r1 in generate_matches(rest, nodes[c0:]): 88483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r = {} 88583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r.update(r0) 88683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh r.update(r1) 88783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh yield c0 + c1, r 888