#!/usr/bin/python2 # 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 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', 'includes': '#include ', 'namespace': 'gl', 'enum_type': 'GLenum', }, { 'json': 'packed_egl_enums.json', 'output': 'PackedEGLEnums', 'includes': '#include \n#include ', 'namespace': 'egl', 'enum_type': 'EGLenum', }, { 'json': 'packed_cl_enums.json', 'output': 'PackedCLEnums', 'includes': '#include \ntypedef cl_uint CLenum;', 'namespace': 'cl', 'enum_type': 'CLenum', }, ] 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 2017 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}_ {includes} #include #include namespace {namespace} {{ template 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, includes, 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), data_source_name=data_source_name, script_name=sys.argv[0], file_name=file_name, include_guard=generate_include_guard(file_name), includes=includes, 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 2017 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), 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'] includes = generator['includes'] 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, includes, 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())