-
Notifications
You must be signed in to change notification settings - Fork 2
/
gen_enums.py
executable file
·120 lines (86 loc) · 3.11 KB
/
gen_enums.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#! /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
import os
# 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)
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 '# pylint: disable=invalid-name,missing-docstring'
yield ''
first = True
for lexeme_type, lexemes in lexemes.items():
if first:
first = False
else:
yield ''
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."""
script_dir = os.path.dirname(os.path.realpath(__file__))
input_path = os.path.join(script_dir, 'glsl-parser/lexemes.h')
output_path = os.path.join(script_dir, '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()