refactor: processing flow, and classDefine record.
This commit is contained in:
80
DeThunk/src/header_postprocessor.py
Normal file
80
DeThunk/src/header_postprocessor.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import util.cpp_language as CppUtil
|
||||
|
||||
|
||||
_need_fix_includes_queue = dict()
|
||||
_need_fix_members_queue = dict()
|
||||
_class_defs_record = dict()
|
||||
|
||||
|
||||
class ClassDefineRecord:
|
||||
rpath = str()
|
||||
is_template = bool()
|
||||
is_empty = bool()
|
||||
|
||||
def __init__(self, rpath: str, is_template: bool, is_empty: bool):
|
||||
self.rpath = rpath
|
||||
self.is_template = is_template
|
||||
self.is_empty = is_empty
|
||||
|
||||
|
||||
def record_class_definition(
|
||||
path: str, namespace: str, class_name: str, is_template: bool, is_empty: bool
|
||||
):
|
||||
assert len(path) > 0 and len(class_name) > 0
|
||||
assert '::' not in class_name # c++ does not support forward declaration for nested class.
|
||||
if namespace not in _class_defs_record:
|
||||
_class_defs_record[namespace] = {}
|
||||
assert class_name not in _class_defs_record[namespace], (
|
||||
f'path = {path}, ns = {namespace}, cl = {class_name}'
|
||||
)
|
||||
_class_defs_record[namespace][class_name] = ClassDefineRecord(
|
||||
path[path.find('src/') + 4 :], is_template, is_empty
|
||||
)
|
||||
|
||||
|
||||
def add_pending_fix_includes_queue(path: str, decls: list, member_typeset: list):
|
||||
assert path not in _need_fix_includes_queue
|
||||
if len(decls) > 0 and len(member_typeset) > 0:
|
||||
_need_fix_includes_queue[path] = [decls, member_typeset]
|
||||
|
||||
|
||||
def add_pending_fix_members_queue(path: str, member_typeset: list):
|
||||
assert path not in _need_fix_members_queue
|
||||
if len(member_typeset) > 0:
|
||||
_need_fix_members_queue[path] = member_typeset
|
||||
|
||||
|
||||
def _find_definition(decl: str, in_types: list) -> ClassDefineRecord | None:
|
||||
find_decl = CppUtil.find_class_forward_declaration(decl)
|
||||
assert find_decl
|
||||
|
||||
namespace = find_decl.namespace_decl
|
||||
clazz = find_decl.class_decl
|
||||
|
||||
if not CppUtil.is_full_type_required_for_typeset(namespace, clazz, in_types):
|
||||
return None
|
||||
|
||||
assert namespace in _class_defs_record, f'namespace not recorded, {namespace}'
|
||||
assert clazz in _class_defs_record[namespace], f'{clazz} not recorded, in {namespace}'
|
||||
|
||||
return _class_defs_record[namespace][find_decl.class_decl]
|
||||
|
||||
|
||||
def process():
|
||||
# fix includes
|
||||
for path, decl_and_types in _need_fix_includes_queue.items():
|
||||
with open(path, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
for decl in decl_and_types[0]:
|
||||
record = _find_definition(decl, decl_and_types[1])
|
||||
if record:
|
||||
include = f'#include "{record.rpath}"'
|
||||
content = content.replace(decl, include)
|
||||
with open(path, 'w', encoding='utf-8') as wfile:
|
||||
wfile.write(content)
|
||||
# fix members
|
||||
# for path, types in _need_fix_members_queue.items():
|
||||
# with open(path, 'r', encoding='utf-8') as file:
|
||||
# content = file.read()
|
||||
# with open(path, 'w', encoding='utf-8') as wfile:
|
||||
# wfile.write(content)
|
||||
14
DeThunk/src/header_preprocessor.py
Normal file
14
DeThunk/src/header_preprocessor.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
Preprocessor for _HeaderOutputPredefine.h
|
||||
"""
|
||||
|
||||
|
||||
def process(path_to_file: str):
|
||||
if path_to_file.endswith('_HeaderOutputPredefine.h'):
|
||||
with open(path_to_file, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
|
||||
content += '\n#include <winsock2.h>'
|
||||
|
||||
with open(path_to_file, 'w', encoding='utf-8') as wfile:
|
||||
wfile.write(content)
|
||||
@@ -1,10 +1,10 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
import predefine_subprocessor as PredefineProcessor
|
||||
import util.cpp_language as CppUtil
|
||||
import header_preprocessor as HeaderPreProcessor
|
||||
import header_postprocessor as HeaderPostProcessor
|
||||
|
||||
from include_fixer import IncludeFixer
|
||||
import util.cpp_language as CppUtil
|
||||
|
||||
|
||||
class Options:
|
||||
@@ -21,8 +21,14 @@ class Options:
|
||||
restore_member_variable = bool()
|
||||
|
||||
# others
|
||||
# only takes effect for TypedStorage, since the TypedStorage wrapper makes the full type unnecessary.
|
||||
# * only takes effect for TypedStorage, since the TypedStorage wrapper makes the full type unnecessary.
|
||||
fix_includes_for_member_variables = True
|
||||
# * template definitions cannot be generated for headergen and may be wrong. class sizes may be wrong if
|
||||
# * empty templates are used in TypedStorage.
|
||||
# * this option will erase the type of the empty template (convert to uchar[size]).
|
||||
fix_size_for_type_with_empty_template_class = True
|
||||
# * this option will and add sizeof & alignof static assertions to members. (only takes effect for TypedStorage)
|
||||
add_sizeof_alignof_static_assertions = True
|
||||
|
||||
def __init__(self, args):
|
||||
self.base_dir = args.path
|
||||
@@ -51,11 +57,10 @@ class Options:
|
||||
self.set_variable(opt)
|
||||
|
||||
|
||||
def process(path_to_file: str, include_fixer: IncludeFixer | None, args: Options):
|
||||
def process(path_to_file: str, args: Options):
|
||||
assert os.path.isfile(path_to_file)
|
||||
|
||||
if path_to_file.endswith('_HeaderOutputPredefine.h'):
|
||||
PredefineProcessor.process(path_to_file)
|
||||
return
|
||||
|
||||
RECORDED_THUNKS = []
|
||||
@@ -128,7 +133,9 @@ def process(path_to_file: str, include_fixer: IncludeFixer | None, args: Options
|
||||
continue
|
||||
|
||||
# restore member variable:
|
||||
if args.restore_member_variable and '::ll::' in line: # union { ... };
|
||||
if args.restore_member_variable and stripped_line.startswith(
|
||||
'::ll::'
|
||||
): # union { ... };
|
||||
in_member_variable = True
|
||||
is_modified = True
|
||||
if in_member_variable and stripped_line.endswith(';'):
|
||||
@@ -192,23 +199,29 @@ def process(path_to_file: str, include_fixer: IncludeFixer | None, args: Options
|
||||
in_forward_declaration_list = True
|
||||
if in_forward_declaration_list:
|
||||
if (
|
||||
stripped_line.startswith('class')
|
||||
or stripped_line.startswith('struct')
|
||||
or stripped_line.startswith('namespace')
|
||||
stripped_line.startswith('class ')
|
||||
or stripped_line.startswith('struct ')
|
||||
or stripped_line.startswith('namespace ')
|
||||
):
|
||||
forward_declarations.append(stripped_line)
|
||||
if stripped_line.startswith('// clang-format on') and in_forward_declaration_list:
|
||||
in_forward_declaration_list = False
|
||||
|
||||
# record namespace & classes
|
||||
if not in_forward_declaration_list and args.fix_includes_for_member_variables:
|
||||
if line.startswith('class') or line.startswith(
|
||||
'struct'
|
||||
): # ignore nested class, FIXME: ignore template class
|
||||
if not in_forward_declaration_list:
|
||||
if line.startswith('class ') or line.startswith('struct '): # ignore nested class
|
||||
founded = CppUtil.find_class_definition(line)
|
||||
if founded:
|
||||
include_fixer.record_class_definition(
|
||||
path_to_file, '::'.join(current_namespace), founded
|
||||
is_template = (
|
||||
content[content.rfind('\n', 0, -1) :].strip().startswith('template ')
|
||||
)
|
||||
is_empty = stripped_line.endswith('{};')
|
||||
HeaderPostProcessor.record_class_definition(
|
||||
path_to_file,
|
||||
'::'.join(current_namespace),
|
||||
founded,
|
||||
is_template,
|
||||
is_empty,
|
||||
)
|
||||
founded = CppUtil.find_namespace_declaration(line)
|
||||
if founded:
|
||||
@@ -233,9 +246,13 @@ def process(path_to_file: str, include_fixer: IncludeFixer | None, args: Options
|
||||
content += line
|
||||
if is_modified:
|
||||
if args.fix_includes_for_member_variables and has_typed_storage:
|
||||
include_fixer.add_pending_fix_queue(
|
||||
HeaderPostProcessor.add_pending_fix_includes_queue(
|
||||
path_to_file, forward_declarations, member_variable_types
|
||||
)
|
||||
if args.fix_size_for_type_with_empty_template_class and has_typed_storage:
|
||||
HeaderPostProcessor.add_pending_fix_members_queue(
|
||||
path_to_file, member_variable_types
|
||||
)
|
||||
with open(path_to_file, 'w', encoding='utf-8') as wfile:
|
||||
wfile.write(content)
|
||||
|
||||
@@ -243,12 +260,15 @@ def process(path_to_file: str, include_fixer: IncludeFixer | None, args: Options
|
||||
def iterate(args: Options):
|
||||
assert os.path.isdir(args.base_dir)
|
||||
|
||||
include_fixer = args.fix_includes_for_member_variables and IncludeFixer()
|
||||
|
||||
for root, dirs, files in os.walk(args.base_dir):
|
||||
for file in files:
|
||||
if CppUtil.is_header_file(file):
|
||||
process(os.path.join(root, file), include_fixer, args)
|
||||
path = os.path.join(root, file)
|
||||
# preprocessing: execution time is before each file.
|
||||
HeaderPreProcessor.process(path)
|
||||
# processing: executed immediately after preprocessing is completed.
|
||||
process(path, args)
|
||||
|
||||
if include_fixer:
|
||||
include_fixer.run_fix()
|
||||
# post-processing: executed after all files have been processed.
|
||||
# during processing, files that require post-processing will be marked.
|
||||
HeaderPostProcessor.process()
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import os
|
||||
|
||||
import util.cpp_language as CppUtil
|
||||
|
||||
|
||||
class IncludeFixer:
|
||||
_need_fix_queue = dict()
|
||||
_class_defs_record = dict()
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def record_class_definition(self, path: str, namespace: str, class_name: str):
|
||||
assert len(path) > 0 and len(class_name) > 0
|
||||
assert '::' not in class_name # c++ does not support forward declaration for nested class.
|
||||
if namespace not in self._class_defs_record:
|
||||
self._class_defs_record[namespace] = {}
|
||||
assert class_name not in self._class_defs_record[namespace]
|
||||
self._class_defs_record[namespace][class_name] = path[path.find('src/') + 4 :]
|
||||
|
||||
def add_pending_fix_queue(self, path: str, decls: list, member_typeset: list):
|
||||
assert os.path.isfile(path)
|
||||
assert path not in self._need_fix_queue
|
||||
if len(decls) > 0 and len(member_typeset):
|
||||
self._need_fix_queue[path] = [decls, member_typeset]
|
||||
|
||||
def _find_definition(self, decl: str, in_types: list):
|
||||
find_decl = CppUtil.find_class_forward_declaration(decl)
|
||||
assert find_decl
|
||||
|
||||
namespace = find_decl.namespace_decl
|
||||
clazz = find_decl.class_decl
|
||||
|
||||
if not CppUtil.is_full_type_required_for_typeset(namespace, clazz, in_types):
|
||||
return None
|
||||
|
||||
assert namespace in self._class_defs_record, f'namespace not recorded, {namespace}'
|
||||
assert clazz in self._class_defs_record[namespace], f'{clazz} not recorded, in {namespace}'
|
||||
|
||||
return self._class_defs_record[namespace][find_decl.class_decl]
|
||||
|
||||
def run_fix(self):
|
||||
for path, decl_and_types in self._need_fix_queue.items():
|
||||
with open(path, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
for decl in decl_and_types[0]:
|
||||
define_location = self._find_definition(decl, decl_and_types[1])
|
||||
if define_location:
|
||||
include = f'#include "{define_location}"'
|
||||
content = content.replace(decl, include)
|
||||
with open(path, 'w', encoding='utf-8') as wfile:
|
||||
wfile.write(content)
|
||||
@@ -1,13 +0,0 @@
|
||||
"""
|
||||
Preprocessor for _HeaderOutputPredefine.h
|
||||
"""
|
||||
|
||||
|
||||
def process(path_to_file: str):
|
||||
with open(path_to_file, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
|
||||
content += '\n#include <winsock2.h>'
|
||||
|
||||
with open(path_to_file, 'w', encoding='utf-8') as wfile:
|
||||
wfile.write(content)
|
||||
Reference in New Issue
Block a user