new_contents: #! /usr/bin/env python
  
  """Generate pyglsl_parser/lexemes.py from glsl-parser/lexemes.h."""
  
  from collections import OrderedDict
  from enum import Enum
  from keyword import iskeyword
  import re
  
  
  # TODO(nicholasbishop): operators
  class LexemeType(Enum):
      """GLSL lexeme categories."""
      TYPE = 0,
      KEYWORD = 1,
      TYPENAME = 2,
  
  
  def lexeme_type_names():
      """Tuple of the LexemeType names."""
      return tuple(member.name for member in LexemeType)
  
  
  def compile_pattern():
      """Compile the regex pattern used for parsing lexemes.h."""
      # Capture lexeme type
      group_one = r'({})'.format('|'.join(lexeme_type_names()))
  
      # Capture lexeme name
      group_two = r'\((\w+)\)'
  
      pattern = group_one + group_two
      return re.compile(pattern)
  
  
  def parse_lexeme_line(regex, line):
      """Parse one line from the lexemes.h header.
  
      Returns a pair of (LexemeType, lexeme string), or None if the line
      can't be parsed.
  
      Example: "KEYWORD(float)" -> (LexemeType.KEYWORD, 'float')
  
      """
      match = regex.match(line)
      if match is not None:
          return match.groups()
  
  
  def parse_lexemes(lexemes_file):
      """Parse the glsl-parser lexemes.h header.
  
      Returns a dictionary mapping LexemeType to a list of the
      corresponding lexemes.
      """
      regex = compile_pattern()
      lexemes = OrderedDict((name, []) for name in lexeme_type_names())
  
      for line in lexemes_file.readlines():
          lexeme = parse_lexeme_line(regex, line)
          if lexeme is not None:
              lexeme_type, name = lexeme
              lexemes[lexeme_type].append(name)
  
      return lexemes
  
  
  def gen_enum_code(name, members):
      """Yield lines of Python code that define an enum."""
      yield '@unique'
      yield 'class {}(Enum):'.format(name)
      for index, member in enumerate(members):
          if iskeyword(member):
              member = '{}_'.format(member)
          yield '    {} = {}'.format(member, index)
      yield ''
  
  
  def gen_lexemes_code(lexemes):
      """Generate the lines of code for lexemes.py."""
      yield '"""Autogenerated by gen_enums.py"""'
      yield 'from enum import Enum, unique'
      yield ''
      for lexeme_type, lexemes in lexemes.items():
          yield from gen_enum_code(lexeme_type.capitalize(), lexemes)
  
  
  def write_lines(lines, output_path):
      """Write out |lines| to |output_path|.
  
      The lines should not end in a newline character, that is added by
      this function.
      """
      with open(output_path, 'w') as output_file:
          for line in lines:
              output_file.write(line + '\n')
  
  
  def main():
      """Parse the lexemes.h header and generate the Python enums."""
      # TODO(nicholasbishop): use the script's path to ensure the
      # following relative paths are correct
      input_path = 'glsl-parser/lexemes.h'
      output_path = 'pyglsl_parser/lexemes.py'
  
      with open(input_path) as lexemes_file:
          lexemes = parse_lexemes(lexemes_file)
  
      code = gen_lexemes_code(lexemes)
  
      write_lines(code, output_path)
  
  
  if __name__ == '__main__':
      main()
  
subject: Add gen_enums script