mirror of https://github.com/ecmwf/eccodes.git
Added support for using Class::func
This commit is contained in:
parent
7a575acd5a
commit
ba803aa537
|
@ -3,6 +3,7 @@ import code_object.arg as arg
|
|||
import code_object.code_interface as code_interface
|
||||
import code_object.value_declaration_reference as value_declaration_reference
|
||||
from utils.string_funcs import strip_semicolon
|
||||
from code_object.code_interface import NONE_VALUE
|
||||
|
||||
# Represent a function call
|
||||
#
|
||||
|
|
|
@ -8,6 +8,7 @@ from code_object.variable_declaration import VariableDeclaration
|
|||
from code_object.array_access import ArrayAccess
|
||||
from code_object.struct_member_access import StructMemberAccess
|
||||
from code_object.value_declaration_reference import ValueDeclarationReference
|
||||
from code_object.unary_operation import UnaryOperation
|
||||
|
||||
# Try to extract a name value from the object, else return ""
|
||||
def extract_name(cpp_obj):
|
||||
|
@ -28,6 +29,9 @@ def extract_name(cpp_obj):
|
|||
return cpp_obj.name
|
||||
elif isinstance(cpp_obj, ValueDeclarationReference):
|
||||
return cpp_obj.value
|
||||
elif isinstance(cpp_obj, UnaryOperation):
|
||||
# Operand will a CodeInterface, so we need to recurse!
|
||||
return extract_name(cpp_obj.operand)
|
||||
|
||||
return ""
|
||||
|
||||
|
|
|
@ -5,11 +5,14 @@ import code_object_converter.conversion_pack.code_mappings as code_mappings
|
|||
import code_object_converter.conversion_pack.funcsig_mapping as funcsig_mapping
|
||||
import code_object_converter.conversion_pack.funcsig_pointer_mapping as funcsig_pointer_mapping
|
||||
from code_object.arg import Arg
|
||||
from code_object.function_call import FunctionCall
|
||||
from code_object.funcsig import FuncSig
|
||||
from code_object.data_member import DataMember
|
||||
from code_object.declaration_specifier import DeclSpec
|
||||
from code_object_converter.conversion_pack.conversion_data_helper import *
|
||||
from code_object.code_interface import NONE_VALUE
|
||||
import code_object_converter.conversion_pack.buffer_mapping as buffer_mapping
|
||||
import code_object_converter.conversion_pack.arg_utils as arg_utils
|
||||
from copy import deepcopy
|
||||
|
||||
# Store C to C++ conversion data to be used by the converters
|
||||
|
@ -22,6 +25,9 @@ class ConversionData:
|
|||
self._global_mappings = code_mappings.CodeMappings()
|
||||
self._local_mappings = None
|
||||
|
||||
# The name of the c function currently being processed
|
||||
self._current_cfuncname = ""
|
||||
|
||||
# Call this to ensure local state is set ready for function conversions
|
||||
def set_local_state(self):
|
||||
self._state = ConversionDataState.LOCAL
|
||||
|
@ -30,7 +36,7 @@ class ConversionData:
|
|||
# Clear out / reset local state data ready to convert a new function (cfuncname)
|
||||
def reset_local_state(self, cfuncname):
|
||||
self._local_mappings = code_mappings.CodeMappings()
|
||||
self.info.current_cfuncname = cfuncname
|
||||
self._current_cfuncname = cfuncname
|
||||
debug.line("reset_local_state", f"cfuncname=[{cfuncname}]")
|
||||
|
||||
# The info object can be manipulated directly
|
||||
|
@ -156,6 +162,26 @@ class ConversionData:
|
|||
assert isinstance(type, str), f"Expected str, got [{type}]"
|
||||
self.active_map.container_types.append(type)
|
||||
|
||||
# Converts the function call into a funcsig object (with void return type) and stores in the info
|
||||
# object. This allows all arg type information to be available (for example when post-processing)
|
||||
def add_cppfunction_call(self, cppfunction_call):
|
||||
assert isinstance(cppfunction_call, FunctionCall), f"Expected FunctionCall, got [{cppfunction_call}]"
|
||||
|
||||
cppargs = []
|
||||
for entry in cppfunction_call.args:
|
||||
cppname = arg_utils.extract_name(entry)
|
||||
cpparg = self.cpparg_for_cname(cppname) if cppname else None
|
||||
debug.line("add_cppfunction_call", f"[{debug.as_debug_string(cppfunction_call)}]---> entry type=[{type(entry)}] value=[{debug.as_debug_string(entry)}] cppname=[{debug.as_debug_string(cppname)}] cpparg=[{debug.as_debug_string(cpparg)}]")
|
||||
assert cppname
|
||||
|
||||
if cpparg and cpparg != NONE_VALUE:
|
||||
cppargs.append(cpparg)
|
||||
|
||||
cppfuncsig = FuncSig("void", cppfunction_call.name, cppargs)
|
||||
|
||||
self._info.add_function_call_entry(cppfuncsig)
|
||||
debug.line("add_cppfunction_call", f"Added function call cppfunction_call=[{debug.as_debug_string(cppfunction_call)}] -> cppfuncsig=[{debug.as_debug_string(cppfuncsig)}]")
|
||||
|
||||
# ============================== Functions to update the mappings: end ==============================
|
||||
|
||||
# ============================== Functions to query the mappings: start ==============================
|
||||
|
@ -338,7 +364,7 @@ class ConversionData:
|
|||
return None
|
||||
|
||||
def funcsig_mapping_for_current_cfuncname(self):
|
||||
return self.funcsig_mapping_for_cfuncname(self._info.current_cfuncname)
|
||||
return self.funcsig_mapping_for_cfuncname(self._current_cfuncname)
|
||||
|
||||
def funcsig_buffer_mapping_for_cname(self, cname):
|
||||
for mapping in self.all_mappings():
|
||||
|
|
|
@ -35,10 +35,17 @@ class FunctionCallConverter(code_interface_converter.CodeInterfaceConverter):
|
|||
for arg_entry in self._ccode_object.args:
|
||||
cpp_arg_entry = conversion_funcs.convert_ccode_object(arg_entry, conversion_pack)
|
||||
|
||||
if cpp_arg_entry != NONE_VALUE:
|
||||
if cpp_arg_entry and cpp_arg_entry != NONE_VALUE:
|
||||
cpp_args.append(cpp_arg_entry)
|
||||
|
||||
cppfunction_call = function_call.FunctionCall(cpp_name, cpp_args)
|
||||
|
||||
# 3. Apply validation (and special handling)
|
||||
return conversion_pack.conversion_validation.validate_function_call(cfunction_call, cppfunction_call)
|
||||
updated_cppfunction_call = conversion_pack.conversion_validation.validate_function_call(cfunction_call, cppfunction_call)
|
||||
|
||||
# 4. Add the function call to the conversion data in case we need to process it later (e.g. for using C::x declarations)
|
||||
# Only if function_call type!
|
||||
if isinstance(updated_cppfunction_call, function_call.FunctionCall):
|
||||
conversion_pack.conversion_data.add_cppfunction_call(updated_cppfunction_call)
|
||||
|
||||
return updated_cppfunction_call
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
|
||||
import utils.debug as debug
|
||||
from code_object.funcsig import FuncSig
|
||||
|
||||
# Stores info about the code, such as class name, includes etc
|
||||
#
|
||||
# NOTE: Any data stored here will be part of the final CppCode object
|
||||
class CodeInfo:
|
||||
def __init__(self, file_name, class_name, super_class_name="") -> None:
|
||||
self._file_name = file_name
|
||||
|
@ -9,11 +12,10 @@ class CodeInfo:
|
|||
self._super_class_name = super_class_name
|
||||
self._namespaces = []
|
||||
self._forward_declarations = []
|
||||
self._base_function_names = [] # i.e. for using ClassName::funcName entries
|
||||
self._header_includes = []
|
||||
self._source_includes = []
|
||||
|
||||
# Access directly to set/get the name of the c function currently being processed
|
||||
self.current_cfuncname = ""
|
||||
self._function_calls = [] # List all function calls made whilst converting (for post-processing)
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
|
@ -35,6 +37,10 @@ class CodeInfo:
|
|||
def forward_declarations(self):
|
||||
return self._forward_declarations
|
||||
|
||||
@property
|
||||
def base_function_names(self):
|
||||
return self._base_function_names
|
||||
|
||||
@property
|
||||
def header_includes(self):
|
||||
return self._header_includes
|
||||
|
@ -43,14 +49,31 @@ class CodeInfo:
|
|||
def source_includes(self):
|
||||
return self._source_includes
|
||||
|
||||
@property
|
||||
def function_calls(self):
|
||||
return self._function_calls
|
||||
|
||||
def add_namespace(self, entry):
|
||||
self._namespaces.append(entry)
|
||||
|
||||
def add_forward_declaration(self, entry):
|
||||
self._forward_declarations.append(entry)
|
||||
|
||||
def add_base_function_name(self, funcname):
|
||||
if funcname not in self._base_function_names:
|
||||
self._base_function_names.append(funcname)
|
||||
|
||||
def add_header_include(self, entry):
|
||||
self._header_includes.append(entry)
|
||||
|
||||
def add_source_include(self, entry):
|
||||
self._source_includes.append(entry)
|
||||
|
||||
def add_function_call_entry(self, entry):
|
||||
assert isinstance(entry, FuncSig), f"add_function_call_entry requires FuncSig, not [{entry}]"
|
||||
|
||||
for func_call in self._function_calls:
|
||||
if entry.name == func_call.name:
|
||||
return # Duplicate
|
||||
|
||||
self._function_calls.append(entry)
|
||||
|
|
|
@ -39,6 +39,10 @@ class CppCode:
|
|||
def forward_declarations(self):
|
||||
return self._code_info.forward_declarations
|
||||
|
||||
@property
|
||||
def base_function_names(self):
|
||||
return self._code_info.base_function_names
|
||||
|
||||
@property
|
||||
def header_file_includes(self):
|
||||
return self._code_info.header_includes
|
||||
|
@ -79,10 +83,6 @@ class CppCode:
|
|||
def virtual_member_functions(self):
|
||||
return self._code_elements.virtual_member_functions
|
||||
|
||||
@property
|
||||
def virtual_member_functions_using_list(self):
|
||||
return []
|
||||
|
||||
@property
|
||||
def data_members(self):
|
||||
return self._code_elements.data_members
|
||||
|
|
|
@ -35,6 +35,9 @@ class DefaultCCodeConverter:
|
|||
self.convert_member_functions()
|
||||
self.convert_virtual_member_functions()
|
||||
|
||||
# Post-processing
|
||||
self.run_post_processing()
|
||||
|
||||
return cppcode.CppCode(self._code_info, self._code_elements)
|
||||
|
||||
# ============================== Setup functions: start ==============================
|
||||
|
@ -111,6 +114,7 @@ class DefaultCCodeConverter:
|
|||
if isinstance(cpp_func, member_function.MemberFunction):
|
||||
cpp_func.class_name = self._conversion_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):
|
||||
|
@ -145,6 +149,18 @@ class DefaultCCodeConverter:
|
|||
self._code_elements.add_virtual_member_function(virtual_member_func)
|
||||
self.dump_function("convert_virtual_member_functions", virtual_member_func)
|
||||
|
||||
# ============================== Post-processing: begin ==============================
|
||||
|
||||
def run_post_processing(self):
|
||||
self.post_process_function_calls()
|
||||
|
||||
# Override as required...
|
||||
def post_process_function_calls(self):
|
||||
pass
|
||||
|
||||
# ============================== Post-processing: end ==============================
|
||||
|
||||
|
||||
# Helper for consistent debug output!
|
||||
def dump_function(self, def_name, cppfunc):
|
||||
debug.line("dump_function", "================================================================================")
|
||||
|
|
|
@ -21,6 +21,9 @@ import grib_accessor.supporting.arg_mappings as arg_mappings
|
|||
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 code_object_converter.conversion_pack.arg_utils as arg_utils
|
||||
|
||||
|
||||
prefix = "grib_accessor_class_"
|
||||
rename = {
|
||||
"Gen": "Accessor", # "Generic",
|
||||
|
@ -56,7 +59,6 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
|
|||
|
||||
return info
|
||||
|
||||
#
|
||||
def function_specific_conversion_pack_updates(self, cfunction_name):
|
||||
super().function_specific_conversion_pack_updates(cfunction_name)
|
||||
# See if we have a function-specific validator,
|
||||
|
@ -134,3 +136,32 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter):
|
|||
|
||||
def is_const_member_function(self, function_name):
|
||||
return function_name in virtual_member_functions.const_virtual_member_function_names
|
||||
|
||||
def post_process_function_calls(self):
|
||||
debug.line("post_process_function_calls", f"Function calls summary:")
|
||||
|
||||
for funcsig_call in self._code_info.function_calls:
|
||||
debug.line("post_process_function_calls", f" -> [{debug.as_debug_string(funcsig_call)}]")
|
||||
# See if this is a virtual function that isn't defined for this class, and add a using
|
||||
# statement for it...
|
||||
|
||||
mismatch_found = False
|
||||
for virt_func in self._code_elements.virtual_member_functions:
|
||||
debug.line("post_process_function_calls", f"CHECKING VIRT_FUNC funcsig=[{debug.as_debug_string(virt_func.funcsig)}]")
|
||||
|
||||
if funcsig_call.name == virt_func.funcsig.name:
|
||||
debug.line("post_process_function_calls", f"NAME MATCH -> funcsig_call=[{debug.as_debug_string(funcsig_call)}] virt_func.funcsig=[{debug.as_debug_string(virt_func.funcsig)}]")
|
||||
|
||||
# Get just the valid (not NONE_VALUE) args for the virtual function under test
|
||||
virt_func_args = [a for a in virt_func.funcsig.args if a != NONE_VALUE]
|
||||
|
||||
for i in range(len(funcsig_call.args)):
|
||||
if funcsig_call.args[i].decl_spec.type != virt_func_args[i].decl_spec.type:
|
||||
# MISMATCH: Add base function name
|
||||
debug.line("post_process_function_calls", f"MISMATCH FOUND, adding base function name=[{funcsig_call.name}]: i=[{i}] funcsig_call.args[i]=[{debug.as_debug_string(funcsig_call.args[i])}] virt_func_args[i]=[{debug.as_debug_string(virt_func_args[i])}]")
|
||||
self._code_info.add_base_function_name(funcsig_call.name)
|
||||
mismatch_found = True
|
||||
break
|
||||
|
||||
if mismatch_found:
|
||||
break
|
||||
|
|
|
@ -33,8 +33,8 @@ public:
|
|||
|
||||
protected:
|
||||
// Virtual member functions
|
||||
{%- for u in c.virtual_member_functions_using_list %}
|
||||
using c.class_name::{{u}};{% endfor %}
|
||||
{%- for u in c.base_function_names %}
|
||||
using AccessorData::{{u}};{% endfor %}
|
||||
{%- for m in c.virtual_member_functions %}
|
||||
{{ m.funcsig_as_declaration }};{% endfor %}
|
||||
|
||||
|
|
Loading…
Reference in New Issue