docs: def postprocess_value(property, tokens, important, line, col):
      """ Convert a list of property value tokens into a single Value instance.
      
          Values can be numbers, strings, colors, uris, or booleans:
          http://www.w3.org/TR/CSS2/syndata.html#values
      """
      #
      # Helper function.
      #
      
      def combine_negative_numbers(tokens, line, col):
          """ Find negative numbers in a list of tokens, return a new list.
          
              Negative numbers come as two tokens, a minus sign and a number.
          """
          tokens, original_tokens = [], iter(tokens)
          
          while True:
              try:
                  tname, tvalue = original_tokens.next()[:2]
                  
                  if (tname, tvalue) == ('CHAR', '-'):
                      tname, tvalue = original_tokens.next()[:2]
      
                      if tname == 'NUMBER':
                          # minus sign with a number is a negative number
                          tokens.append(('NUMBER', '-'+tvalue))
                      else:
                          raise ParseException('Unexpected non-number after a minus sign', line, col)
      
                  else:
                      tokens.append((tname, tvalue))
      
              except StopIteration:
                  break
          
          return tokens
      
      #
      # The work.
      #
      
      tokens = combine_negative_numbers(tokens, line, col)
      
      if properties[property.name] in (int, float, str, color, uri, boolean) or type(properties[property.name]) is tuple:
          if len(tokens) != 1:
              raise ParseException('Single value only for property "%(property)s"' % locals(), line, col)
  
      if properties[property.name] is int:
          if tokens[0][0] != 'NUMBER':
              raise ParseException('Number value only for property "%(property)s"' % locals(), line, col)
  
          value = int(tokens[0][1])
  
      elif properties[property.name] is float:
          if tokens[0][0] != 'NUMBER':
              raise ParseException('Number value only for property "%(property)s"' % locals(), line, col)
  
          value = float(tokens[0][1])
  
      elif properties[property.name] is str:
          if tokens[0][0] != 'STRING':
              raise ParseException('String value only for property "%(property)s"' % locals(), line, col)
  
          value = str(tokens[0][1][1:-1])
  
      elif properties[property.name] is color_transparent:
          if tokens[0][0] != 'HASH' and (tokens[0][0] != 'IDENT' or tokens[0][1] != 'transparent'):
              raise ParseException('Hash or transparent value only for property "%(property)s"' % locals(), line, col)
  
          if tokens[0][0] == 'HASH':
              if not re.match(r'^#([0-9a-f]{3}){1,2}$', tokens[0][1], re.I):
                  raise ParseException('Unrecognized color value for property "%(property)s"' % locals(), line, col)
      
              hex = tokens[0][1][1:]
              
              if len(hex) == 3:
                  hex = hex[0]+hex[0] + hex[1]+hex[1] + hex[2]+hex[2]
              
              rgb = (ord(unhex(h)) for h in (hex[0:2], hex[2:4], hex[4:6]))
              
              value = color(*rgb)
  
          else:
              value = 'transparent'
  
      elif properties[property.name] is color:
          if tokens[0][0] != 'HASH':
              raise ParseException('Hash value only for property "%(property)s"' % locals(), line, col)
  
          if not re.match(r'^#([0-9a-f]{3}){1,2}$', tokens[0][1], re.I):
              raise ParseException('Unrecognized color value for property "%(property)s"' % locals(), line, col)
  
          hex = tokens[0][1][1:]
          
          if len(hex) == 3:
              hex = hex[0]+hex[0] + hex[1]+hex[1] + hex[2]+hex[2]
          
          rgb = (ord(unhex(h)) for h in (hex[0:2], hex[2:4], hex[4:6]))
          
          value = color(*rgb)
  
      elif properties[property.name] is uri:
          if tokens[0][0] != 'URI':
              raise ParseException('URI value only for property "%(property)s"' % locals(), line, col)
  
          raw = str(tokens[0][1])
  
          if raw.startswith('url("') and raw.endswith('")'):
              raw = raw[5:-2]
              
          elif raw.startswith("url('") and raw.endswith("')"):
              raw = raw[5:-2]
              
          elif raw.startswith('url(') and raw.endswith(')'):
              raw = raw[4:-1]
  
          value = uri(raw)
              
      elif properties[property.name] is boolean:
          if tokens[0][0] != 'IDENT' or tokens[0][1] not in ('true', 'false'):
              raise ParseException('true/false value only for property "%(property)s"' % locals(), line, col)
  
          value = boolean(tokens[0][1] == 'true')
              
      elif type(properties[property.name]) is tuple:
          if tokens[0][0] != 'IDENT':
              raise ParseException('Identifier value only for property "%(property)s"' % locals(), line, col)
  
          if tokens[0][1] not in properties[property.name]:
              raise ParseException('Unrecognized value for property "%(property)s"' % locals(), line, col)
  
          value = str(tokens[0][1])
              
      elif properties[property.name] is numbers:
          values = []
          
          # strip spaces from the list
          relevant_tokens = [token for token in tokens if token[0] != 'S']
          
          for (i, token) in enumerate(relevant_tokens):
              if (i % 2) == 0 and token[0] == 'NUMBER':
                  try:
                      value = int(token[1])
                  except ValueError:
                      value = float(token[1])
  
                  values.append(value)
  
              elif (i % 2) == 1 and token[0] == 'CHAR':
                  # fine, it's a comma
                  continue
  
              else:
                  raise ParseException('Value for property "%(property)s" should be a comma-delimited list of numbers' % locals(), line, col)
  
          value = numbers(*values)
  
      elif properties[property.name] is strings:
          values = []
      
          # strip spaces from the list
          relevant_tokens = [token for token in tokens if token[0] != 'S']
          
          for (i, token) in enumerate(relevant_tokens):
              if (i % 2) == 0 and token[0] == 'STRING':
                  values.append(str(token[1][1:-1]))
              
              elif (i % 2) == 1 and token == ('CHAR', ','):
                  # fine, it's a comma
                  continue
              
              else:
                  raise ParseException('Value for property "%(property)s" should be a comma-delimited list of strings' % locals(), line, col)
      
          value = strings(*values)
  
      return Value(value, important)