1#!/usr/bin/python2 2# Copyright 2018 The ANGLE Project Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5# 6# gen_packed_gl_enums.py: 7# Code generation for the packed enums. 8# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 9 10import json, os, sys 11from collections import namedtuple 12from collections import OrderedDict 13 14Enum = namedtuple('Enum', ['name', 'values', 'max_value']) 15EnumValue = namedtuple('EnumValue', ['name', 'gl_name', 'value']) 16 17Generators = [ 18 { 19 'json': 'packed_gl_enums.json', 20 'output': 'PackedGLEnums', 21 'includes': '#include <angle_gl.h>', 22 'namespace': 'gl', 23 'enum_type': 'GLenum', 24 }, 25 { 26 'json': 'packed_egl_enums.json', 27 'output': 'PackedEGLEnums', 28 'includes': '#include <EGL/egl.h>\n#include <EGL/eglext.h>', 29 'namespace': 'egl', 30 'enum_type': 'EGLenum', 31 }, 32 { 33 'json': 'packed_cl_enums.json', 34 'output': 'PackedCLEnums', 35 'includes': '#include <angle_cl.h>\ntypedef cl_uint CLenum;', 36 'namespace': 'cl', 37 'enum_type': 'CLenum', 38 }, 39] 40 41 42def load_enums(path): 43 with open(path) as map_file: 44 enums_dict = json.loads(map_file.read(), object_pairs_hook=OrderedDict) 45 46 enums = [] 47 for (enum_name, value_list) in enums_dict.iteritems(): 48 49 values = [] 50 i = 0 51 52 for (value_name, value_gl_name) in value_list.iteritems(): 53 values.append(EnumValue(value_name, value_gl_name, i)) 54 i += 1 55 56 assert (i < 255) # This makes sure enums fit in the uint8_t 57 enums.append(Enum(enum_name, values, i)) 58 59 enums.sort(key=lambda enum: enum.name) 60 return enums 61 62 63def generate_include_guard(path): 64 return path.replace(".", "_").upper() 65 66 67def header_name_from_cpp_name(path): 68 return path.replace(".cpp", ".h") 69 70 71header_template = """// GENERATED FILE - DO NOT EDIT. 72// Generated by {script_name} using data from {data_source_name}. 73// 74// Copyright 2017 The ANGLE Project Authors. All rights reserved. 75// Use of this source code is governed by a BSD-style license that can be 76// found in the LICENSE file. 77// 78// {file_name}: 79// Declares ANGLE-specific enums classes for {api_enum_name}s and functions operating 80// on them. 81 82#ifndef COMMON_{include_guard}_ 83#define COMMON_{include_guard}_ 84 85{includes} 86 87#include <cstdint> 88#include <ostream> 89 90namespace {namespace} 91{{ 92 93template<typename Enum> 94Enum From{api_enum_name}({api_enum_name} from); 95{content} 96}} // namespace {namespace} 97 98#endif // COMMON_{include_guard}_ 99""" 100 101enum_declaration_template = """ 102enum class {enum_name} : uint8_t 103{{ 104{value_declarations} 105 106 InvalidEnum = {max_value}, 107 EnumCount = {max_value}, 108}}; 109 110template <> 111{enum_name} From{api_enum_name}<{enum_name}>({api_enum_name} from); 112{api_enum_name} To{api_enum_name}({enum_name} from); 113std::ostream &operator<<(std::ostream &os, {enum_name} value); 114""" 115 116 117def write_header(enums, path_prefix, file_name, data_source_name, includes, namespace, 118 api_enum_name): 119 content = [''] 120 121 for enum in enums: 122 value_declarations = [] 123 for value in enum.values: 124 value_declarations.append(' ' + value.name + ' = ' + str(value.value) + ',') 125 126 content.append( 127 enum_declaration_template.format( 128 enum_name=enum.name, 129 max_value=str(enum.max_value), 130 value_declarations='\n'.join(value_declarations), 131 api_enum_name=api_enum_name)) 132 133 header = header_template.format( 134 content=''.join(content), 135 data_source_name=data_source_name, 136 script_name=sys.argv[0], 137 file_name=file_name, 138 include_guard=generate_include_guard(file_name), 139 includes=includes, 140 namespace=namespace, 141 api_enum_name=api_enum_name) 142 143 with (open(path_prefix + file_name, 'wt')) as f: 144 f.write(header) 145 146 147cpp_template = """// GENERATED FILE - DO NOT EDIT. 148// Generated by {script_name} using data from {data_source_name}. 149// 150// Copyright 2017 The ANGLE Project Authors. All rights reserved. 151// Use of this source code is governed by a BSD-style license that can be 152// found in the LICENSE file. 153// 154// {file_name}: 155// Implements ANGLE-specific enums classes for {api_enum_name}s and functions operating 156// on them. 157 158#include "common/debug.h" 159#include "common/{header_name}" 160 161namespace {namespace} 162{{ 163{content} 164}} // namespace {namespace} 165""" 166 167enum_implementation_template = """ 168template <> 169{enum_name} From{api_enum_name}<{enum_name}>({api_enum_name} from) 170{{ 171 switch (from) 172 {{ 173{from_glenum_cases} 174 default: 175 return {enum_name}::InvalidEnum; 176 }} 177}} 178 179{api_enum_name} To{api_enum_name}({enum_name} from) 180{{ 181 switch (from) 182 {{ 183{to_glenum_cases} 184 default: 185 UNREACHABLE(); 186 return 0; 187 }} 188}} 189 190std::ostream &operator<<(std::ostream &os, {enum_name} value) 191{{ 192 switch (value) 193 {{ 194{ostream_cases} 195 default: 196 os << "GL_INVALID_ENUM"; 197 break; 198 }} 199 return os; 200}} 201""" 202 203 204def write_cpp(enums, path_prefix, file_name, data_source_name, namespace, api_enum_name): 205 content = [''] 206 207 for enum in enums: 208 from_glenum_cases = [] 209 to_glenum_cases = [] 210 ostream_cases = [] 211 for value in enum.values: 212 qualified_name = enum.name + '::' + value.name 213 from_glenum_cases.append(' case ' + value.gl_name + ':\n return ' + 214 qualified_name + ';') 215 to_glenum_cases.append(' case ' + qualified_name + ':\n return ' + 216 value.gl_name + ';') 217 ostream_cases.append(' case ' + qualified_name + ':\n os << "' + 218 value.gl_name + '";\n break;') 219 220 content.append( 221 enum_implementation_template.format( 222 enum_name=enum.name, 223 from_glenum_cases='\n'.join(from_glenum_cases), 224 max_value=str(enum.max_value), 225 to_glenum_cases='\n'.join(to_glenum_cases), 226 api_enum_name=api_enum_name, 227 ostream_cases='\n'.join(ostream_cases))) 228 229 cpp = cpp_template.format( 230 content=''.join(content), 231 data_source_name=data_source_name, 232 script_name=sys.argv[0], 233 file_name=file_name, 234 header_name=header_name_from_cpp_name(file_name), 235 namespace=namespace, 236 api_enum_name=api_enum_name) 237 238 with (open(path_prefix + file_name, 'wt')) as f: 239 f.write(cpp) 240 241 242def main(): 243 244 # auto_script parameters. 245 if len(sys.argv) > 1: 246 inputs = [] 247 outputs = [] 248 for generator in Generators: 249 inputs += [generator['json']] 250 outputs += [ 251 generator['output'] + '_autogen.cpp', 252 generator['output'] + '_autogen.h', 253 ] 254 255 if sys.argv[1] == 'inputs': 256 print ','.join(inputs) 257 elif sys.argv[1] == 'outputs': 258 print ','.join(outputs) 259 else: 260 print('Invalid script parameters') 261 return 1 262 return 0 263 264 path_prefix = os.path.dirname(os.path.realpath(__file__)) + os.path.sep 265 266 for generator in Generators: 267 json_file = generator['json'] 268 output_file = generator['output'] 269 includes = generator['includes'] 270 namespace = generator['namespace'] 271 enum_type = generator['enum_type'] 272 enums = load_enums(path_prefix + json_file) 273 write_header(enums, path_prefix, output_file + '_autogen.h', json_file, includes, 274 namespace, enum_type) 275 write_cpp(enums, path_prefix, output_file + '_autogen.cpp', json_file, namespace, 276 enum_type) 277 return 0 278 279 280if __name__ == '__main__': 281 sys.exit(main()) 282