Fixed sizeof parse bug

This commit is contained in:
kevstone 2024-02-08 13:14:47 +00:00
parent 0d3692512e
commit 5999f9001b
3 changed files with 52 additions and 23 deletions

View File

@ -508,6 +508,7 @@ class AstParser:
return literal.Literal(tokens[0])
def parse_PAREN_EXPR(self, node):
children = list(node.get_children())
assert len(children) == 1, f"Expected exactly one child for paren expression"
expression = children[0]
@ -521,16 +522,20 @@ class AstParser:
keyword = node.spelling
if not keyword:
# Some unary expressions (e.g. sizeof) give an empty keyword, but we can extract it
# from the first token. In this case we have no child nodes and have to extract
# the expression from the tokens as well
# from the first token.
tokens = [token.spelling for token in node.get_tokens()]
keyword = tokens[0]
assert keyword == "sizeof", f"Unexpected keyword [{keyword}] - not able to parse this (yet!)"
children = list(node.get_children())
child_count = len(children)
if child_count == 0:
# No child nodes so extract expression from tokens...
expression_text = literal.Literal(" ".join([t for t in tokens[2:-1]]))
expression = paren_expression.ParenExpression(expression_text)
else:
children = list(node.get_children())
assert len(children) == 1, f"Expected exactly one child for unary expression, got [{len(children)}]"
assert child_count == 1, f"Expected a maximum of one child for unary expression, got [{child_count}]"
expression = self.parse_ast_node(children[0])
c_unary_expr = unary_expression.UnaryExpression(keyword, expression)
@ -677,6 +682,9 @@ class AstParser:
def parse_CSTYLE_CAST_EXPR(self, node):
debug.line("parse_CSTYLE_CAST_EXPR", f"Node dump:")
ast_utils.dump_node(node)
tokens = [token.spelling for token in node.get_tokens()]
assert tokens[0] == "("
@ -687,9 +695,10 @@ class AstParser:
children = list(node.get_children())
child_count = len(children)
assert child_count == 1, f"Expected exactly one child node for cast expression, but got [{child_count}]"
if child_count != 1:
debug.line("parse_CSTYLE_CAST_EXPR", f"Expected exactly one child node for cast expression, but got [{child_count}] - we'll process the last node as the expression")
cexpression = self.parse_ast_node(children[0])
cexpression = self.parse_ast_node(children[-1])
ccast_expression = cast_expression.CastExpression("C", ccast_value, cexpression)

View File

@ -9,31 +9,44 @@ 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
from code_object.unary_expression import UnaryExpression
from code_object.paren_expression import ParenExpression
# Try to extract a name value from the object, else return ""
def extract_name(cpp_obj):
debug.line("extract_name", f"[IN] cpp_obj=[{debug.as_debug_string(cpp_obj)}] type=[{type(cpp_obj)}]")
assert isinstance(cpp_obj, CodeInterface), f"Expected CodeInterfacce, got [{type(cpp_obj).__name__}]"
cppname = ""
if isinstance(cpp_obj, Literal):
return cpp_obj.value
cppname = cpp_obj.value
elif isinstance(cpp_obj, Arg):
return cpp_obj.name
cppname = cpp_obj.name
elif isinstance(cpp_obj, StructArg):
return cpp_obj.name
cppname = cpp_obj.name
elif isinstance(cpp_obj, VariableDeclaration):
return cpp_obj.variable
cppname = cpp_obj.variable
elif isinstance(cpp_obj, ArrayAccess):
return cpp_obj.name
cppname = cpp_obj.name
elif isinstance(cpp_obj, StructMemberAccess):
return cpp_obj.name
cppname = cpp_obj.name
elif isinstance(cpp_obj, ValueDeclarationReference):
return cpp_obj.value
cppname = cpp_obj.value
elif isinstance(cpp_obj, UnaryOperation):
# Operand will a CodeInterface, so we need to recurse!
return extract_name(cpp_obj.operand)
cppname = extract_name(cpp_obj.operand)
elif isinstance(cpp_obj, UnaryExpression):
# expression will a CodeInterface, so we need to recurse!
cppname = extract_name(cpp_obj.expression)
elif isinstance(cpp_obj, ParenExpression):
# expression will a paren_expression, so we need to recurse!
cppname = extract_name(cpp_obj.expression)
return ""
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,
# otherwise None
@ -42,9 +55,11 @@ def to_cpparg(cpp_obj, conversion_data):
assert isinstance(cpp_obj, CodeInterface), f"Expected CodeInterfacce, got [{type(cpp_obj).__name__}]"
cppname = extract_name(cpp_obj)
if cppname:
cpparg = conversion_data.cpparg_for_cppname(cppname)
name = extract_name(cpp_obj)
if name:
cpparg = conversion_data.cpparg_for_cppname(name)
if not cpparg:
cpparg = conversion_data.cpparg_for_cname(name)
assert cpparg is None or isinstance(cpparg, Arg), f"cpparg should be Arg, not [{type(cpparg).__name__}]"

View File

@ -78,10 +78,10 @@ class DefaultConversionValidation(conversion_validation.ConversionValidation):
if cppunary_expression.keyword == "sizeof":
assert isinstance(cppunary_expression.expression, paren_expression.ParenExpression)
cpparg = arg_utils.to_cpparg(cppunary_expression.expression.expression, self._conversion_data)
cpparg = arg_utils.to_cpparg(cppunary_expression.expression, self._conversion_data)
if cpparg and self._conversion_data.is_container_type(cpparg.decl_spec.type):
cpp_size_call = literal.Literal(f"{cpparg.name}.size()")
debug.line("validate_unary_operation", f"Updating size evaluation: [{debug.as_debug_string(cppunary_expression)}]->[{debug.as_debug_string(cpp_size_call)}]")
debug.line("validate_unary_expression", f"Updating size evaluation: [{debug.as_debug_string(cppunary_expression)}]->[{debug.as_debug_string(cpp_size_call)}]")
return cpp_size_call
return cppunary_expression
@ -94,9 +94,14 @@ class DefaultConversionValidation(conversion_validation.ConversionValidation):
if cpparg:
if self._conversion_data.is_container_type(cpparg.decl_spec.type):
# 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
if cppunary_operation.unary_op.value == "!":
cpp_empty_call = literal.Literal(f"{cpparg.name}.empty()")
debug.line("validate_unary_operation", f"Updating empty evaluation: [{debug.as_debug_string(cppunary_operation)}]->[{debug.as_debug_string(cpp_empty_call)}]")
return cpp_empty_call
else:
# 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 == "&":
debug.line("validate_unary_operation", f"Stripping [*] from ref type: current cppunary_operation=[{debug.as_debug_string(cppunary_operation)}]")
return cppunary_operation.operand