Improved visibility of member funcs globally

This commit is contained in:
kevstone 2024-02-10 16:37:42 +00:00
parent 1ed85d67d6
commit 4f09d13b50
8 changed files with 131 additions and 87 deletions

View File

@ -59,10 +59,18 @@ class CodeMappings:
def member_funcsig_mappings(self):
return self._member_funcsig_mappings
@member_funcsig_mappings.setter
def member_funcsig_mappings(self, new_member_funcsig_mappings):
self._member_funcsig_mappings = new_member_funcsig_mappings
@property
def virtual_member_funcsig_mappings(self):
return self._virtual_member_funcsig_mappings
@virtual_member_funcsig_mappings.setter
def virtual_member_funcsig_mappings(self, new_virtual_member_funcsig_mappings):
self._virtual_member_funcsig_mappings = new_virtual_member_funcsig_mappings
@property
def literal_mappings(self):
return self._literal_mappings

View File

@ -128,21 +128,29 @@ class ConversionData:
self.active_map.funcsig_pointer_mappings.append(mapping)
def add_member_funcsig_mapping(self, mapping):
# These need to be global as all functions may access them...
def add_global_member_funcsig_mapping(self, mapping):
debug.line("add_global_member_funcsig_mapping", f">>>>> [IN:SELF]=[{self}]")
debug.line("add_global_member_funcsig_mapping", f">>>>> [IN] cfuncsig=[{debug.as_debug_string(mapping.cfuncsig)}] cppfuncsig=[{debug.as_debug_string(mapping.cppfuncsig)}]")
assert isinstance(mapping, funcsig_mapping.FuncSigMapping), f"Expected FuncSigMapping, got type=[{type(mapping).__name__}]"
for entry in self.active_map.member_funcsig_mappings:
if entry.cfuncsig.name == mapping.cfuncsig.name:
for entry in self._global_mappings.member_funcsig_mappings:
debug.line("add_global_member_funcsig_mapping", f">>>>> entry.cfuncsig.name=[{entry.cfuncsig.name}] mapping.cfuncsig.name=[{mapping.cfuncsig.name}]")
if entry.cfuncsig.name == mapping.cfuncsig.name and entry.cppfuncsig:
assert False, f"Mapping for [{mapping.cfuncsig.name}] already exists!"
self.active_map.member_funcsig_mappings.append(mapping)
self._global_mappings.member_funcsig_mappings.append(mapping)
def add_virtual_member_funcsig_mapping(self, mapping):
debug.line("add_global_member_funcsig_mapping", f">>>>> [OUT]")
def add_global_virtual_member_funcsig_mapping(self, mapping):
assert isinstance(mapping, funcsig_mapping.FuncSigMapping), f"Expected FuncSigMapping, got type=[{type(mapping).__name__}]"
for entry in self.active_map.virtual_member_funcsig_mappings:
for entry in self._global_mappings.virtual_member_funcsig_mappings:
if entry.cfuncsig.name == mapping.cfuncsig.name:
assert False, f"Mapping for [{mapping.cfuncsig.name}] already exists!"
self.active_map.virtual_member_funcsig_mappings.append(mapping)
self._global_mappings.virtual_member_funcsig_mappings.append(mapping)
def add_literal_mapping(self, cstring, cppstring):
assert isinstance(cstring, str), f"Expected str, got [{cstring}]"
@ -365,7 +373,7 @@ class ConversionData:
def funcsig_mapping_for_cfuncname(self, cfuncname):
for mapping in self.all_mappings():
for entry in mapping.all_funcsig_mappings:
if entry.cfuncsig.name == cfuncname:
if entry.cfuncsig.name == cfuncname and entry.cppfuncsig:
return entry
return None
@ -403,19 +411,20 @@ class ConversionData:
#def funcsig_buffer_mapping_for
# Searches both C and C++ member and virtual member maps
# NOTE: cppfuncsig will be none for "discovered" virtual functions until they have been converted!
def is_member_function(self, function_name):
for mapping in self.all_mappings():
for entry in mapping.member_funcsig_mappings:
if entry.cfuncsig.name == function_name:
return True
if entry.cppfuncsig != NONE_VALUE and entry.cppfuncsig.name == function_name:
return True
for entry in mapping.virtual_member_funcsig_mappings:
if entry.cfuncsig.name == function_name:
return True
if entry.cppfuncsig != NONE_VALUE and entry.cppfuncsig.name == function_name:
return True
for entry in self._global_mappings.member_funcsig_mappings:
if entry.cfuncsig.name == function_name:
return True
if entry.cppfuncsig and entry.cppfuncsig != NONE_VALUE and entry.cppfuncsig.name == function_name:
return True
for entry in self._global_mappings.virtual_member_funcsig_mappings:
if entry.cfuncsig.name == function_name:
return True
if entry.cppfuncsig and entry.cppfuncsig != NONE_VALUE and entry.cppfuncsig.name == function_name:
return True
return False

View File

@ -15,11 +15,10 @@ class FuncSigConverter(code_interface_converter.CodeInterfaceConverter):
assert isinstance(ccode_object, funcsig.FuncSig), f"Expected FuncSig, got type=[{type(ccode_object)}]"
def create_cpp_code_object(self, conversion_pack):
self._conversion_pack = conversion_pack
cfuncsig = self._ccode_object
# If we have a mapping already stored, just use that!
mapping = self._conversion_pack.conversion_data.funcsig_mapping_for_cfuncname(cfuncsig.name)
mapping = conversion_pack.conversion_data.funcsig_mapping_for_cfuncname(cfuncsig.name)
if mapping:
cppfuncsig = mapping.cppfuncsig
@ -32,10 +31,10 @@ class FuncSigConverter(code_interface_converter.CodeInterfaceConverter):
cbuffer = cfuncsig.args[mapping.arg_indexes.cbuffer]
clength = cfuncsig.args[mapping.arg_indexes.clength]
cpp_container = cppfuncsig.args[mapping.arg_indexes.cpp_container]
self._conversion_pack.conversion_data.add_funcsig_buffer_mapping(cbuffer, clength, cpp_container)
conversion_pack.conversion_data.add_funcsig_buffer_mapping(cbuffer, clength, cpp_container)
else:
cppfunc_arg = self.to_cpp_func_arg()
cpp_args = self.to_cpp_args()
cppfunc_arg = self.to_cpp_func_arg(conversion_pack)
cpp_args = self.to_cpp_args(conversion_pack)
cppfuncsig = funcsig.FuncSig(cppfunc_arg.decl_spec,
cppfunc_arg.name,
cpp_args,
@ -43,16 +42,25 @@ class FuncSigConverter(code_interface_converter.CodeInterfaceConverter):
#cppfuncsig.static = self.is_cpp_static()
# Add this to the conversion data mappings
# Add this to the correct conversion data mappings
mapping = funcsig_mapping.FuncSigMapping(cfuncsig, cppfuncsig)
self._conversion_pack.conversion_data.add_funcsig_mapping(mapping)
# Debug info...
is_mem_func = conversion_pack.conversion_data.is_member_function(cfuncsig.name)
debug.line("create_cpp_code_object", f"Member function test for [{cfuncsig.name}] is_member_function=[{is_mem_func}]")
if is_mem_func:
stored_cppfuncsig = conversion_pack.conversion_data.cppfuncsig_for_cfuncname(cfuncsig.name)
if not stored_cppfuncsig:
debug.line("create_cpp_code_object", f" -> stored_cppfuncsig=[{debug.as_debug_string(stored_cppfuncsig)}], updating member function mapping...")
conversion_pack.conversion_data.add_global_member_funcsig_mapping(mapping)
else:
conversion_pack.conversion_data.add_funcsig_mapping(mapping)
# Add all the arg mappings for the rest of the function to use
# NOTE: We use cfuncsig rather than mapping.cfuncsig as the former may not have variable names included which will
# will cause confusion if multiple args have the same type!
for i in range(len(mapping.cfuncsig.args)):
debug.line("create_cpp_code_object", f"DEBUG FUNCSIG MAPPING: cfuncsig.args[{i}]=[{debug.as_debug_string(cfuncsig.args[i])}] mapping.cppfuncsig.args[{i}]=[{debug.as_debug_string(mapping.cppfuncsig.args[i])}]")
self._conversion_pack.conversion_data.add_funcsig_arg_mapping(
conversion_pack.conversion_data.add_funcsig_arg_mapping(
cfuncsig.args[i],
mapping.cppfuncsig.args[i]
)
@ -68,9 +76,9 @@ class FuncSigConverter(code_interface_converter.CodeInterfaceConverter):
return self._ccode_object.static
# Converts the name and return type internal representation to C++
def to_cpp_func_arg(self):
def to_cpp_func_arg(self, conversion_pack):
cfunc_arg = self._ccode_object.func_arg
cppfunc_arg = conversion_funcs.convert_ccode_object(cfunc_arg, self._conversion_pack)
cppfunc_arg = conversion_funcs.convert_ccode_object(cfunc_arg, conversion_pack)
if cppfunc_arg.decl_spec.type == "int":
# We'll assume int means GribStatus
@ -83,10 +91,10 @@ class FuncSigConverter(code_interface_converter.CodeInterfaceConverter):
return cppfunc_arg
# This should return the same number of cppargs as there are cargs (set unused cppargs to None)
def to_cpp_args(self):
def to_cpp_args(self, conversion_pack):
cppargs = []
for entry in self._ccode_object.args:
cpparg = conversion_funcs.convert_ccode_object(entry, self._conversion_pack)
cpparg = conversion_funcs.convert_ccode_object(entry, conversion_pack)
cppargs.append(cpparg)
return cppargs

View File

@ -15,13 +15,11 @@ class FuncSigPointerConverter(funcsig_converter.FuncSigConverter):
assert isinstance(ccode_object, funcsig_pointer.FuncSigPointer), f"Expected FuncSigPointer, got type=[{type(ccode_object)}]"
def create_cpp_code_object(self, conversion_pack):
self._conversion_pack = conversion_pack
# If we have a mapping already stored, just use that!
cppfuncsig_pointer = self._conversion_pack.conversion_data.cppfuncsig_pointer_for_cfuncsig_pointer(self._ccode_object)
cppfuncsig_pointer = conversion_pack.conversion_data.cppfuncsig_pointer_for_cfuncsig_pointer(self._ccode_object)
if not cppfuncsig_pointer:
cppfunc_arg = self.to_cpp_func_arg()
cpp_args = self.to_cpp_args()
cppfunc_arg = self.to_cpp_func_arg(conversion_pack)
cpp_args = self.to_cpp_args(conversion_pack)
cppfuncsig_pointer = funcsig_pointer.FuncSigPointer(cppfunc_arg.decl_spec,
cppfunc_arg.name,
@ -31,12 +29,12 @@ class FuncSigPointerConverter(funcsig_converter.FuncSigConverter):
# Add this to the conversion data mappings
mapping = funcsig_pointer_mapping.FuncSigPointerMapping(self._ccode_object, cppfuncsig_pointer)
self._conversion_pack.conversion_data.add_funcsig_pointer_mapping(mapping)
conversion_pack.conversion_data.add_funcsig_pointer_mapping(mapping)
# We've also created a new type, so need to add this (to the funcbody map) too!
cdecl_spec = declaration_specifier.DeclSpec(type=self._ccode_object.func_arg.name, pointer=self._ccode_object.func_arg.decl_spec.pointer)
cppdecl_spec = declaration_specifier.DeclSpec(type=cppfunc_arg.name, pointer=cppfunc_arg.decl_spec.pointer)
self._conversion_pack.conversion_data.add_funcbody_type_mapping(cdecl_spec, cppdecl_spec)
conversion_pack.conversion_data.add_funcbody_type_mapping(cdecl_spec, cppdecl_spec)
debug.line("create_cpp_code_object", f"FuncSigPointer conversion: [{cdecl_spec.as_string()}] -> [{cppdecl_spec.as_string()}]")

View File

@ -15,8 +15,13 @@ class FunctionCallConverter(code_interface_converter.CodeInterfaceConverter):
cfunction_call = self._ccode_object
cppfunction_call = None
debug.line("create_cpp_code_object", f"FunctionCallConverter [IN] cfunction_call=[{debug.as_debug_string(cfunction_call)}]")
# 1. Check if there is a function mapping defined
mapping = conversion_pack.conversion_data.funcsig_mapping_for_cfuncname(cfunction_call.name)
debug.line("create_cpp_code_object", f"FunctionCallConverter [-] name=[{cfunction_call.name}] mapping=[{mapping}]")
if mapping:
debug.line("create_cpp_code_object", f"FunctionCallConverter [1] mapping.cfuncsig=[{debug.as_debug_string(mapping.cfuncsig)}] -> mapping.cppfuncsig=[{debug.as_debug_string(mapping.cppfuncsig)}]")
cpp_args = []

View File

@ -23,19 +23,25 @@ class DefaultCCodeConverter:
self._ccode = ccode_instance
def convert(self):
self.setup_conversion_pack()
self.add_includes()
self.convert_global_function()
self.convert_data_members()
conv_pack = self.setup_conversion_pack()
self.add_includes(conv_pack)
self.convert_global_function(conv_pack)
self.convert_data_members(conv_pack)
# Now set the conversion data state to local for the rest of the conversion
self._conversion_pack.conversion_data.set_local_state()
conv_pack.conversion_data.set_local_state()
self.convert_functions()
self.convert_constructor_function()
self.convert_destructor_function()
self.convert_member_functions()
self.convert_virtual_member_functions()
# Function conversion order is:
# 1. Non-class functions
# 2. Member functions, as they may be called by:
# 3. Constructor (shouldn't call virtual member functions)
# 4. Virtual funcs
# 5. Destructor last!
self.convert_functions(conv_pack)
self.convert_member_functions(conv_pack)
self.convert_constructor_function(conv_pack)
self.convert_virtual_member_functions(conv_pack)
self.convert_destructor_function(conv_pack)
# Post-processing
self.run_post_processing()
@ -52,7 +58,7 @@ class DefaultCCodeConverter:
conv_data = self.create_conversion_data()
conv_validation = self.create_conversion_validation()
container_utils = self.create_container_utils()
self._conversion_pack = conversion_pack.ConversionPack(conv_data, conv_validation, container_utils)
return conversion_pack.ConversionPack(conv_data, conv_validation, container_utils)
def create_code_info(self):
cpp_filename = self._ccode.cfilename
@ -90,20 +96,20 @@ class DefaultCCodeConverter:
return default_type_info.DefaultTypeInfo()
# A chance to add specific data - override as required
def function_specific_conversion_pack_updates(self, cfunction_name):
def function_specific_conversion_pack_updates(self, cfunction_name, conv_pack):
pass
def add_includes(self):
def add_includes(self, conv_pack):
pass
def convert_global_function(self):
self._code_elements.global_function = conversion_funcs.convert_ccode_object(self._ccode.global_function, self._conversion_pack)
def convert_global_function(self, conv_pack):
self._code_elements.global_function = conversion_funcs.convert_ccode_object(self._ccode.global_function, conv_pack)
debug.line("convert_global_function", f"Converted C++ code [as_lines]...")
debug.line("convert_global_function", self._code_elements.global_function.as_lines())
def convert_data_members(self):
def convert_data_members(self, conv_pack):
for cmember in self._ccode.data_members:
cppmember = conversion_funcs.convert_ccode_object(cmember, self._conversion_pack)
cppmember = conversion_funcs.convert_ccode_object(cmember, conv_pack)
self._code_elements.add_data_member(cppmember)
# Override to return True if the member function should be marked const
@ -114,49 +120,49 @@ class DefaultCCodeConverter:
#
# NOTE: ***** This function will return NONE_VALUE if the function cannot be converted to C++ *****
#
def to_cpp_function(self, func):
self._conversion_pack.conversion_data.reset_local_state(func.funcsig.name)
self.function_specific_conversion_pack_updates(func.funcsig.name)
cpp_func = conversion_funcs.convert_ccode_object(func, self._conversion_pack)
def to_cpp_function(self, func, conv_pack):
conv_pack.conversion_data.reset_local_state(func.funcsig.name)
self.function_specific_conversion_pack_updates(func.funcsig.name, conv_pack)
cpp_func = conversion_funcs.convert_ccode_object(func, conv_pack)
if isinstance(cpp_func, member_function.MemberFunction):
cpp_func.class_name = self._conversion_pack.conversion_data.info.class_name
cpp_func.class_name = conv_pack.conversion_data.info.class_name
cpp_func.set_is_const(self.is_const_member_function(func.funcsig.name))
return cpp_func
def convert_functions(self):
def convert_functions(self, conv_pack):
for func in self._ccode.functions:
cppfunc = self.to_cpp_function(func)
cppfunc = self.to_cpp_function(func, conv_pack)
if cppfunc != NONE_VALUE:
self._code_elements.add_function(cppfunc)
self.dump_function("convert_functions", cppfunc)
def convert_constructor_function(self):
def convert_constructor_function(self, conv_pack):
if self._ccode.constructor :
constructor = self.to_cpp_function(self._ccode.constructor)
constructor = self.to_cpp_function(self._ccode.constructor, conv_pack)
if constructor != NONE_VALUE:
self._code_elements.add_constructor(constructor)
self.dump_function("convert_constructor_function", constructor)
def convert_destructor_function(self):
def convert_destructor_function(self, conv_pack):
if self._ccode.destructor :
destructor = self.to_cpp_function(self._ccode.destructor)
destructor = self.to_cpp_function(self._ccode.destructor, conv_pack)
if destructor != NONE_VALUE:
self._code_elements.add_destructor(destructor)
self.dump_function("convert_destructor_function", destructor)
def convert_member_functions(self):
def convert_member_functions(self, conv_pack):
debug.line("convert_member_functions", f"Converting member functions...")
for func in self._ccode.member_functions:
member_func = self.to_cpp_function(func)
member_func = self.to_cpp_function(func, conv_pack)
if member_func != NONE_VALUE:
self._code_elements.add_member_function(member_func)
self.dump_function("convert_member_functions", member_func)
def convert_virtual_member_functions(self):
def convert_virtual_member_functions(self, conv_pack):
debug.line("convert_virtual_member_functions", f"Converting virtual member functions...")
for func in self._ccode.virtual_member_functions:
virtual_member_func = self.to_cpp_function(func)
virtual_member_func = self.to_cpp_function(func, conv_pack)
if virtual_member_func != NONE_VALUE:
self._code_elements.add_virtual_member_function(virtual_member_func)
self.dump_function("convert_virtual_member_functions", virtual_member_func)

View File

@ -21,6 +21,7 @@ import grib_accessor.supporting.data_member_mappings as data_member_mappings
import grib_accessor.grib_accessor_conversion_pack.grib_accessor_type_info as grib_accessor_type_info
import grib_accessor.grib_accessor_conversion_pack.grib_accessor_container_utils as grib_accessor_container_utils
import grib_accessor.grib_accessor_conversion_pack.conversion_pack_updates.base_conversion_pack_updates as base_conversion_pack_updates
import code_object_converter.conversion_pack.funcsig_mapping as funcsig_mapping
prefix = "grib_accessor_class_"
rename = {
@ -57,7 +58,7 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
return info
def function_specific_conversion_pack_updates(self, cfunction_name):
def function_specific_conversion_pack_updates(self, cfunction_name, conv_pack):
# See if we have a function-specific validator,
# Otherwise use the main-one
conversion_pack_updates_path="grib_accessor.grib_accessor_conversion_pack.conversion_pack_updates"
@ -77,9 +78,9 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
debug.line("function_specific_conversion_pack_updates", f"Could not find accessor_conversion_pack_updates_lib_name=[{accessor_conversion_pack_updates_lib_name}], using base version")
updates_class_inst = base_conversion_pack_updates.BaseConversionPackUpdates()
updates_class_inst.apply_updates_for_cfunction(cfunction_name, self._conversion_pack)
updates_class_inst.apply_updates_for_cfunction(cfunction_name, conv_pack)
super().function_specific_conversion_pack_updates(cfunction_name)
super().function_specific_conversion_pack_updates(cfunction_name, conv_pack)
# See if we have an Accessor-specific validator (e.g. ProjStringValidation),
# Otherwise use the default
@ -106,10 +107,19 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
def set_custom_conversion_data(self, conv_data):
for mapping in grib_accessor_member_funcsig_mapping:
conv_data.add_member_funcsig_mapping(mapping)
conv_data.add_global_member_funcsig_mapping(mapping)
# Store any member functions we have "discovered"
# We don't yet have the C++ conversion so we'll add the C funcsig for C++ (it's a hack, but should be ok unless we later look
# for the C++ name!)
for cfunc in self._ccode.member_functions:
if not conv_data.is_member_function(cfunc.funcsig.name):
mapping = funcsig_mapping.FuncSigMapping(cfunc.funcsig, None)
debug.line("set_custom_conversion_data", f"Adding <discovered> member function mapping (only cfuncsig available): [{debug.as_debug_string(cfunc.funcsig)}]->[None]")
conv_data.add_global_member_funcsig_mapping(mapping)
for mapping in grib_accessor_virtual_member_funcsig_mapping:
conv_data.add_virtual_member_funcsig_mapping(mapping)
conv_data.add_global_virtual_member_funcsig_mapping(mapping)
all_funcsig_mappings.add_all_funcsig_mappings_to_conversion_data(conv_data)
@ -122,7 +132,7 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
data_member_mappings.add_data_member_mappings_to_conversion_data(conv_data)
# Add C class name pointer as "do not convert" (e.g. grib_accessor_class_proj_string* -> NoneDeclSpec)
debug.line("initialise_conversion_data", f"Adding funcbody mapping for Accessor name=[{self._ccode.accessor_name}]")
debug.line("set_custom_conversion_data", f"Adding funcbody mapping for Accessor name=[{self._ccode.accessor_name}]")
conv_data.add_funcbody_type_mapping(DeclSpec.from_decl_specifier_seq(self._ccode.accessor_name+"*"), NONE_VALUE)
# Override to extend the type-info...
@ -130,26 +140,26 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
def type_info(self):
return grib_accessor_type_info.GribAccessorTypeInfo()
def add_includes(self):
def add_includes(self, conv_pack):
# Header includes
if self._conversion_pack.conversion_data.info.super_class_name == "AccessorData":
self._conversion_pack.conversion_data.info.header_includes.append("/".join(["AccessorData", self._conversion_pack.conversion_data.info.super_class_name + ".h"]))
if conv_pack.conversion_data.info.super_class_name == "AccessorData":
conv_pack.conversion_data.info.header_includes.append("/".join(["AccessorData", conv_pack.conversion_data.info.super_class_name + ".h"]))
else:
self._conversion_pack.conversion_data.info.header_includes.append(f"{self._conversion_pack.conversion_data.info.super_class_name}.h")
conv_pack.conversion_data.info.header_includes.append(f"{conv_pack.conversion_data.info.super_class_name}.h")
for inc in includes.grib_accessor_header_includes:
self._conversion_pack.conversion_data.info.header_includes.append(inc)
conv_pack.conversion_data.info.header_includes.append(inc)
# Source includes
self._conversion_pack.conversion_data.info.source_includes.append(f"\"{self._conversion_pack.conversion_data.info.class_name}.h\"")
conv_pack.conversion_data.info.source_includes.append(f"\"{conv_pack.conversion_data.info.class_name}.h\"")
for inc in includes.grib_accessor_source_includes:
self._conversion_pack.conversion_data.info.source_includes.append(inc)
conv_pack.conversion_data.info.source_includes.append(inc)
# TODO: Class-specific includes
return super().add_includes()
return super().add_includes(conv_pack)
def is_const_member_function(self, function_name):
return function_name in virtual_member_functions.const_virtual_member_function_names

View File

@ -7,7 +7,7 @@ class BitConversionPackUpdates(base_conversion_pack_updates.BaseConversionPackUp
def __init__(self) -> None:
super().__init__()
self._update_funcs.extend({
self._update_funcs.update({
"pack_long": self.apply_updates_for_pack_long
})