diff --git a/src/clang_convert/code_object/arg.py b/src/clang_convert/code_object/arg.py index cbac60080..0105c4575 100755 --- a/src/clang_convert/code_object/arg.py +++ b/src/clang_convert/code_object/arg.py @@ -12,8 +12,11 @@ class Arg(code_interface.CodeInterface): def __init__(self, decl_spec, name="", is_func_arg=False) -> None: if isinstance(decl_spec, DeclSpec): self._decl_spec = DeclSpec.from_instance(decl_spec) - else: + elif isinstance(decl_spec, str): self._decl_spec = DeclSpec.from_decl_specifier_seq(decl_spec) + else: + assert False, f"Unexpected decl_spec=[{decl_spec}]" + self._name = name self._is_func_arg = is_func_arg # Support for processing function sig args differently to other args diff --git a/src/clang_convert/code_object/declaration_specifier.py b/src/clang_convert/code_object/declaration_specifier.py index d5b70f556..39b1e7beb 100755 --- a/src/clang_convert/code_object/declaration_specifier.py +++ b/src/clang_convert/code_object/declaration_specifier.py @@ -16,9 +16,34 @@ class DeclSpec(code_interface.CodeInterface): self._type = type self._pointer = pointer + # ---------- Support for NoneDeclSpec: Begin ---------- + + # NoneDeclSpec is used when a C DeclSpec doesn't have a C++ equivalent (i.e. we don't want to convert it!) + class _NoneDeclSpec: + def __repr__(self): + return "" + + def __eq__(self, other): + # This version is required for testing DeclSpec.NONE = + # As the DeclSpec.__eq__ version won't be called when self=DeclSpec.NONE !!! + return isinstance(other, DeclSpec._NoneDeclSpec) + + def __ne__(self, other): + return not self.__eq__(other) + + NONE = _NoneDeclSpec() # The singleton instance to represent "None" + + # ---------- Support for NoneDeclSpec: End ---------- + + # Create a DeclSpec from a string representing the sequence, e.g. "const char*" + # Pass None (or empty string) to return DeclSpec.NONE @classmethod def from_decl_specifier_seq(cls, decl_specifier_seq): - assert decl_specifier_seq, f"Unexpected decl_specifier_seq=[{decl_specifier_seq}]" + if not decl_specifier_seq: + return DeclSpec.NONE + + assert isinstance(decl_specifier_seq, str), f"Expected str, got [{decl_specifier_seq}]" + decl_specifier_seq = decl_specifier_seq.strip() storage_class = "" const_qualifier = "" @@ -97,15 +122,19 @@ class DeclSpec(code_interface.CodeInterface): def is_array_type(self): return self.pointer == "[]" - # Support for DeclSpec as a dict key + # ---------- Support for DeclSpec as a dict key: Begin ---------- def __hash__(self): return hash((self._storage_class, self._const_qualifier, self.type, self._pointer)) # Support for DeclSpec as a dict key def __eq__(self, other): - if isinstance(other, DeclSpec): - return self.storage_class == other.storage_class and self.const_qualifier == other.const_qualifier and self.pointer == other.pointer and self.type == other.type - return False + if self is DeclSpec.NONE or other is DeclSpec.NONE: + return self is other + return self.storage_class == other.storage_class and self.const_qualifier == other.const_qualifier and self.pointer == other.pointer and self.type == other.type + + def __ne__(self, other): + return not self.__eq__(other) + # ---------- Support for DeclSpec as a dict key: End ---------- # Return the full decl-specifier-seq as a (parsed) string (i.e. consistent spacing etc, not just what was passed in!) def as_lines(self): diff --git a/src/clang_convert/code_object/variable_declaration.py b/src/clang_convert/code_object/variable_declaration.py index 6327d0554..c482471f2 100755 --- a/src/clang_convert/code_object/variable_declaration.py +++ b/src/clang_convert/code_object/variable_declaration.py @@ -13,7 +13,8 @@ class VariableDeclaration(code_interface.CodeInterface): self._variable = variable self._value = value - assert isinstance(self._variable, arg.Arg), f"Variable must be an Arg class" + assert self._variable != arg.Arg.NONE, f"Variable can't be NoneArg!" + assert isinstance(self._variable, arg.Arg), f"Variable must be an Arg class, not=[{variable}]" assert isinstance(self._value, code_interface.CodeInterface), f"Value must be a CodeInterface class (or a string)" @property diff --git a/src/clang_convert/code_object_converter/arg_converter.py b/src/clang_convert/code_object_converter/arg_converter.py index fb365fdd4..a76647212 100755 --- a/src/clang_convert/code_object_converter/arg_converter.py +++ b/src/clang_convert/code_object_converter/arg_converter.py @@ -28,10 +28,13 @@ class ArgConverter(code_interface_converter.CodeInterfaceConverter): conversion_data.add_type_mapping(carg.decl_spec, cpp_decl_spec) debug.line("create_cpp_code_object", f"Arg conversion type mapping: carg.decl_spec=[{debug.as_debug_string(carg.decl_spec)}] cpp_decl_spec=[{debug.as_debug_string(cpp_decl_spec)}]") - cpp_name = standard_transforms.transform_variable_name(carg.name) - cpp_is_func_arg = carg.is_func_arg + if cpp_decl_spec == declaration_specifier.DeclSpec.NONE: + cpp_arg = arg.Arg.NONE + else: + cpp_name = standard_transforms.transform_variable_name(carg.name) + cpp_is_func_arg = carg.is_func_arg - cpp_arg = arg.Arg(cpp_decl_spec, cpp_name, cpp_is_func_arg) + cpp_arg = arg.Arg(cpp_decl_spec, cpp_name, cpp_is_func_arg) conversion_data.add_arg_mapping(carg, cpp_arg) debug.line("create_cpp_code_object", f"Arg conversion arg mapping: [{debug.as_debug_string(carg)}] -> [{debug.as_debug_string(cpp_arg)}]") diff --git a/src/clang_convert/code_object_converter/conversion_funcs.py b/src/clang_convert/code_object_converter/conversion_funcs.py index 2629c3c46..2f4d3291e 100755 --- a/src/clang_convert/code_object_converter/conversion_funcs.py +++ b/src/clang_convert/code_object_converter/conversion_funcs.py @@ -102,15 +102,9 @@ CodeInterfaceConverterClasses = { virtual_member_function.VirtualMemberFunction : virtual_member_function_converter.VirtualMemberFunctionConverter, } -def get_debug_string(code_obj): - if code_obj: - return f"{code_obj if type(code_obj) is str else code_obj.as_string()}" - else: - return "None" - # Convert a code_object into a C++ code_object def convert_ccode_object(ccode_object, conversion_data): - debug.line("convert_ccode_object", f"[IN] [{type(ccode_object).__name__}] {get_debug_string(ccode_object)}") + debug.line("convert_ccode_object", f"[IN] [{type(ccode_object).__name__}] {debug.as_debug_string(ccode_object)}") if ccode_object is None: cpp_obj = None @@ -121,6 +115,14 @@ def convert_ccode_object(ccode_object, conversion_data): converter = converter_class(ccode_object) cpp_obj = converter.to_cpp_code_object(conversion_data) - debug.line("convert_ccode_object", f"[OUT][{type(cpp_obj).__name__}] {get_debug_string(cpp_obj)}") + debug.line("convert_ccode_object", f"[OUT][{type(cpp_obj).__name__}] {debug.as_debug_string(cpp_obj)}") return cpp_obj + +def as_commented_out_code(ccode_object, prefix=""): + comment_string = "// " + if prefix: + comment_string += f"[{prefix}] " + comment_string += debug.as_debug_string(ccode_object) + + return literal.Literal(comment_string) \ No newline at end of file diff --git a/src/clang_convert/code_object_converter/supporting/conversion_data.py b/src/clang_convert/code_object_converter/supporting/conversion_data.py index c13c7a5ff..82dcb3b69 100755 --- a/src/clang_convert/code_object_converter/supporting/conversion_data.py +++ b/src/clang_convert/code_object_converter/supporting/conversion_data.py @@ -43,10 +43,10 @@ class ConversionData: def add_type_mapping(self, cdecl_spec, cppdecl_spec): if cdecl_spec in self.active_map.type_mappings: - assert self.active_map.type_mappings[cdecl_spec] == cppdecl_spec, f"Updating an existing arg: [{cdecl_spec.as_string()}] -> [{cppdecl_spec.as_string()}] Previous arg=[{self.active_map.type_mappings[cdecl_spec]}]" + assert self.active_map.type_mappings[cdecl_spec] == cppdecl_spec, f"Updating an existing arg: [{debug.as_debug_string(cdecl_spec)}] -> [{debug.as_debug_string(cppdecl_spec)}] Previous arg=[{self.active_map.type_mappings[cdecl_spec]}]" else: self.active_map.type_mappings[cdecl_spec] = cppdecl_spec - debug.line("add_type_mapping", f"Adding decl_spec: [{cdecl_spec.as_string()}] -> [{cppdecl_spec.as_string()}]") + debug.line("add_type_mapping", f"Adding decl_spec: [{debug.as_debug_string(cdecl_spec)}] -> [{debug.as_debug_string(cppdecl_spec)}]") def add_arg_mapping(self, carg, cpparg): if not carg.name: @@ -54,17 +54,17 @@ class ConversionData: return if carg in self.active_map.arg_mappings: - assert self.active_map.arg_mappings[carg] == cpparg, f"Updating an existing arg: [{carg.as_string()}] -> [{cpparg.as_string()}] Previous arg=[{self.active_map.arg_mappings[carg]}]" + assert self.active_map.arg_mappings[carg] == cpparg, f"Updating an existing arg: [{debug.as_debug_string(carg)}] -> [{debug.as_debug_string(cpparg)}] Previous arg=[{self.active_map.arg_mappings[carg]}]" else: self.active_map.arg_mappings[carg] = cpparg - debug.line("add_arg_mapping", f"Adding arg: [{carg.as_string()}] -> [{cpparg.as_string()}]") + debug.line("add_arg_mapping", f"Adding arg: [{debug.as_debug_string(carg)}] -> [{debug.as_debug_string(cpparg)}]") def add_function_arg_mapping(self, carg, cpparg): if carg in self.active_map.function_arg_mappings: - assert self.active_map.function_arg_mappings[carg] == cpparg, f"Updating an existing function arg: [{carg.as_string()}] -> [{cpparg.as_string()}] Previous function arg=[{self.active_map.function_arg_mappings[carg]}]" + assert self.active_map.function_arg_mappings[carg] == cpparg, f"Updating an existing function arg: [{debug.as_debug_string(carg)}] -> [{debug.as_debug_string(cpparg)}] Previous function arg=[{self.active_map.function_arg_mappings[carg]}]" else: self.active_map.function_arg_mappings[carg] = cpparg - debug.line("add_function_arg_mappings", f"Adding function arg: [{carg.as_string()}] -> [{cpparg.as_string()}]") + debug.line("add_function_arg_mappings", f"Adding function arg: [{debug.as_debug_string(carg)}] -> [{debug.as_debug_string(cpparg)}]") def add_funcsig_mapping(self, mapping): assert isinstance(mapping, funcsig_mapping.FuncSigMapping), f"Expected FuncSigMapping, got type=[{type(mapping).__name__}]" diff --git a/src/clang_convert/code_object_converter/value_declaration_reference_converter.py b/src/clang_convert/code_object_converter/value_declaration_reference_converter.py index 6ef0b16ba..511441c61 100755 --- a/src/clang_convert/code_object_converter/value_declaration_reference_converter.py +++ b/src/clang_convert/code_object_converter/value_declaration_reference_converter.py @@ -1,6 +1,7 @@ import utils.debug as debug import code_object.value_declaration_reference as value_declaration_reference +import code_object.arg as arg import code_object_converter.code_interface_converter as code_interface_converter import code_object_converter.conversion_funcs as conversion_funcs @@ -19,7 +20,7 @@ class ValueDeclarationReferenceConverter(code_interface_converter.CodeInterfaceC # 2. Check if it is an arg cpparg = conversion_data.cpparg_for_carg_name(cdecl_ref_expr_value) - if cpparg: + if cpparg and cpparg != arg.Arg.NONE: return value_declaration_reference.ValueDeclarationReference(cpparg.name) # 3. Perform a default conversion diff --git a/src/clang_convert/code_object_converter/variable_declaration_converter.py b/src/clang_convert/code_object_converter/variable_declaration_converter.py index 3cdcbe34f..b4fe2205d 100755 --- a/src/clang_convert/code_object_converter/variable_declaration_converter.py +++ b/src/clang_convert/code_object_converter/variable_declaration_converter.py @@ -1,6 +1,7 @@ import utils.debug as debug import code_object.variable_declaration as variable_declaration +import code_object.arg as arg import code_object_converter.code_interface_converter as code_interface_converter import code_object_converter.conversion_funcs as conversion_funcs @@ -10,10 +11,16 @@ class VariableDeclarationConverter(code_interface_converter.CodeInterfaceConvert assert isinstance(ccode_object, variable_declaration.VariableDeclaration), f"Expected VariableDeclaration, got type=[{type(ccode_object)}]" def create_cpp_code_object(self, conversion_data): + cpp_variable = conversion_funcs.convert_ccode_object(self._ccode_object.variable, conversion_data) + + if cpp_variable == arg.Arg.NONE: + return conversion_funcs.as_commented_out_code(self._ccode_object, f"Removed invalid variable") + cpp_value = conversion_funcs.convert_ccode_object(self._ccode_object.value, conversion_data) cpp_variable_declaration = variable_declaration.VariableDeclaration(cpp_variable, cpp_value) + return cpp_variable_declaration diff --git a/src/clang_convert/grib_accessor/grib_accessor_ccode_converter.py b/src/clang_convert/grib_accessor/grib_accessor_ccode_converter.py index 3ec411d3e..889a9ffc3 100755 --- a/src/clang_convert/grib_accessor/grib_accessor_ccode_converter.py +++ b/src/clang_convert/grib_accessor/grib_accessor_ccode_converter.py @@ -9,6 +9,7 @@ from grib_accessor.supporting.member_functions import grib_accessor_member_funcs import grib_accessor.supporting.member_functions as member_functions import grib_accessor.supporting.virtual_member_functions as virtual_member_functions import grib_accessor.supporting.includes as includes +import grib_accessor.supporting.grib_types as grib_types prefix = "grib_accessor_class_" rename = { @@ -52,6 +53,8 @@ class GribAccessorCCodeConverter(default_ccode_converter.DefaultCCodeConverter): for mapping in grib_accessor_virtual_member_funcsig_mapping: self._conversion_data.add_virtual_member_funcsig_mapping(mapping) + grib_types.add_grib_types_to_conversion_data(self._conversion_data) + def set_function_specific_conversion_data(self, function_name): pass diff --git a/src/clang_convert/grib_accessor/supporting/grib_types.py b/src/clang_convert/grib_accessor/supporting/grib_types.py new file mode 100755 index 000000000..1ac45b3db --- /dev/null +++ b/src/clang_convert/grib_accessor/supporting/grib_types.py @@ -0,0 +1,37 @@ + +from code_object.arg import Arg +from code_object.declaration_specifier import DeclSpec +import code_object_converter.supporting.conversion_data as conversion_data + +common_grib_type_transforms = { + "grib_accessor*" : "AccessorPtr", + "grib_handle*" : None, + "grib_context*" : None, +} + +grib_array_type_transforms = { + "grib_darray*" : "std::vector", + "grib_iarray*" : "std::vector", + "grib_sarray*" : "std::string", + "grib_vdarray*" : "std::vector>", + "grib_viarray*" : "std::vector>", + "grib_vsarray*" : "std::vector", +} + +grib_array_function_transforms = { + "grib_darray" : "std::vector", + "grib_iarray" : "std::vector", + "grib_sarray" : "std::string", + "grib_vdarray" : "std::vector>", + "grib_viarray" : "std::vector>", + "grib_vsarray" : "std::vector", +} + +def add_grib_types_to_conversion_data(conversion_data): + for type_transforms in [common_grib_type_transforms, grib_array_type_transforms]: + for key, value in type_transforms.items(): + cdecl_spec = DeclSpec.from_decl_specifier_seq(key) + cppdecl_spec = DeclSpec.from_decl_specifier_seq(value) + conversion_data.add_type_mapping(cdecl_spec, cppdecl_spec) + + # TODO - Add Function Transforms... \ No newline at end of file diff --git a/src/clang_convert/utils/debug.py b/src/clang_convert/utils/debug.py index 511919d7a..3b764ee95 100755 --- a/src/clang_convert/utils/debug.py +++ b/src/clang_convert/utils/debug.py @@ -1,5 +1,6 @@ from datetime import datetime +from code_object.code_interface import CodeInterface func_pad = 40 debug_enabled = True @@ -57,13 +58,15 @@ def line(func, text): else: print(f"{func:{func_pad}}:{elapsed_time_str} {text}") -# Safe way to print a CodeInterface object even if it is None - useful for -# debug output -def as_debug_string(code_interface_inst): - if code_interface_inst is not None: - if isinstance(code_interface_inst, str): - return code_interface_inst +# Safe way to print a value even if it is None - useful for +# CodeInstance classes etc +def as_debug_string(value): + if value is not None: + if isinstance(value, str): + return value + elif isinstance(value, CodeInterface): + return value.as_string() else: - return code_interface_inst.as_string() + return f"[{value}]" else: return "None"