Files
email-tracker/external/duckdb/scripts/generate_enums.py
2025-10-24 19:21:19 -05:00

162 lines
5.1 KiB
Python

import os
import json
import re
targets = [{'source': 'extension/json/include/', 'target': 'extension/json'}]
file_list = []
for target in targets:
source_base = os.path.sep.join(target['source'].split('/'))
target_base = os.path.sep.join(target['target'].split('/'))
for fname in os.listdir(source_base):
if '_enums.json' not in fname:
continue
file_list.append(
{
'source': os.path.join(source_base, fname),
'include_path': fname.replace('.json', '.hpp'),
'target_hpp': os.path.join(source_base, fname.replace('.json', '.hpp')),
'target_cpp': os.path.join(target_base, fname.replace('.json', '.cpp')),
}
)
header = '''//===----------------------------------------------------------------------===//
// This file is automatically generated by scripts/generate_enums.py
// Do not edit this file manually, your changes will be overwritten
//===----------------------------------------------------------------------===//
${INCLUDE_LIST}
namespace duckdb {
'''
footer = '''
} // namespace duckdb
'''
include_base = '#include "${FILENAME}"\n'
enum_header = '\nenum class ${ENUM_NAME} : ${ENUM_TYPE} {\n'
enum_footer = '};'
enum_value = '\t${ENUM_MEMBER} = ${ENUM_VALUE},\n'
enum_util_header = '''
template<>
const char* EnumUtil::ToChars<${ENUM_NAME}>(${ENUM_NAME} value);
template<>
${ENUM_NAME} EnumUtil::FromString<${ENUM_NAME}>(const char *value);
'''
enum_util_conversion_begin = '''
template<>
const char* EnumUtil::ToChars<${ENUM_NAME}>(${ENUM_NAME} value) {
switch(value) {
'''
enum_util_switch = '\tcase ${ENUM_NAME}::${ENUM_MEMBER}:\n\t\treturn "${ENUM_MEMBER}";\n'
enum_util_conversion_end = ''' default:
throw NotImplementedException(StringUtil::Format("Enum value of type ${ENUM_NAME}: '%d' not implemented", value));
}
}
'''
from_string_begin = '''
template<>
${ENUM_NAME} EnumUtil::FromString<${ENUM_NAME}>(const char *value) {
'''
from_string_comparison = ''' if (StringUtil::Equals(value, "${ENUM_MEMBER}")) {
return ${ENUM_NAME}::${ENUM_MEMBER};
}
'''
from_string_end = ''' throw NotImplementedException(StringUtil::Format("Enum value of type ${ENUM_NAME}: '%s' not implemented", value));
}
'''
class EnumMember:
def __init__(self, entry, index):
self.comment = None
self.index = index
if type(entry) == str:
self.name = entry
else:
self.name = entry['name']
if 'comment' in entry:
self.comment = entry['comment']
if 'index' in entry:
self.index = int(entry['index'])
class EnumClass:
def __init__(self, entry):
self.name = entry['name']
self.type = 'uint8_t'
self.values = []
index = 0
for value_entry in entry['values']:
self.values.append(EnumMember(value_entry, index))
index += 1
for entry in file_list:
source_path = entry['source']
target_header = entry['target_hpp']
target_source = entry['target_cpp']
include_path = entry['include_path']
with open(source_path, 'r') as f:
json_data = json.load(f)
include_list = ['duckdb/common/constants.hpp', 'duckdb/common/enum_util.hpp']
enums = []
for entry in json_data:
if 'includes' in entry:
include_list += entry['includes']
enums.append(EnumClass(entry))
with open(target_header, 'w+') as f:
include_text = '#pragma once\n\n'
include_text += ''.join([include_base.replace('${FILENAME}', x) for x in include_list])
f.write(header.replace('${INCLUDE_LIST}', include_text))
for enum in enums:
f.write(enum_header.replace('${ENUM_NAME}', enum.name).replace('${ENUM_TYPE}', enum.type))
for value in enum.values:
if value.comment is not None:
f.write('\t//! ' + value.comment + '\n')
f.write(enum_value.replace('${ENUM_MEMBER}', value.name).replace('${ENUM_VALUE}', str(value.index)))
f.write(enum_footer)
f.write('\n')
for enum in enums:
f.write(enum_util_header.replace('${ENUM_NAME}', enum.name))
f.write(footer)
with open(target_source, 'w+') as f:
source_include_list = [include_path, 'duckdb/common/string_util.hpp']
f.write(
header.replace(
'${INCLUDE_LIST}', ''.join([include_base.replace('${FILENAME}', x) for x in source_include_list])
)
)
for enum in enums:
f.write(enum_util_conversion_begin.replace('${ENUM_NAME}', enum.name))
for value in enum.values:
f.write(enum_util_switch.replace('${ENUM_MEMBER}', value.name).replace('${ENUM_NAME}', enum.name))
f.write(enum_util_conversion_end.replace('${ENUM_NAME}', enum.name))
f.write(from_string_begin.replace('${ENUM_NAME}', enum.name))
for value in enum.values:
f.write(from_string_comparison.replace('${ENUM_MEMBER}', value.name).replace('${ENUM_NAME}', enum.name))
f.write(from_string_end.replace('${ENUM_NAME}', enum.name))
f.write(footer)