| # Copyright 2018 The ANGLE Project Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| # |
| # gen_packed_gl_enums.py: |
| # Code generation for the packed enums. |
| # NOTE: don't run this script directly. Run scripts/run_code_generation.py. |
| |
| import datetime, json, os, sys |
| from collections import namedtuple |
| from collections import OrderedDict |
| |
| Enum = namedtuple('Enum', ['name', 'values', 'max_value']) |
| EnumValue = namedtuple('EnumValue', ['name', 'gl_name', 'value']) |
| |
| Generators = [ |
| { |
| 'json': 'packed_gl_enums.json', |
| 'output': 'PackedGLEnums', |
| 'namespace': 'gl', |
| 'enum_type': 'GLenum', |
| }, |
| { |
| 'json': 'packed_egl_enums.json', |
| 'output': 'PackedEGLEnums', |
| 'namespace': 'egl', |
| 'enum_type': 'EGLenum', |
| }, |
| ] |
| |
| |
| def load_enums(path): |
| with open(path) as map_file: |
| enums_dict = json.loads(map_file.read(), object_pairs_hook=OrderedDict) |
| |
| enums = [] |
| for (enum_name, value_list) in enums_dict.iteritems(): |
| |
| values = [] |
| i = 0 |
| |
| for (value_name, value_gl_name) in value_list.iteritems(): |
| values.append(EnumValue(value_name, value_gl_name, i)) |
| i += 1 |
| |
| assert (i < 255) # This makes sure enums fit in the uint8_t |
| enums.append(Enum(enum_name, values, i)) |
| |
| enums.sort(key=lambda enum: enum.name) |
| return enums |
| |
| |
| def generate_include_guard(path): |
| return path.replace(".", "_").upper() |
| |
| |
| def header_name_from_cpp_name(path): |
| return path.replace(".cpp", ".h") |
| |
| |
| header_template = """// GENERATED FILE - DO NOT EDIT. |
| // Generated by {script_name} using data from {data_source_name}. |
| // |
| // Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // {file_name}: |
| // Declares ANGLE-specific enums classes for {api_enum_name}s and functions operating |
| // on them. |
| |
| #ifndef COMMON_{include_guard}_ |
| #define COMMON_{include_guard}_ |
| |
| #include <angle_gl.h> |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| |
| #include <cstdint> |
| #include <ostream> |
| |
| namespace {namespace} |
| {{ |
| |
| template<typename Enum> |
| Enum From{api_enum_name}({api_enum_name} from); |
| {content} |
| }} // namespace {namespace} |
| |
| #endif // COMMON_{include_guard}_ |
| """ |
| |
| enum_declaration_template = """ |
| enum class {enum_name} : uint8_t |
| {{ |
| {value_declarations} |
| |
| InvalidEnum = {max_value}, |
| EnumCount = {max_value}, |
| }}; |
| |
| template <> |
| {enum_name} From{api_enum_name}<{enum_name}>({api_enum_name} from); |
| {api_enum_name} To{api_enum_name}({enum_name} from); |
| std::ostream &operator<<(std::ostream &os, {enum_name} value); |
| """ |
| |
| |
| def write_header(enums, path_prefix, file_name, data_source_name, namespace, api_enum_name): |
| content = [''] |
| |
| for enum in enums: |
| value_declarations = [] |
| for value in enum.values: |
| value_declarations.append(' ' + value.name + ' = ' + str(value.value) + ',') |
| |
| content.append( |
| enum_declaration_template.format( |
| enum_name=enum.name, |
| max_value=str(enum.max_value), |
| value_declarations='\n'.join(value_declarations), |
| api_enum_name=api_enum_name)) |
| |
| header = header_template.format( |
| content=''.join(content), |
| copyright_year=datetime.date.today().year, |
| data_source_name=data_source_name, |
| script_name=sys.argv[0], |
| file_name=file_name, |
| include_guard=generate_include_guard(file_name), |
| namespace=namespace, |
| api_enum_name=api_enum_name) |
| |
| with (open(path_prefix + file_name, 'wt')) as f: |
| f.write(header) |
| |
| |
| cpp_template = """// GENERATED FILE - DO NOT EDIT. |
| // Generated by {script_name} using data from {data_source_name}. |
| // |
| // Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // {file_name}: |
| // Implements ANGLE-specific enums classes for {api_enum_name}s and functions operating |
| // on them. |
| |
| #include "common/debug.h" |
| #include "common/{header_name}" |
| |
| namespace {namespace} |
| {{ |
| {content} |
| }} // namespace {namespace} |
| """ |
| |
| enum_implementation_template = """ |
| template <> |
| {enum_name} From{api_enum_name}<{enum_name}>({api_enum_name} from) |
| {{ |
| switch (from) |
| {{ |
| {from_glenum_cases} |
| default: |
| return {enum_name}::InvalidEnum; |
| }} |
| }} |
| |
| {api_enum_name} To{api_enum_name}({enum_name} from) |
| {{ |
| switch (from) |
| {{ |
| {to_glenum_cases} |
| default: |
| UNREACHABLE(); |
| return 0; |
| }} |
| }} |
| |
| std::ostream &operator<<(std::ostream &os, {enum_name} value) |
| {{ |
| switch (value) |
| {{ |
| {ostream_cases} |
| default: |
| os << "GL_INVALID_ENUM"; |
| break; |
| }} |
| return os; |
| }} |
| """ |
| |
| |
| def write_cpp(enums, path_prefix, file_name, data_source_name, namespace, api_enum_name): |
| content = [''] |
| |
| for enum in enums: |
| from_glenum_cases = [] |
| to_glenum_cases = [] |
| ostream_cases = [] |
| for value in enum.values: |
| qualified_name = enum.name + '::' + value.name |
| from_glenum_cases.append(' case ' + value.gl_name + ':\n return ' + |
| qualified_name + ';') |
| to_glenum_cases.append(' case ' + qualified_name + ':\n return ' + |
| value.gl_name + ';') |
| ostream_cases.append(' case ' + qualified_name + ':\n os << "' + |
| value.gl_name + '";\n break;') |
| |
| content.append( |
| enum_implementation_template.format( |
| enum_name=enum.name, |
| from_glenum_cases='\n'.join(from_glenum_cases), |
| max_value=str(enum.max_value), |
| to_glenum_cases='\n'.join(to_glenum_cases), |
| api_enum_name=api_enum_name, |
| ostream_cases='\n'.join(ostream_cases))) |
| |
| cpp = cpp_template.format( |
| content=''.join(content), |
| copyright_year=datetime.date.today().year, |
| data_source_name=data_source_name, |
| script_name=sys.argv[0], |
| file_name=file_name, |
| header_name=header_name_from_cpp_name(file_name), |
| namespace=namespace, |
| api_enum_name=api_enum_name) |
| |
| with (open(path_prefix + file_name, 'wt')) as f: |
| f.write(cpp) |
| |
| |
| def main(): |
| |
| # auto_script parameters. |
| if len(sys.argv) > 1: |
| inputs = [] |
| outputs = [] |
| for generator in Generators: |
| inputs += [generator['json']] |
| outputs += [ |
| generator['output'] + '_autogen.cpp', |
| generator['output'] + '_autogen.h', |
| ] |
| |
| if sys.argv[1] == 'inputs': |
| print ','.join(inputs) |
| elif sys.argv[1] == 'outputs': |
| print ','.join(outputs) |
| else: |
| print('Invalid script parameters') |
| return 1 |
| return 0 |
| |
| path_prefix = os.path.dirname(os.path.realpath(__file__)) + os.path.sep |
| |
| for generator in Generators: |
| json_file = generator['json'] |
| output_file = generator['output'] |
| namespace = generator['namespace'] |
| enum_type = generator['enum_type'] |
| enums = load_enums(path_prefix + json_file) |
| write_header(enums, path_prefix, output_file + '_autogen.h', json_file, namespace, |
| enum_type) |
| write_cpp(enums, path_prefix, output_file + '_autogen.cpp', json_file, namespace, |
| enum_type) |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |