docs: 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)