templates converting correctly now

This commit is contained in:
kevstone 2024-02-11 00:04:55 +00:00
parent 5316b0684b
commit ea6fa100c6
19 changed files with 186 additions and 84 deletions

View File

@ -42,6 +42,11 @@ class FuncSig(code_interface.CodeInterface):
@property
def template_type_params(self):
return self._template_type_params
@template_type_params.setter
def template_type_params(self, new_template_type_params):
self._template_type_params = new_template_type_params
@property
def is_declaration(self):

View File

@ -38,6 +38,10 @@ class Function(code_interface.CodeInterface):
def body(self, lines):
self._body = lines
@property
def is_template(self):
return len(self._funcsig.template_type_params) > 0
# The whole function will be returned: signature and body (in braces)
def as_lines(self):
lines = [self.funcsig_as_definition]

View File

@ -2,6 +2,7 @@ import utils.debug as debug
import code_object.arg as arg
import code_object.code_interface as code_interface
import code_object.value_declaration_reference as value_declaration_reference
import code_object_converter.conversion_pack.arg_utils as arg_utils
from utils.string_funcs import strip_semicolon
from code_object.code_interface import NONE_VALUE
@ -30,5 +31,7 @@ class FunctionCall(code_interface.CodeInterface):
assert isinstance(arg_entry, code_interface.CodeInterface), f"arg_entry must be a CodeInterface class, supplied=[{arg_entry}]"
self._args.append(arg_entry)
def as_lines(self):
return [f"{self._name}({', '.join([strip_semicolon(a.as_string()) for a in self._args])});"]
return [f"{self._name}({', '.join([arg_utils.extract_function_call_name(a) for a in self._args])});"]
#return [f"{self._name}({', '.join([strip_semicolon(a.as_string()) for a in self._args])});"]

View File

@ -21,8 +21,13 @@ class MemberFunction(function.Function):
# Overridden to add class_name::
@property
def funcsig_as_definition(self):
funcsig_string = re.sub(r"^(.*\s)([^\(]*\()", rf"\1{self._class_name}::\2", self._funcsig.as_string())
return funcsig_string
lines = self.funcsig.as_lines()
if lines[0].startswith("template"):
lines[1] = re.sub(r"^(.*\s)([^\(]*\()", rf"\1{self._class_name}::\2", lines[1])
else:
lines[0] = re.sub(r"^(.*\s)([^\(]*\()", rf"\1{self._class_name}::\2", lines[0])
return "\n".join(lines)
@property
def is_const(self):

View File

@ -11,6 +11,7 @@ from code_object.value_declaration_reference import ValueDeclarationReference
from code_object.unary_operation import UnaryOperation
from code_object.unary_expression import UnaryExpression
from code_object.paren_expression import ParenExpression
from utils.string_funcs import strip_semicolon
# Try to extract a name value from the object, else return ""
def extract_name(cpp_obj):
@ -45,7 +46,12 @@ def extract_name(cpp_obj):
# expression will a paren_expression, so we need to recurse!
cppname = extract_name(cpp_obj.expression)
if not isinstance(cppname, str):
debug.line("extract_name", f"** Could not extract string name. cppname type=[{type(cppname)}] value=[{debug.as_debug_string(cppname)}]")
cppname = ""
debug.line("extract_name", f"[OUT] cpp_obj=[{debug.as_debug_string(cpp_obj)}] -> cppname=[{cppname}]")
return cppname
# If the code_object has an Arg representation, then this will be returned,
@ -65,3 +71,38 @@ def to_cpparg(cpp_obj, conversion_data):
debug.line("to_cpparg", f"cpp_obj=[{debug.as_debug_string(cpp_obj)}] -> cpparg=[{debug.as_debug_string(cpparg)}]")
return cpparg
# Return the argument in a form that can be used in a function call
def extract_function_call_name(cpp_obj):
cppname = None
if isinstance(cpp_obj, Literal):
cppname = cpp_obj.value
elif isinstance(cpp_obj, Arg):
cppname = cpp_obj.name
elif isinstance(cpp_obj, StructArg):
cppname = cpp_obj.name
elif isinstance(cpp_obj, VariableDeclaration):
cppname = cpp_obj.variable
'''elif isinstance(cpp_obj, ArrayAccess):
cppname = cpp_obj.name
elif isinstance(cpp_obj, StructMemberAccess):
cppname = cpp_obj.name
elif isinstance(cpp_obj, ValueDeclarationReference):
cppname = cpp_obj.value
elif isinstance(cpp_obj, UnaryOperation):
# Operand will a CodeInterface, so we need to recurse!
cppname = self.function_call_name(cpp_obj.operand)
elif isinstance(cpp_obj, UnaryExpression):
# expression will a CodeInterface, so we need to recurse!
cppname = self.function_call_name(cpp_obj.expression)
elif isinstance(cpp_obj, ParenExpression):
# expression will a paren_expression, so we need to recurse!
cppname = self.function_call_name(cpp_obj.expression)'''
if not cppname:
cppname = strip_semicolon(cpp_obj.as_string())
debug.line("function_call_name", f"Converted cpp_obj: [{debug.as_debug_string(cpp_obj)}] -> [{cppname}] cpp_ob type=[{type(cpp_obj)}]")
return cppname

View File

@ -62,13 +62,13 @@ class ConversionData:
# ------------------------------ SET ------------------------------
def add_funcsig_mapping(self, mapping):
def add_global_funcsig_mapping(self, mapping):
assert isinstance(mapping, funcsig_mapping.FuncSigMapping), f"Expected FuncSigMapping, got type=[{type(mapping).__name__}]"
for entry in self.active_map.funcsig_mappings:
for entry in self._global_mappings.funcsig_mappings:
if entry.cfuncsig.name == mapping.cfuncsig.name:
assert False, f"Mapping for [{mapping.cfuncsig.name}] already exists!"
self.active_map.funcsig_mappings.append(mapping)
self._global_mappings.funcsig_mappings.append(mapping)
# These need to be global as all functions may access them...
def add_global_member_funcsig_mapping(self, mapping):
@ -135,6 +135,14 @@ class ConversionData:
for entry in mapping.all_funcsig_mappings:
if entry.cfuncsig.name == cfuncname and entry.cppfuncsig:
return entry
# is this a template?
if "<" in cfuncname:
template_index = cfuncname.index("<")
non_template_name = cfuncname[:template_index]
debug.line("funcsig_mapping_for_cfuncname", f"cfuncname=[{cfuncname}] is a template, checking non_template_name=[{non_template_name}]")
return self.funcsig_mapping_for_cfuncname(non_template_name)
return None
def funcsig_mapping_for_current_cfuncname(self):
@ -460,6 +468,10 @@ class ConversionData:
if entry.cppfuncsig and entry.cppfuncsig != NONE_VALUE and entry.cppfuncsig.name == function_name:
return True
return self.is_virtual_member_function(function_name)
def is_virtual_member_function(self, function_name):
for entry in self._global_mappings.virtual_member_funcsig_mappings:
if entry.cfuncsig.name == function_name:
return True
@ -468,6 +480,7 @@ class ConversionData:
return False
def is_self_class_pointer_name(self, name):
debug.line("is_self_class_pointer_name", f"Testing name=[{debug.as_debug_string(name)}]")
for mapping in self.all_mappings():

View File

@ -26,6 +26,8 @@ class FuncSigConverter(code_interface_converter.CodeInterfaceConverter):
debug.line("", f"cppfuncsig is NONE_VALUE for cfuncsig.name=[{cfuncsig.name}] so won't be converted")
return NONE_VALUE
cppfuncsig.template_type_params = cfuncsig.template_type_params
# Add any buffer mappings: {ptr, buffer} -> C++ Container
if mapping.arg_indexes:
cbuffer = cfuncsig.args[mapping.arg_indexes.cbuffer]
@ -38,23 +40,20 @@ class FuncSigConverter(code_interface_converter.CodeInterfaceConverter):
cppfuncsig = funcsig.FuncSig(cppfunc_arg.decl_spec,
cppfunc_arg.name,
cpp_args,
self._ccode_object.template_type_params)
cfuncsig.template_type_params)
#cppfuncsig.static = self.is_cpp_static()
# Add this to the correct conversion data mappings
mapping = funcsig_mapping.FuncSigMapping(cfuncsig, cppfuncsig)
# 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)
conversion_pack.conversion_data.add_global_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

View File

@ -5,6 +5,7 @@ import code_object_converter.code_interface_converter as code_interface_converte
import code_object_converter.conversion_funcs as conversion_funcs
import code_object.arg as arg
from code_object.code_interface import NONE_VALUE
import code_object_converter.conversion_pack.arg_utils as arg_utils
class FunctionCallConverter(code_interface_converter.CodeInterfaceConverter):
def __init__(self, ccode_object) -> None:
@ -30,9 +31,20 @@ class FunctionCallConverter(code_interface_converter.CodeInterfaceConverter):
if arg_entry != NONE_VALUE:
cpp_arg_entry = conversion_funcs.convert_ccode_object(cfunction_call.args[i], conversion_pack)
assert cpp_arg_entry != NONE_VALUE, f"Expected cpp_arg_entry for carg=[{debug.as_debug_string(cfunction_call.args[i])}], got NoneValue!"
# Check if we have a container arg
cpp_arg_name = arg_utils.extract_name(cpp_arg_entry)
if cpp_arg_name:
cpp_container_arg = conversion_pack.container_utils.cname_to_cpp_container(cpp_arg_name, conversion_pack.conversion_data)
if cpp_container_arg:
cpp_arg_entry = cpp_container_arg
cpp_args.append(cpp_arg_entry)
cppfunction_call = function_call.FunctionCall(mapping.cppfuncsig.name, cpp_args)
debug.line("create_cpp_code_object", f"cppfunction_call NOW EQUALS [{debug.as_debug_string(cppfunction_call)}]")
else:
debug.line("create_cpp_code_object", f"FunctionCallConverter [2]")
# 2. Perform a manual conversion

View File

@ -16,9 +16,13 @@ class GlobalFunctionConverter(function_converter.FunctionConverter):
cpp_body = code_objects.CodeObjects()
for entry in self._ccode_object.body.code_objects:
if isinstance(entry, funcsig.FuncSig) and self._conversion_pack.conversion_data.is_member_function(entry.name):
debug.line("create_cpp_code_object", f"Ignoring member function name=[{entry.name}]")
continue
if isinstance(entry, funcsig.FuncSig):
if self._conversion_pack.conversion_data.is_member_function(entry.name):
debug.line("create_cpp_code_object", f"Ignoring member function name=[{entry.name}]")
continue
if self._conversion_pack.conversion_data.is_virtual_member_function(entry.name):
debug.line("create_cpp_code_object", f"Ignoring virtual member function name=[{entry.name}]")
continue
cpp_code_obj = conversion_funcs.convert_ccode_object(entry, self._conversion_pack)
cpp_body.add_code_object(cpp_code_obj)

View File

@ -59,6 +59,19 @@ class CppCode:
def global_function(self):
return self._code_elements.global_function
# Returns all functions, in dependency order (as best as possible)
# Templates are returned ahead of others in each set
@property
def all_functions(self):
sorted_functions = sorted(self.functions, key=lambda instance: instance.is_template, reverse=True)
sorted_member_functions = sorted(self.member_functions, key=lambda instance: instance.is_template, reverse=True)
sorted_virtual_member_functions = sorted(self.virtual_member_functions, key=lambda instance: instance.is_template, reverse=True)
sorted_constructor = [self.constructor] if self.constructor else []
sorted_destructor = [self.destructor] if self.destructor else []
return sorted_functions + sorted_member_functions + sorted_constructor + sorted_virtual_member_functions + sorted_destructor
@property
def functions(self):
return self._code_elements.functions

View File

@ -113,7 +113,7 @@ class DefaultCCodeConverter:
self._code_elements.add_data_member(cppmember)
# Override to return True if the member function should be marked const
def is_const_member_function(self, function_name):
def is_const_member_function(self, function_name, conv_pack):
return False
# Helper to ensure the function is converted correctly, including resetting the local conversion data!
@ -126,7 +126,7 @@ class DefaultCCodeConverter:
cpp_func = conversion_funcs.convert_ccode_object(func, conv_pack)
if isinstance(cpp_func, member_function.MemberFunction):
cpp_func.class_name = conv_pack.conversion_data.info.class_name
cpp_func.set_is_const(self.is_const_member_function(func.funcsig.name))
cpp_func.set_is_const(self.is_const_member_function(func.funcsig.name, conv_pack))
return cpp_func

View File

@ -18,30 +18,8 @@ namespace {{ c.nested_namespaces }} {
{{ c.global_function.as_string() }}
// Globals - END
{% for func in c.functions %}
{% for func in c.all_functions %}
{{ func.as_string() }}
{% endfor %}
{% if c.class_name %}
{{ c.constructor.as_string() }}
{% if c.destructor %}
{{ c.destructor.as_string() }}
{% endif %}
{% for func in c.template_member_functions %}
{{ func.as_string() }}
{% endfor %}
{% for func in c.virtual_member_functions %}
{{ func.as_string() }}
{% endfor %}
{% for func in c.member_functions %}
{{ func.as_string() }}
{% endfor %}
{% endif %}
} // namespace {{ c.nested_namespaces }}

View File

@ -33,6 +33,26 @@ rename = {
class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
def __init__(self, ccode_instance) -> None:
super().__init__(ccode_instance)
self.load_conversion_pack_updates_class()
# See if we have a function-specific updater, otherwise use the main-one
def load_conversion_pack_updates_class(self):
conversion_pack_updates_path="grib_accessor.grib_accessor_conversion_pack.conversion_pack_updates"
cclass_short_name = self._ccode.class_name.replace(prefix, "")
accessor_conversion_pack_updates_mod_name = f"{cclass_short_name}_conversion_pack_updates"
accessor_conversion_pack_updates_lib_name = f"{conversion_pack_updates_path}.{accessor_conversion_pack_updates_mod_name}"
try:
accessor_conversion_pack_updates_lib = importlib.import_module(accessor_conversion_pack_updates_lib_name)
debug.line("function_specific_conversion_pack_updates", f"Loaded accessor_conversion_pack_updates_lib_name=[{accessor_conversion_pack_updates_lib_name}]")
accessor_conversion_pack_updates_class_name = standard_transforms.transform_type_name(accessor_conversion_pack_updates_mod_name)
accessor_conversion_pack_updates_class = getattr(accessor_conversion_pack_updates_lib, accessor_conversion_pack_updates_class_name)
debug.line("function_specific_conversion_pack_updates", f"Loaded accessor_conversion_pack_updates_class_name=[{accessor_conversion_pack_updates_class_name}]")
self._conversion_pack_updates = accessor_conversion_pack_updates_class()
except ModuleNotFoundError:
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")
self._conversion_pack_updates = base_conversion_pack_updates.BaseConversionPackUpdates()
# Convert e.g. grib_accessor_class_proj_string.cc to ProjStringData.cc
def transform_file_name(self, name):
@ -59,27 +79,7 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
return info
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"
cclass_short_name = self._ccode.class_name.replace(prefix, "")
accessor_conversion_pack_updates_mod_name = f"{cclass_short_name}_conversion_pack_updates"
accessor_conversion_pack_updates_lib_name = f"{conversion_pack_updates_path}.{accessor_conversion_pack_updates_mod_name}"
try:
accessor_conversion_pack_updates_lib = importlib.import_module(accessor_conversion_pack_updates_lib_name)
debug.line("function_specific_conversion_pack_updates", f"Loaded accessor_conversion_pack_updates_lib_name=[{accessor_conversion_pack_updates_lib_name}]")
accessor_conversion_pack_updates_class_name = standard_transforms.transform_type_name(accessor_conversion_pack_updates_mod_name)
accessor_conversion_pack_updates_class = getattr(accessor_conversion_pack_updates_lib, accessor_conversion_pack_updates_class_name)
debug.line("function_specific_conversion_pack_updates", f"Loaded accessor_conversion_pack_updates_class_name=[{accessor_conversion_pack_updates_class_name}]")
updates_class_inst = accessor_conversion_pack_updates_class()
except ModuleNotFoundError:
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, conv_pack)
self._conversion_pack_updates.apply_updates_for_cfunction(cfunction_name, conv_pack)
super().function_specific_conversion_pack_updates(cfunction_name, conv_pack)
# See if we have an Accessor-specific validator (e.g. ProjStringValidation),
@ -121,6 +121,8 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
for mapping in grib_accessor_virtual_member_funcsig_mapping:
conv_data.add_global_virtual_member_funcsig_mapping(mapping)
self._conversion_pack_updates.add_funcsig_mappings_to_conversion_data(conv_data)
all_funcsig_mappings.add_all_funcsig_mappings_to_conversion_data(conv_data)
arg_mappings.add_arg_mappings_to_conversion_data(conv_data)
@ -161,8 +163,18 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
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
def is_const_member_function(self, function_name, conv_pack):
if function_name in ["init", "destroy"]:
return False
if conv_pack.conversion_data.is_virtual_member_function(function_name):
return function_name in virtual_member_functions.const_virtual_member_function_names
if conv_pack.conversion_data.is_member_function(function_name):
return True
return False
def post_process_function_calls(self):
debug.line("post_process_function_calls", f"Function calls summary:")

View File

@ -7,6 +7,12 @@ from code_object.code_interface import NONE_VALUE
class BaseConversionPackUpdates:
def __init__(self) -> None:
self._update_funcs = {}
self._funcsig_mappings = []
def add_funcsig_mappings_to_conversion_data(self, conversion_data):
for mapping in self._funcsig_mappings:
debug.line("add_funcsig_mappings_to_conversion_data", f"Adding funcsig mapping: [{mapping.cfuncsig.name}] -> [{mapping.cppfuncsig.name}]")
conversion_data.add_global_funcsig_mapping(mapping)
# Use this entry point to call the appropriate derived function
def apply_updates_for_cfunction(self, cfuncname, conversion_pack):

View File

@ -2,6 +2,10 @@
import utils.debug as debug
import grib_accessor.grib_accessor_conversion_pack.conversion_pack_updates.base_conversion_pack_updates as base_conversion_pack_updates
from code_object.arg import Arg
from code_object_converter.conversion_pack.funcsig_mapping import FuncSigMapping
from code_object_converter.conversion_pack.arg_indexes import ArgIndexes
from code_object.funcsig import FuncSig
from code_object.code_interface import NONE_VALUE
class BitConversionPackUpdates(base_conversion_pack_updates.BaseConversionPackUpdates):
def __init__(self) -> None:

View File

@ -0,0 +1,19 @@
import utils.debug as debug
import grib_accessor.grib_accessor_conversion_pack.conversion_pack_updates.base_conversion_pack_updates as base_conversion_pack_updates
from code_object.arg import Arg
from code_object_converter.conversion_pack.funcsig_mapping import FuncSigMapping
from code_object_converter.conversion_pack.arg_indexes import ArgIndexes
from code_object.funcsig import FuncSig
from code_object.code_interface import NONE_VALUE
class BitmapConversionPackUpdates(base_conversion_pack_updates.BaseConversionPackUpdates):
def __init__(self) -> None:
super().__init__()
self._funcsig_mappings.extend([
# template<typename T> static int unpack_helper(grib_accessor* a, T* val, size_t* len)
FuncSigMapping(FuncSig("int", "unpack_helper", [Arg("grib_accessor*", "a"), Arg("T*", "val"), Arg("size_t*", "len")]),
FuncSig("GribStatus", "unpackHelper", [NONE_VALUE, Arg("std::vector<T>&", "vecTValues"), NONE_VALUE]),
ArgIndexes(cbuffer=1, clength=2, cpp_container=1)),
])

View File

@ -94,7 +94,7 @@ class GribAccessorConversionValidation(default_conversion_validation.DefaultConv
def validate_function_call_arg(self, calling_arg_value, target_arg):
if "AccessorName" in target_arg.decl_spec.type:
return literal.Literal(f"AccessorName({calling_arg_value.as_string()})")
return literal.Literal(f"AccessorName({arg_utils.extract_function_call_name(calling_arg_value)})")
return super().validate_function_call_arg(calling_arg_value, target_arg)
@ -110,11 +110,11 @@ class GribAccessorConversionValidation(default_conversion_validation.DefaultConv
arg_entry = literal.Literal(f"initData.args[{arg_string}].second")
return function_call.FunctionCall(f"std::get<long>", [arg_entry])
# If we're calling grib_XXX which is a member function, and the first argument is "a", then we're actually calling ourself!
# If we're calling grib_XXX which is a virtual member function, and the first argument is "a", then we're actually calling ourself!
if cfunction_call.name.startswith("grib_"):
updated_cfuncname = cfunction_call.name[5:]
if self._conversion_data.is_member_function(updated_cfuncname) and \
len(cppfunction_call.args) > 0 and cppfunction_call.args[0].as_string() == "a":
if self._conversion_data.is_virtual_member_function(updated_cfuncname) and \
len(cfunction_call.args) > 0 and cfunction_call.args[0].as_string() == "a":
mapping = self._conversion_data.funcsig_mapping_for_cfuncname(updated_cfuncname)
if mapping:
updated_cppfunction_call = function_call.FunctionCall(mapping.cppfuncsig.name, cppfunction_call.args[1:])

View File

@ -18,23 +18,7 @@ namespace {{ c.nested_namespaces }} {
{{ c.global_function.as_string() }}
// Globals - END
{% for func in c.functions %}
{{ func.as_string() }}
{% endfor %}
{% if c.constructor %}
{{ c.constructor.as_string() }}
{% endif %}
{% if c.destructor %}
{{ c.destructor.as_string() }}
{% endif %}
{% for func in c.virtual_member_functions %}
{{ func.as_string() }}
{% endfor %}
{% for func in c.member_functions %}
{% for func in c.all_functions %}
{{ func.as_string() }}
{% endfor %}

View File

@ -12,4 +12,4 @@ def add_all_funcsig_mappings_to_conversion_data(conversion_data):
for mapping in all_funcsig_mappings():
for entry in mapping:
debug.line("add_all_funcsig_mappings_to_conversion_data", f"ADDING FUNCIG MAPPING: [{entry.cfuncsig.name}] -> [{entry.cppfuncsig.name}]")
conversion_data.add_funcsig_mapping(entry)
conversion_data.add_global_funcsig_mapping(entry)