def test_parse_variable_in_parentheses2(self): # Unfortunately our parser is not that great since it misidentifies the # below with & is substituted for +. It accidentally considers it the # dereference operator. I dont think there is a way to properly parse # without context (i.e. cant make a context free grammer) because you # need to resolve the RHS to the & operator to know if it makes sense. source = '(((x) + 1) | 2)' actual = self.parser.parse(source) expected = c_ast.CNestedExpression( opener='(', closer=')', content=c_ast.CFunctionCall( function_name="|", arguments=[ c_ast.CNestedExpression( opener='(', closer=')', content=c_ast.CFunctionCall( function_name="+", arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('x'), closer=')', ), c_ast.CNumber(1), ])), c_ast.CNumber(2) ])) self.assertASTEqual(actual, expected)
def test_multiplication_in_parentheses_and_binary_minus(self): # This is tricky because it's not a cast and an unary minus. To fully # distinguish those cases we would need to know what identifiers are # types and what identifiers are variables, e.g. # (x) - y # depends on the meaning of x. If x is a type then it can be a cast and # an unary minus, if x is a variable then it is a binary minus. source = '(a * b) - c' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='-', arguments=[ c_ast.CNestedExpression(opener='(', content=c_ast.CFunctionCall( function_name='*', arguments=[ c_ast.CVariable('a'), c_ast.CVariable('b'), ], ), closer=')'), c_ast.CVariable('c'), ], ) self.assertASTEqual(actual, expected)
def test_parse_unary_operator_on_expression_in_parentheses(self): source = '!(x > 0 || y == 0)' expected = c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall( function_name='||', arguments=[ c_ast.CFunctionCall( function_name='>', arguments=[ c_ast.CVariable('x'), c_ast.CNumber(0), ], ), c_ast.CFunctionCall( function_name='==', arguments=[ c_ast.CVariable('y'), c_ast.CNumber(0), ], ), ], ), closer=')', ), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_not_defined_function_like(self): source = '!defined(CONFIG_SOMETHING)' expected = c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CFunctionCall( function_name='defined', arguments=[c_ast.CVariable('CONFIG_SOMETHING')], ), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_addition_and_multiplication_precedence(self): source = 'a + b * c' expected = c_ast.CFunctionCall(function_name='+', arguments=[ c_ast.CVariable('a'), c_ast.CFunctionCall( function_name='*', arguments=[ c_ast.CVariable('b'), c_ast.CVariable('c'), ]) ]) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def _construct_unary(self, tok): expression_tokens = tok.first operator_name, argument = expression_tokens return c_ast.CFunctionCall( function_name=operator_name, arguments=[argument], )
def test_parse_function_call_with_one_argument(self): source = 'f(a)' expected = c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CVariable('a')], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_function_call_with_no_arguments(self): source = 'f()' expected = c_ast.CFunctionCall( function_name='f', arguments=[], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_negative_hex_integer_with_suffix(self): source = '-0xdcbaLL' expected = c_ast.CFunctionCall( function_name='-', arguments=[c_ast.CNumber(56506)], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_multidimensional_array_expression(self): source = 't[x][y]' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='[]', arguments=[ c_ast.CFunctionCall( function_name='[]', arguments=[ c_ast.CVariable('t'), c_ast.CVariable('x'), ], ), c_ast.CVariable('y'), ], ) self.assertASTEqual(actual, expected)
def test_parse_alignof_with_double_underscores_of_array(self): source = '__alignof__(unsigned int[42])' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='__alignof__', arguments=[c_ast.CLiteral('unsigned int[42]')], ) self.assertASTEqual(actual, expected)
def test_parse_sizeof(self): source = 'sizeof(struct s*)' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='sizeof', arguments=[c_ast.CLiteral('struct s*')], ) self.assertASTEqual(actual, expected)
def test_parse_alignof_with_double_underscores(self): source = '__alignof__(struct s*)' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='__alignof__', arguments=[c_ast.CLiteral('struct s*')], ) self.assertASTEqual(actual, expected)
def test_parse_same_precedence_operators_plus_and_plus(self): source = 'a + b + c' expected = c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CVariable('a'), c_ast.CVariable('b'), ], ), c_ast.CVariable('c'), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_negative_hex_integer(self): source = '-0xabcd' expected = c_ast.CFunctionCall( function_name='-', arguments=[c_ast.CNumber(43981)], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_binary_operator_with_function_calls(self): source = 'defined(CONFIG_SOMETHING) && defined(CONFIG_SOMETHING_ELSE)' expected = c_ast.CFunctionCall( function_name='&&', arguments=[ c_ast.CFunctionCall( function_name='defined', arguments=[c_ast.CVariable('CONFIG_SOMETHING')], ), c_ast.CFunctionCall( function_name='defined', arguments=[c_ast.CVariable('CONFIG_SOMETHING_ELSE')], ), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_unary_operator_with_variable(self): for unary_operator in self.unary_operators: source = unary_operator + 'CONFIG_SOMETHING' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name=unary_operator, arguments=[c_ast.CVariable('CONFIG_SOMETHING')], ) self.assertASTEqual(actual, expected)
def _construct_ternary_or_more(self, tok): expression_tokens = tok.first arguments = expression_tokens[::2] operators = expression_tokens[1::2] function_name = ''.join(operators) return c_ast.CFunctionCall( function_name=function_name, arguments=arguments, )
def test_parse_unary_operator_with_number(self): for unary_operator in self.unary_operators: source = unary_operator + '33' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name=unary_operator, arguments=[c_ast.CNumber(33)], ) self.assertASTEqual(actual, expected)
def test_parse_attribute(self): source = '__attribute__((x))' expected = c_ast.CFunctionCall( function_name='__attribute__', arguments=[ c_ast.CVariable('x'), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_comparison_and_shift_with_parentheses_on_right(self): source = 'x < (1 << 14)' expected = c_ast.CFunctionCall( function_name='<', arguments=[ c_ast.CVariable('x'), c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall(function_name='<<', arguments=[ c_ast.CNumber(1), c_ast.CNumber(14), ]), closer=')', ), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_parentheses_with_addition_and_multiplication(self): source = '(a + b) * c' expected = c_ast.CFunctionCall(function_name='*', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CVariable('a'), c_ast.CVariable('b'), ], ), closer=')', ), c_ast.CVariable('c'), ]) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_complex_parentheses_expression(self): source = '(((x) + (y)) & ~(y))' actual = self.parser.parse(source) expected = c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall( function_name='&', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('x'), closer=')', ), c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('y'), closer=')', ), ], ), closer=')', ), c_ast.CFunctionCall( function_name='~', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('y'), closer=')', ), ], ), ], ), closer=')', ) self.assertASTEqual(actual, expected)
def test_parse_function_call_with_two_arguments(self): source = 'f(a, 42)' expected = c_ast.CFunctionCall( function_name='f', arguments=[ c_ast.CVariable('a'), c_ast.CNumber(42), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def _construct_binary(self, tok): expression_tokens = tok.first result = expression_tokens[0] operators = expression_tokens[1::2] values = expression_tokens[2::2] for operator_name, value in zip(operators, values): result = c_ast.CFunctionCall( function_name=operator_name, arguments=[result, value], ) return result
def test_parse_binary_operator_with_variable_and_number(self): for binary_operator in self.binary_operators: source = '51' + binary_operator + 'CONFIG_SOMETHING' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name=binary_operator, arguments=[ c_ast.CNumber(51), c_ast.CVariable('CONFIG_SOMETHING'), ]) self.assertASTEqual(actual, expected)
def test_parse_ternary_conditional(self): source = 'a ? b : c' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='?:', arguments=[ c_ast.CVariable('a'), c_ast.CVariable('b'), c_ast.CVariable('c'), ], ) self.assertASTEqual(actual, expected)
def _create_base_or_array_expression(self, array_expression, indices): """Creates FunctionCalls for array calls of a form t[x][y]...[z].""" result = array_expression for index in indices: result = c_ast.CFunctionCall( function_name='[]', arguments=[ result, index, ], ) return result
def test_visit_function_call(self): function_call = c_ast.CFunctionCall( function_name='f1', arguments=[ c_ast.CNumber(24), c_ast.CLiteral('literal'), ], ) actual = self.expression_evaluator.evaluate(function_call) self.assertEqual(actual, 33) self.assertEqual(self.x, [24]) self.assertEqual(self.y, ['literal'])
def test_parse_sizeof_and_binary_plus_operators_and_additional_parentheses( self): source = """ ( sizeof(struct ymmh_struct) + sizeof(struct lwp_struct) + sizeof(struct mpx_struct) ) """ actual = self.parser.parse(source) expected = c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CFunctionCall( function_name='sizeof', arguments=[ c_ast.CLiteral('struct ymmh_struct') ], ), c_ast.CFunctionCall( function_name='sizeof', arguments=[ c_ast.CLiteral('struct lwp_struct') ], ), ], ), c_ast.CFunctionCall( function_name='sizeof', arguments=[c_ast.CLiteral('struct mpx_struct')], ), ], ), closer=')', ) self.assertASTEqual(actual, expected)