<s> import regex <EOL> from collections import namedtuple <EOL> Attr = namedtuple ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> Pseudo = namedtuple ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> class Selector ( object ) : <EOL> DESCENDANT = '<STR_LIT:U+0020>' <EOL> CHILD = '<STR_LIT:>>' <EOL> SIBLING = '<STR_LIT>' <EOL> ADJACENT = '<STR_LIT:+>' <EOL> NOT_SET = None <EOL> class RE ( object ) : <EOL> id = r'<STR_LIT>' <EOL> ws = r'<STR_LIT>' <EOL> comma = '<STR_LIT>' . format ( ws = ws ) <EOL> combinator = r'<STR_LIT>' . format ( ws = ws ) <EOL> type_selector = '<STR_LIT>' . format ( id = id ) <EOL> id_selector = '<STR_LIT>' . format ( id = id ) <EOL> class_selector = r'<STR_LIT>' + id + '<STR_LIT:)>' <EOL> pseudo_selector = r'<STR_LIT>' . format ( id = id ) <EOL> attr_selector = r'<STR_LIT>' . format ( <EOL> id = id , ws = ws ) <EOL> selector = '<STR_LIT>' . format ( <EOL> typ = id , id = id_selector , cls = class_selector , pseudo = pseudo_selector , <EOL> attr = attr_selector ) <EOL> def __init__ ( self , name , combinator = None ) : <EOL> self . name = name <EOL> self . combinator = combinator <EOL> self . next_selector = None <EOL> selector_patterns = { <EOL> '<STR_LIT>' : self . RE . type_selector , <EOL> '<STR_LIT>' : self . RE . id_selector , <EOL> '<STR_LIT>' : self . RE . class_selector , <EOL> '<STR_LIT>' : self . RE . pseudo_selector , <EOL> '<STR_LIT>' : self . RE . attr_selector , <EOL> } <EOL> matches = { } <EOL> while True : <EOL> pattern_matched = False <EOL> for key , pattern in selector_patterns . items ( ) : <EOL> match = regex . search ( r'<STR_LIT>' . format ( pattern ) , name ) <EOL> if match : <EOL> i , pos = match . span ( ) <EOL> if key not in matches : <EOL> matches [ key ] = [ ] <EOL> matches [ key ] . append ( match . groups ( ) ) <EOL> name = name [ pos : ] <EOL> pattern_matched = True <EOL> if not pattern_matched : <EOL> break <EOL> self . typ = None <EOL> for types in matches . pop ( '<STR_LIT>' , [ ] ) : <EOL> self . typ = types [ <NUM_LIT:0> ] <EOL> self . id_ = None <EOL> for ids in matches . pop ( '<STR_LIT>' , [ ] ) : <EOL> self . id_ = ids [ <NUM_LIT:0> ] <EOL> self . classes = [ a [ <NUM_LIT:0> ] for a in matches . pop ( '<STR_LIT>' , [ ] ) ] <EOL> self . attrs = [ <EOL> Attr ( l , o , r . strip ( ) ) <EOL> for l , o , r in matches . pop ( '<STR_LIT>' , [ ] ) <EOL> ] <EOL> self . pseudos = [ <EOL> Pseudo ( * a [ <NUM_LIT:1> : ] ) <EOL> for a in matches . pop ( '<STR_LIT>' , [ ] ) <EOL> ] <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' . format ( self . name ) <EOL> @ classmethod <EOL> def parse ( cls , string ) : <EOL> selectors = [ ] <EOL> combinator = None <EOL> prev_selector = None <EOL> while True : <EOL> match = regex . search ( cls . RE . comma , string ) <EOL> if match : <EOL> _ , pos = match . span ( ) <EOL> string = string [ pos : ] <EOL> continue <EOL> match = regex . search ( cls . RE . combinator , string ) <EOL> if match : <EOL> _ , pos = match . span ( ) <EOL> combinator = string [ : pos ] . strip ( ) <EOL> string = string [ pos : ] <EOL> else : <EOL> combinator = None <EOL> match = regex . search ( cls . RE . selector , string ) <EOL> if match : <EOL> _ , pos = match . span ( ) <EOL> seltext = string [ : pos ] <EOL> string = string [ pos : ] <EOL> selector = cls ( seltext , combinator = combinator ) <EOL> if combinator is not None and prev_selector : <EOL> prev_selector . next_selector = prev_selector = selector <EOL> else : <EOL> prev_selector = selector <EOL> selectors . append ( selector ) <EOL> continue <EOL> break <EOL> return selectors </s>
