<s> from . selector import Selector <EOL> class MatchEngine ( object ) : <EOL> pseudo_fns = { } <EOL> selector_class = Selector <EOL> def __init__ ( self ) : <EOL> self . register_pseudo ( '<STR_LIT>' , self . pseudo_not ) <EOL> self . register_pseudo ( '<STR_LIT>' , self . pseudo_has ) <EOL> def register_pseudo ( self , name , fn ) : <EOL> self . pseudo_fns [ name ] = fn <EOL> @ staticmethod <EOL> def pseudo_not ( matcher , node , value ) : <EOL> return not matcher . match_node ( matcher . parse_selector ( value ) [ <NUM_LIT:0> ] , node ) <EOL> @ staticmethod <EOL> def pseudo_has ( matcher , node , value ) : <EOL> for node , body in matcher . iter_data ( [ node ] ) : <EOL> if body : <EOL> return any ( <EOL> matcher . match_data ( matcher . parse_selector ( value ) [ <NUM_LIT:0> ] , body ) ) <EOL> def parse_selector ( self , selector ) : <EOL> return self . selector_class . parse ( selector ) <EOL> def match ( self , selector , data ) : <EOL> selectors = self . parse_selector ( selector ) <EOL> nodeids = { } <EOL> for selector in selectors : <EOL> for node in self . match_data ( selector , data ) : <EOL> nodeid = id ( node ) <EOL> if nodeid not in nodeids : <EOL> nodeids [ nodeid ] = None <EOL> yield node <EOL> def match_data ( self , selector , data ) : <EOL> for node , body in self . _iter_data ( data ) : <EOL> match = self . match_node ( selector , node ) <EOL> if match : <EOL> next_selector = selector . next_selector <EOL> if next_selector : <EOL> if body : <EOL> for node in self . match_data ( next_selector , body ) : <EOL> yield node <EOL> else : <EOL> yield node <EOL> if body and not selector . combinator == self . selector_class . CHILD : <EOL> for node in self . match_data ( selector , body ) : <EOL> yield node <EOL> def match_node ( self , selector , node ) : <EOL> match = all ( self . match_rules ( selector , node ) ) <EOL> if match and selector . attrs : <EOL> match &= all ( self . match_attrs ( selector , node ) ) <EOL> if match and selector . pseudos : <EOL> match &= all ( self . match_pseudos ( selector , node ) ) <EOL> return match <EOL> def match_rules ( self , selector , node ) : <EOL> if selector . typ : <EOL> yield self . match_type ( selector . typ , node ) <EOL> if selector . id_ : <EOL> yield self . match_id ( selector . id_ , node ) <EOL> def match_attrs ( self , selector , node ) : <EOL> for a in selector . attrs : <EOL> lft , op , rgt = a <EOL> yield self . match_attr ( lft , op , rgt , node ) <EOL> def match_pseudos ( self , selector , d ) : <EOL> for p in selector . pseudos : <EOL> name , value = p <EOL> if name not in self . pseudo_fns : <EOL> raise Exception ( '<STR_LIT>' . format ( name ) ) <EOL> yield self . pseudo_fns [ name ] ( self , d , value ) <EOL> def _iter_data ( self , data ) : <EOL> for tupl in self . iter_data ( data ) : <EOL> if len ( tupl ) != <NUM_LIT:2> : <EOL> raise Exception ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> yield tupl <EOL> def match_type ( self , typ , node ) : <EOL> raise NotImplementedError <EOL> def match_id ( self , id_ , node ) : <EOL> raise NotImplementedError <EOL> def match_attr ( self , lft , op , rgt , no ) : <EOL> raise NotImplementedError <EOL> def iter_data ( self , data ) : <EOL> raise NotImplementedError </s>
