def parse_block(tokens, variables, selectors, is_merc):
    """ Parse a token stream into an array of declaration tuples.
    
        In addition to tokens, requires a dictionary of declared variables,
        a list of selectors that will apply to the declarations parsed in
        this block, and a boolean flag for mercator projection, both needed
        by possible recursive calls back to parse_rule().
    
        Return an array of (property, value, (line, col), importance).
    
        Enter this function after a left-brace is found:
        http://www.w3.org/TR/CSS2/syndata.html#block
    """
    #
    # Local helper functions
    #

    def parse_value(tokens, variables):
        """ Look for value tokens after a property name, possibly !important.
        """
        value = []
        while True:
            tname, tvalue, line, col = tokens.next()
            if (tname, tvalue) == ('CHAR', '!'):
                while True:
                    tname, tvalue, line, col = tokens.next()
                    if (tname, tvalue) == ('IDENT', 'important'):
                        while True:
                            tname, tvalue, line, col = tokens.next()
                            if (tname, tvalue) == ('CHAR', ';'):
                                #
                                # end of a high-importance value
                                #
                                return value, True
                            elif (tname, tvalue) == ('CHAR', '}'):
                                #
                                # end of a block means end of a value
                                #
                                raise BlockTerminatedValue(value, True, line, col)
                            elif (tname, tvalue) == ('S', '\n'):
                                raise ParseException('Unexpected end of line', line, col)
                            elif tname not in ('S', 'COMMENT'):
                                raise ParseException('Unexpected values after !important declaration', line, col)
                        break
                    else:
                        raise ParseException('Malformed declaration after "!"', line, col)
                break
            elif (tname, tvalue) == ('CHAR', ';'):
                #
                # end of a low-importance value
                #
                return value, False
            elif (tname, tvalue) == ('CHAR', '}'):
                #
                # end of a block means end of a value
                #
                raise BlockTerminatedValue(value, False, line, col)
            elif tname == 'ATKEYWORD':
                #
                # Possible variable use:
                # http://lesscss.org/#-variables
                #
                tokens = chain(iter(variables[tvalue]), tokens)
            elif (tname, tvalue) == ('S', '\n'):
                raise ParseException('Unexpected end of line', line, col)
            elif tname not in ('S', 'COMMENT'):
                #
                # Legitimate-looking value token.
                #
                value.append((tname, tvalue))
        raise ParseException('Malformed property value', line, col)
    
    #
    # The work.
    #
    
    ruleset = []
    property_values = []
    
    while True:
        tname, tvalue, line, col = tokens.next()
        
        if tname == 'IDENT':
            _tname, _tvalue, _line, _col = tokens.next()
            
            if (_tname, _tvalue) == ('CHAR', ':'):
                #
                # Retrieve and process a value after a property name.
                # http://www.w3.org/TR/CSS2/syndata.html#declaration
                #
                if tvalue not in properties:
                    raise ParseException('Unsupported property name, %s' % tvalue, line, col)

                try:
                    property = Property(tvalue)
                    vtokens, importance = parse_value(tokens, variables)
                except BlockTerminatedValue, e:
                    vtokens, importance = e.tokens, e.important
                    tokens = chain([('CHAR', '}', e.line, e.col)], tokens)

                value = postprocess_value(property, vtokens, importance, line, col)
                property_values.append((property, value, (line, col), importance))
                
            else:
                #
                # We may have just found the start of a nested block.
                # http://lesscss.org/#-nested-rules
                #
                tokens_ = chain([(tname, tvalue, line, col), (_tname, _tvalue, _line, _col)], tokens)
                ruleset += parse_rule(tokens_, variables, [], selectors, is_merc)
        
        elif (tname, tvalue) == ('CHAR', '}'):
            #
            # Closing out a block
            #
            for (selector, property_value) in product(selectors, property_values):

                property, value, (line, col), importance = property_value
                sort_key = value.importance(), selector.specificity(), (line, col)

                ruleset.append(Declaration(selector, property, value, sort_key))
                
            return ruleset
        
        elif tname in ('HASH', ) or (tname, tvalue) in [('CHAR', '.'), ('CHAR', '*'), ('CHAR', '['), ('CHAR', '&')]:
            #
            # One of a bunch of valid ways to start a nested rule.
            #
            # Most will end up rejected by Cascadenik as parsing errors,
            # except for identifiers for text rules and the start of
            # nested blocks with a "&" combinator:
            # http://lesscss.org/#-nested-rules
            #
            tokens_ = chain([(tname, tvalue, line, col)], tokens)
            ruleset += parse_rule(tokens_, variables, [], selectors, is_merc)
        
        elif tname not in ('S', 'COMMENT'):
            raise ParseException('Malformed style rule', line, col)

    raise ParseException('Malformed block', line, col)
def parse_block ( tokens , variables , selectors , is_merc ) : def parse_value ( tokens , variables ) : value = [ ] while True : tname , tvalue , line , col = tokens . next ( ) if ( tname , tvalue ) == ( 'CHAR' , '!' ) : while True : tname , tvalue , line , col = tokens . next ( ) if ( tname , tvalue ) == ( 'IDENT' , 'important' ) : while True : tname , tvalue , line , col = tokens . next ( ) if ( tname , tvalue ) == ( 'CHAR' , ';' ) : return value , True elif ( tname , tvalue ) == ( 'CHAR' , '}' ) : raise BlockTerminatedValue ( value , True , line , col ) elif ( tname , tvalue ) == ( 'S' , '\n' ) : raise ParseException ( 'Unexpected end of line' , line , col ) elif tname not in ( 'S' , 'COMMENT' ) : raise ParseException ( 'Unexpected values after !important declaration' , line , col ) break else : raise ParseException ( 'Malformed declaration after "!"' , line , col ) break elif ( tname , tvalue ) == ( 'CHAR' , ';' ) : return value , False elif ( tname , tvalue ) == ( 'CHAR' , '}' ) : raise BlockTerminatedValue ( value , False , line , col ) elif tname == 'ATKEYWORD' : tokens = chain ( iter ( variables [ tvalue ] ) , tokens ) elif ( tname , tvalue ) == ( 'S' , '\n' ) : raise ParseException ( 'Unexpected end of line' , line , col ) elif tname not in ( 'S' , 'COMMENT' ) : value . append ( ( tname , tvalue ) ) raise ParseException ( 'Malformed property value' , line , col ) ruleset = [ ] property_values = [ ] while True : tname , tvalue , line , col = tokens . next ( ) if tname == 'IDENT' : _tname , _tvalue , _line , _col = tokens . next ( ) if ( _tname , _tvalue ) == ( 'CHAR' , ':' ) : if tvalue not in properties : raise ParseException ( 'Unsupported property name, %s' % tvalue , line , col ) try : property = Property ( tvalue ) vtokens , importance = parse_value ( tokens , variables ) except BlockTerminatedValue , e : vtokens , importance = e . tokens , e . important tokens = chain ( [ ( 'CHAR' , '}' , e . line , e . col ) ] , tokens ) value = postprocess_value ( property , vtokens , importance , line , col ) property_values . append ( ( property , value , ( line , col ) , importance ) ) else : tokens_ = chain ( [ ( tname , tvalue , line , col ) , ( _tname , _tvalue , _line , _col ) ] , tokens ) ruleset += parse_rule ( tokens_ , variables , [ ] , selectors , is_merc ) elif ( tname , tvalue ) == ( 'CHAR' , '}' ) : for ( selector , property_value ) in product ( selectors , property_values ) : property , value , ( line , col ) , importance = property_value sort_key = value . importance ( ) , selector . specificity ( ) , ( line , col ) ruleset . append ( Declaration ( selector , property , value , sort_key ) ) return ruleset elif tname in ( 'HASH' , ) or ( tname , tvalue ) in [ ( 'CHAR' , '.' ) , ( 'CHAR' , '*' ) , ( 'CHAR' , '[' ) , ( 'CHAR' , '&' ) ] : tokens_ = chain ( [ ( tname , tvalue , line , col ) ] , tokens ) ruleset += parse_rule ( tokens_ , variables , [ ] , selectors , is_merc ) elif tname not in ( 'S' , 'COMMENT' ) : raise ParseException ( 'Malformed style rule' , line , col ) raise ParseException ( 'Malformed block' , line , col )
Parse a token stream into an array of declaration tuples.
    
        In addition to tokens, requires a dictionary of declared variables,
        a list of selectors that will apply to the declarations parsed in
        this block, and a boolean flag for mercator projection, both needed
        by possible recursive calls back to parse_rule().
    
        Return an array of (property, value, (line, col), importance).
    
        Enter this function after a left-brace is found:
        http://www.w3.org/TR/CSS2/syndata.html#block