From c147a0519984a418ec636421b27a4ba8256d629e Mon Sep 17 00:00:00 2001 From: kevstone Date: Thu, 15 Feb 2024 14:01:46 +0000 Subject: [PATCH] Added support for goto and labels --- .../accessor_working_input_files | 4 +- src/clang_convert/ast_object/ast_parser.py | 44 +++++++++++++++++-- .../code_object/case_statement.py | 2 - .../code_object/function_call.py | 4 +- .../code_object/goto_statement.py | 21 +++++++++ .../code_object/label_statement.py | 33 ++++++++++++++ .../case_statement_converter.py | 4 +- .../code_object_converter/conversion_funcs.py | 6 +++ .../conversion_pack/arg_utils.py | 2 +- .../conversion_pack/conversion_validation.py | 6 +++ .../goto_statement_converter.py | 16 +++++++ .../label_statement_converter.py | 18 ++++++++ .../unary_operation_converter.py | 5 +++ .../default_conversion_validation.py | 2 +- 14 files changed, 154 insertions(+), 13 deletions(-) create mode 100755 src/clang_convert/code_object/goto_statement.py create mode 100755 src/clang_convert/code_object/label_statement.py create mode 100755 src/clang_convert/code_object_converter/goto_statement_converter.py create mode 100755 src/clang_convert/code_object_converter/label_statement_converter.py diff --git a/src/clang_convert/accessor_working_input_files b/src/clang_convert/accessor_working_input_files index d26f4f961..c16808f8a 100644 --- a/src/clang_convert/accessor_working_input_files +++ b/src/clang_convert/accessor_working_input_files @@ -16,8 +16,8 @@ grib_accessor_class_long.cc grib_accessor_class_proj_string.cc grib_accessor_class_blob.cc #grib_accessor_class_bufr_data_array.cc -#grib_accessor_class_bufr_data_element.cc -#grib_accessor_class_bufr_elements_table.cc +grib_accessor_class_bufr_data_element.cc +grib_accessor_class_bufr_elements_table.cc #grib_accessor_class_bufr_extract_area_subsets.cc #grib_accessor_class_bufr_extract_datetime_subsets.cc #grib_accessor_class_bufr_extract_subsets.cc diff --git a/src/clang_convert/ast_object/ast_parser.py b/src/clang_convert/ast_object/ast_parser.py index ca5785c23..b579068bf 100755 --- a/src/clang_convert/ast_object/ast_parser.py +++ b/src/clang_convert/ast_object/ast_parser.py @@ -14,10 +14,12 @@ import code_object.conditional_operation as conditional_operation import code_object.declaration_specifier as declaration_specifier import code_object.for_statement as for_statement import code_object.function_call as function_call +import code_object.goto_statement as goto_statement import code_object.if_statement as if_statement import code_object.init_list as init_list import code_object.macro_definition as macro_definition import code_object.macro_instantation as macro_instantation +import code_object.label_statement as label_statement import code_object.literal as literal import code_object.paren_expression as paren_expression import code_object.return_statement as return_statement @@ -271,6 +273,30 @@ class AstParser: return stmt_lines + def parse_GOTO_STMT(self, node): + children = list(node.get_children()) + child_count = len(children) + assert child_count == 1, f"Expected one child for goto statement, not [{child_count}]" + + label = self.parse_ast_node(children[0]) + + return goto_statement.GotoStatement(label) + + def parse_LABEL_STMT(self, node): + children = list(node.get_children()) + child_count = len(children) + assert child_count == 1, f"Expected one child for label statement, not [{child_count}]" + + label = literal.Literal(node.spelling) + statement = self.parse_ast_node(children[0]) + + label_stmt = label_statement.LabelStatement(label, statement) + debug.line("parse_LABEL_STMT", f"label_stmt=[{debug.as_debug_string(label_stmt)}]") + #ast_utils.dump_node(node) + #assert False + + return label_stmt + def parse_RETURN_STMT(self, node): children = list(node.get_children()) child_count = len(children) @@ -354,6 +380,9 @@ class AstParser: def parse_BREAK_STMT(self, node): return literal.Literal("break;") + def parse_CONTINUE_STMT(self, node): + return literal.Literal("continue;") + def parse_FOR_STMT(self, node): init_statement = condition = iteration_expression = statement = None @@ -437,12 +466,13 @@ class AstParser: clang.cindex.CursorKind.CASE_STMT: parse_CASE_STMT, clang.cindex.CursorKind.DEFAULT_STMT: parse_CASE_STMT, clang.cindex.CursorKind.IF_STMT: parse_IF_STMT, + clang.cindex.CursorKind.LABEL_STMT: parse_LABEL_STMT, clang.cindex.CursorKind.SWITCH_STMT: parse_SWITCH_STMT, clang.cindex.CursorKind.WHILE_STMT: parse_WHILE_STMT, clang.cindex.CursorKind.DO_STMT: parse_node_not_implemented, clang.cindex.CursorKind.FOR_STMT: parse_FOR_STMT, - clang.cindex.CursorKind.GOTO_STMT: parse_node_not_implemented, - clang.cindex.CursorKind.CONTINUE_STMT: parse_node_not_implemented, + clang.cindex.CursorKind.GOTO_STMT: parse_GOTO_STMT, + clang.cindex.CursorKind.CONTINUE_STMT: parse_CONTINUE_STMT, clang.cindex.CursorKind.BREAK_STMT: parse_BREAK_STMT, clang.cindex.CursorKind.RETURN_STMT: parse_RETURN_STMT, clang.cindex.CursorKind.NULL_STMT: parse_NULL_STMT, @@ -565,9 +595,11 @@ class AstParser: func_name = self.parse_ast_node(children[0]) cargs = [] for entry in children [1:]: - if entry.kind == clang.cindex.CursorKind.DECL_REF_EXPR: + carg = self.parse_ast_node(entry) + cargs.append(carg) + '''if entry.kind == clang.cindex.CursorKind.DECL_REF_EXPR: carg = arg.Arg(entry.type.spelling, entry.spelling) - cargs.append(carg) + cargs.append(carg)''' func_call = function_call.FunctionCall(func_name.as_string(), cargs) debug.line("parse_UNEXPOSED_EXPR", f"Extracted func_call=[{debug.as_debug_string(func_call)}]") return func_call @@ -882,11 +914,15 @@ class AstParser: ast_utils.dump_node(node) return literal.Literal("::".join([t.spelling for t in node.get_tokens()])) + def parse_LABEL_REF(self, node): + return literal.Literal(node.spelling) + parse_REF_funcs = { clang.cindex.CursorKind.TYPE_REF: parse_TYPE_REF, clang.cindex.CursorKind.TEMPLATE_REF: parse_node_not_implemented, clang.cindex.CursorKind.MEMBER_REF: parse_node_not_implemented, clang.cindex.CursorKind.NAMESPACE_REF: parse_NAMESPACE_REF, + clang.cindex.CursorKind.LABEL_REF: parse_LABEL_REF, } def parse_REF_node(self, node): diff --git a/src/clang_convert/code_object/case_statement.py b/src/clang_convert/code_object/case_statement.py index 963fb5b91..a086d4ad7 100755 --- a/src/clang_convert/code_object/case_statement.py +++ b/src/clang_convert/code_object/case_statement.py @@ -14,8 +14,6 @@ class CaseStatement(code_interface.CodeInterface): self._statement = statement assert isinstance(self._statement, code_interface.CodeInterface), f"Statement must be a CodeInterface class" - self._else = None - @property def constant_expression(self): return self._constant_expression diff --git a/src/clang_convert/code_object/function_call.py b/src/clang_convert/code_object/function_call.py index cb63d3b16..9fdd4fb6a 100755 --- a/src/clang_convert/code_object/function_call.py +++ b/src/clang_convert/code_object/function_call.py @@ -33,5 +33,7 @@ class FunctionCall(code_interface.CodeInterface): def as_lines(self): - return [f"{self._name}({', '.join([arg_utils.extract_function_call_name(a) for a in self._args])});"] + func_call_string = f"{self._name}({', '.join([arg_utils.extract_function_call_name(a) for a in self._args])});" + debug.line("as_lines", f"func_call_string=[{func_call_string}]") + return [func_call_string] #return [f"{self._name}({', '.join([strip_semicolon(a.as_string()) for a in self._args])});"] diff --git a/src/clang_convert/code_object/goto_statement.py b/src/clang_convert/code_object/goto_statement.py new file mode 100755 index 000000000..df10dbcea --- /dev/null +++ b/src/clang_convert/code_object/goto_statement.py @@ -0,0 +1,21 @@ +import utils.debug as debug +import code_object.code_interface as code_interface +import code_object.arg as arg + +# Represent a goto statement of the form goto LABEL; +# +class GotoStatement(code_interface.CodeInterface): + def __init__(self, label) -> None: + self._label = label + + assert isinstance(self._label, code_interface.CodeInterface), f"Label must be a CodeInterface class (or a string)" + + @property + def label(self): + return self._label + + def as_lines(self): + lines = [f"goto {self._label.as_string()};"] + + return lines + \ No newline at end of file diff --git a/src/clang_convert/code_object/label_statement.py b/src/clang_convert/code_object/label_statement.py new file mode 100755 index 000000000..b37c6ac79 --- /dev/null +++ b/src/clang_convert/code_object/label_statement.py @@ -0,0 +1,33 @@ +import utils.debug as debug +import code_object.code_interface as code_interface + +# Represents a label statement in the form: label: statement +# +# For example: +# the_end: +# GRIB_MUTEX_UNLOCK(&mutex1); +# +class LabelStatement(code_interface.CodeInterface): + def __init__(self, label, statement) -> None: + self._label = label + assert isinstance(self._label, code_interface.CodeInterface), f"Label must be a CodeInterface class" + + self._statement = statement + assert isinstance(self._statement, code_interface.CodeInterface), f"Statement must be a CodeInterface class" + + @property + def label(self): + return self._label + + @property + def statement(self): + return self._statement + + def as_lines(self): + label_lines = [f"{self._label.as_string()}:"] + + statement_lines = [] + statement_lines.extend(self._statement.as_lines()) + + return label_lines + statement_lines + \ No newline at end of file diff --git a/src/clang_convert/code_object_converter/case_statement_converter.py b/src/clang_convert/code_object_converter/case_statement_converter.py index c0f3e4056..e789e9d3d 100755 --- a/src/clang_convert/code_object_converter/case_statement_converter.py +++ b/src/clang_convert/code_object_converter/case_statement_converter.py @@ -13,6 +13,6 @@ class CaseStatementConverter(code_interface_converter.CodeInterfaceConverter): cpp_constant_expression = conversion_funcs.convert_ccode_object(self._ccode_object.constant_expression, conversion_pack) cpp_statement = conversion_funcs.convert_ccode_object(self._ccode_object.statement, conversion_pack) - cpp_while = case_statement.CaseStatement(cpp_constant_expression, cpp_statement) + cpp_case = case_statement.CaseStatement(cpp_constant_expression, cpp_statement) - return conversion_pack.conversion_validation.validate_case_statement(self._ccode_object, cpp_while) + return conversion_pack.conversion_validation.validate_case_statement(self._ccode_object, cpp_case) diff --git a/src/clang_convert/code_object_converter/conversion_funcs.py b/src/clang_convert/code_object_converter/conversion_funcs.py index 90abf5e8e..feacffcd2 100755 --- a/src/clang_convert/code_object_converter/conversion_funcs.py +++ b/src/clang_convert/code_object_converter/conversion_funcs.py @@ -18,8 +18,10 @@ import code_object.funcsig as funcsig import code_object.function as function import code_object.function_call as function_call import code_object.global_function as global_function +import code_object.goto_statement as goto_statement import code_object.if_statement as if_statement import code_object.init_list as init_list +import code_object.label_statement as label_statement import code_object.literal as literal import code_object.macro_definition as macro_definition import code_object.macro_instantation as macro_instantation @@ -58,8 +60,10 @@ import code_object_converter.funcsig_pointer_converter as funcsig_pointer_conver import code_object_converter.function_call_converter as function_call_converter import code_object_converter.function_converter as function_converter import code_object_converter.global_function_converter as global_function_converter +import code_object_converter.goto_statement_converter as goto_statement_converter import code_object_converter.if_statement_converter as if_statement_converter import code_object_converter.init_list_converter as init_list_converter +import code_object_converter.label_statement_converter as label_statement_converter import code_object_converter.literal_converter as literal_converter import code_object_converter.macro_definition_converter as macro_definition_converter import code_object_converter.macro_instantiation_converter as macro_instantiation_converter @@ -104,8 +108,10 @@ CodeInterfaceConverterClasses = { function_call.FunctionCall : function_call_converter.FunctionCallConverter, function.Function : function_converter.FunctionConverter, global_function.GlobalFunction : global_function_converter.GlobalFunctionConverter, + goto_statement.GotoStatement : goto_statement_converter.GotoStatementConverter, if_statement.IfStatement : if_statement_converter.IfStatementConverter, init_list.InitList : init_list_converter.InitListConverter, + label_statement.LabelStatement : label_statement_converter.LabelStatementConverter, literal.Literal : literal_converter.LiteralConverter, member_function.MemberFunction : member_function_converter.MemberFunctionConverter, macro_definition.MacroDefinition : macro_definition_converter.MacroDefinitionConverter, diff --git a/src/clang_convert/code_object_converter/conversion_pack/arg_utils.py b/src/clang_convert/code_object_converter/conversion_pack/arg_utils.py index ee401d1d6..4e0d18246 100755 --- a/src/clang_convert/code_object_converter/conversion_pack/arg_utils.py +++ b/src/clang_convert/code_object_converter/conversion_pack/arg_utils.py @@ -111,6 +111,6 @@ def extract_function_call_name(cpp_obj): 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)}]") + debug.line("extract_function_call_name", f"Converted cpp_obj: [{debug.as_debug_string(cpp_obj)}] -> [{cppname}] cpp_ob type=[{type(cpp_obj)}]") return cppname diff --git a/src/clang_convert/code_object_converter/conversion_pack/conversion_validation.py b/src/clang_convert/code_object_converter/conversion_pack/conversion_validation.py index d62f463de..30c0bb3e0 100755 --- a/src/clang_convert/code_object_converter/conversion_pack/conversion_validation.py +++ b/src/clang_convert/code_object_converter/conversion_pack/conversion_validation.py @@ -75,12 +75,18 @@ class ConversionValidation: def validate_global_function(self, cglobal_function, cppglobal_function): return cppglobal_function + def validate_goto_statement(self, cgoto_statement, cppgoto_statement): + return cppgoto_statement + def validate_if_statement(self, cif_statement, cppif_statement): return cppif_statement def validate_init_list(self, cinit_list, cppinit_list): return cppinit_list + def validate_label_statement(self, clabel, cpplabel): + return cpplabel + def validate_literal(self, cliteral, cppliteral): return cppliteral diff --git a/src/clang_convert/code_object_converter/goto_statement_converter.py b/src/clang_convert/code_object_converter/goto_statement_converter.py new file mode 100755 index 000000000..49ac69b73 --- /dev/null +++ b/src/clang_convert/code_object_converter/goto_statement_converter.py @@ -0,0 +1,16 @@ + +import utils.debug as debug +import code_object.goto_statement as goto_statement +import code_object_converter.code_interface_converter as code_interface_converter +import code_object_converter.conversion_funcs as conversion_funcs + +class GotoStatementConverter(code_interface_converter.CodeInterfaceConverter): + def __init__(self, ccode_object) -> None: + super().__init__(ccode_object) + assert isinstance(ccode_object, goto_statement.GotoStatement), f"Expected GotoStatement, got type=[{type(ccode_object)}]" + + def create_cpp_code_object(self, conversion_pack): + cpp_label = conversion_funcs.convert_ccode_object(self._ccode_object.label, conversion_pack) + + cppgoto_statement = goto_statement.GotoStatement(cpp_label) + return conversion_pack.conversion_validation.validate_goto_statement(self._ccode_object, cppgoto_statement) diff --git a/src/clang_convert/code_object_converter/label_statement_converter.py b/src/clang_convert/code_object_converter/label_statement_converter.py new file mode 100755 index 000000000..ecb584819 --- /dev/null +++ b/src/clang_convert/code_object_converter/label_statement_converter.py @@ -0,0 +1,18 @@ + +import utils.debug as debug +import code_object.label_statement as label_statement +import code_object_converter.code_interface_converter as code_interface_converter +import code_object_converter.conversion_funcs as conversion_funcs + +class LabelStatementConverter(code_interface_converter.CodeInterfaceConverter): + def __init__(self, ccode_object) -> None: + super().__init__(ccode_object) + assert isinstance(ccode_object, label_statement.LabelStatement), f"Expected LabelStatement, got type=[{type(ccode_object)}]" + + def create_cpp_code_object(self, conversion_pack): + cpp_label = conversion_funcs.convert_ccode_object(self._ccode_object.label, conversion_pack) + cpp_statement = conversion_funcs.convert_ccode_object(self._ccode_object.statement, conversion_pack) + + cpp_label_stmt = label_statement.LabelStatement(cpp_label, cpp_statement) + + return conversion_pack.conversion_validation.validate_label_statement(self._ccode_object, cpp_label_stmt) diff --git a/src/clang_convert/code_object_converter/unary_operation_converter.py b/src/clang_convert/code_object_converter/unary_operation_converter.py index ce1dc19da..e98822121 100755 --- a/src/clang_convert/code_object_converter/unary_operation_converter.py +++ b/src/clang_convert/code_object_converter/unary_operation_converter.py @@ -4,6 +4,7 @@ import code_object.unary_operation as unary_operation import code_object_converter.code_interface_converter as code_interface_converter import code_object_converter.conversion_funcs as conversion_funcs import code_object.struct_member_access as struct_member_access +from code_object.code_interface import NONE_VALUE class UnaryOperationConverter(code_interface_converter.CodeInterfaceConverter): def __init__(self, ccode_object) -> None: @@ -15,5 +16,9 @@ class UnaryOperationConverter(code_interface_converter.CodeInterfaceConverter): cpp_operand = conversion_funcs.convert_ccode_object(self._ccode_object.operand, conversion_pack) cpp_op_position = self._ccode_object.op_position + if cpp_operand == NONE_VALUE: + debug.line("create_cpp_code_object", f"cpp_operand is NONE_VALUE for self._ccode_object=[{debug.as_debug_string(self._ccode_object)}] - returning NONE_VALUE") + return NONE_VALUE + cpp_unary_operation = unary_operation.UnaryOperation(cpp_unary_op, cpp_operand, cpp_op_position) return conversion_pack.conversion_validation.validate_unary_operation(self._ccode_object, cpp_unary_operation) diff --git a/src/clang_convert/default/default_conversion_pack/default_conversion_validation.py b/src/clang_convert/default/default_conversion_pack/default_conversion_validation.py index 088320978..84c7b6515 100755 --- a/src/clang_convert/default/default_conversion_pack/default_conversion_validation.py +++ b/src/clang_convert/default/default_conversion_pack/default_conversion_validation.py @@ -116,7 +116,7 @@ class DefaultConversionValidation(conversion_validation.ConversionValidation): # C++ variable is a container, so we'll strip the * debug.line("validate_unary_operation", f"Stripping [*] from cppunary_operation=[{debug.as_debug_string(cppunary_operation)}]") return cppunary_operation.operand - elif cpparg.decl_spec.pointer == "&": + elif cpparg.decl_spec.pointer == "&" and cppunary_operation.unary_op.is_member_access(): debug.line("validate_unary_operation", f"Stripping [*] from ref type: current cppunary_operation=[{debug.as_debug_string(cppunary_operation)}]") return cppunary_operation.operand