def _construct_ifndef_expression(identifier): return c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CFunctionCall('defined', [c_ast.CVariable(identifier)]), ], )
def test_parse_with_empty_ifndef_block_and_endif_with_comment(self): source = """ #ifndef _SOMETHING_H #endif /* _SOMETHING_H */ """ actual = self.parser.parse(source) expected = pre_ast.File( pre_ast.CompositeBlock([ pre_ast.If([ pre_ast.ConditionalBlock( conditional_expression=c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CFunctionCall( function_name='defined', arguments=[ c_ast.CVariable('_SOMETHING_H') ]), ], ), content=pre_ast.CompositeBlock([]), ), ]), ]), ) self.assertEqual(actual, expected)
def test_evaluate_with_arithmetic_with_two_operators( self, ): expression = c_ast.CFunctionCall( function_name='*', arguments=[ c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CNumber(2), c_ast.CNumber(3), ], ), c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CNumber(5), c_ast.CNumber(7), ], ), ], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(60) self.assertEqual(actual, expected)
def test_evaluate_with_argument_passing_to_function_call( self, ): self.function_likes.update({ 'f': pre_ast.DefineFunctionLike( name='f', arguments=['x'], replacement=c_ast.CFunctionCall( function_name='g', arguments=[c_ast.CVariable('x')], ), string_replacement='g(x)', ), 'g': pre_ast.DefineFunctionLike( name='g', arguments=['y'], replacement=c_ast.CVariable('y'), string_replacement='y', ), }) expression = c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(42)], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(42) self.assertEqual(actual, expected)
def test_evaluate_function_variable_cycle( self, ): self.object_likes.update({ 'y': pre_ast.DefineObjectLike( name='y', replacement=c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CVariable('x')], ), string_replacement='f(x)', ), }) self.function_likes.update({ 'f': pre_ast.DefineFunctionLike( name='f', arguments=['x'], replacement=c_ast.CVariable('y'), string_replacement='y', ), }) expression = c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(42)], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CVariable('x')], ) self.assertEqual(actual, expected)
def test_evaluate_with_argument_to_resolve_named_as_unresolvable_function( self, ): self.function_likes.update({ 'f': pre_ast.DefineFunctionLike( name='f', arguments=['x'], replacement=c_ast.CFunctionCall( function_name='g', arguments=[c_ast.CVariable('h')], ), string_replacement='g(h)', ), 'g': pre_ast.DefineFunctionLike( name='g', arguments=['f'], replacement=c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(42)], ), string_replacement='f(42)', ), }) expression = c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(33)], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CFunctionCall( function_name='h', arguments=[c_ast.CNumber(42)], ) self.assertEqual(actual, expected)
def test_evaluate_against_mistnesting( self, ): self.function_likes.update({ 'twice': pre_ast.DefineFunctionLike( name='twice', arguments=['x'], replacement=c_ast.CFunctionCall( function_name='*', arguments=[ c_ast.CNumber(2), c_ast.CVariable('x'), ], ), string_replacement='(2*(x))', ), 'call_with_1': pre_ast.DefineFunctionLike( name='call_with_1', arguments=['x'], replacement=c_ast.CFunctionCall( function_name='x', arguments=[c_ast.CNumber(1)], ), string_replacement='(2*(x))', ), }) expression = c_ast.CFunctionCall( function_name='call_with_1', arguments=[c_ast.CVariable('twice')], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(2) self.assertEqual(actual, expected)
def test_evaluate_function_argument_cycle_with_composition( self, ): self.function_likes.update({ 'f': pre_ast.DefineFunctionLike( name='f', arguments=['x'], replacement=c_ast.CFunctionCall( function_name='f', arguments=[ c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CVariable('x')], ), ], ), string_replacement='f(f(x))', ), }) expression = c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(42)], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CFunctionCall( function_name='f', arguments=[ c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(42)], ) ] ) self.assertEqual(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.parseString(source, parseAll=True) 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.assertEqual(actual.asList(), [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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [expected])
def test_parse_with_empty_if_and_elif_blocks_and_expressions(self): source = """ #if CONFIG_SOMETHING == 32 #elif CONFIG_SOMETHING == 64 #endif """ actual = self.parser.parse(source) expected = pre_ast.File( pre_ast.CompositeBlock([ pre_ast.If(conditional_blocks=[ pre_ast.ConditionalBlock( conditional_expression=c_ast.CFunctionCall( function_name='==', arguments=[ c_ast.CVariable('CONFIG_SOMETHING'), c_ast.CNumber(32), ], ), content=pre_ast.CompositeBlock([]), ), pre_ast.ConditionalBlock( conditional_expression=c_ast.CFunctionCall( function_name='==', arguments=[ c_ast.CVariable('CONFIG_SOMETHING'), c_ast.CNumber(64), ], ), content=pre_ast.CompositeBlock([]), ), ], ), ]), ) self.assertEqual(actual, expected)
def test_parse_with_empty_ifndef_header_guard(self): source = """ #ifndef _SOMETHING_H #define _SOMETHING_H #endif """ actual = self.parser.parse(source) expected = pre_ast.File( pre_ast.CompositeBlock([ pre_ast.If([ pre_ast.ConditionalBlock( conditional_expression=c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CFunctionCall( function_name='defined', arguments=[ c_ast.CVariable('_SOMETHING_H') ]), ], ), content=pre_ast.CompositeBlock([ pre_ast.DefineObjectLike( name='_SOMETHING_H', replacement=None, string_replacement='', ), ]), ), ]), ]), ) self.assertEqual(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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [expected])
def test_evaluate_argument_overshadows_top_level_variable( self, ): self.object_likes.update({ 'x': pre_ast.DefineObjectLike( name='x', replacement=c_ast.CNumber(33), string_replacement='33', ), }) self.function_likes.update({ 'f': pre_ast.DefineFunctionLike( name='f', arguments=['x'], replacement=c_ast.CVariable('x'), string_replacement='x', ), }) expression = c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(42)], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(42) self.assertEqual(actual, expected)
def test_evaluate_function_call_with_identifier_defined_to_other_identifier( self, ): self.object_likes.update({ 'foo': pre_ast.DefineObjectLike( name='foo', replacement=c_ast.CVariable('bar'), string_replacement='bar', ), }) self.function_likes.update({ 'bar': pre_ast.DefineFunctionLike( name='bar', arguments=['x'], replacement=c_ast.CNumber(42), string_replacement='42', ), }) expression = c_ast.CFunctionCall( function_name='foo', arguments=[c_ast.CVariable('x')], ) actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(42) self.assertEqual(actual, expected)
def test_parse_with_empty_if_elif_and_else_blocks(self): source = """ #if CONFIG_SOMETHING #elif defined(CONFIG_SOMETHING_ELSE) #else #endif """ actual = self.parser.parse(source) expected = pre_ast.File( pre_ast.CompositeBlock([ pre_ast.If( conditional_blocks=[ pre_ast.ConditionalBlock( conditional_expression=c_ast.CVariable( name='CONFIG_SOMETHING', ), content=pre_ast.CompositeBlock([]), ), pre_ast.ConditionalBlock( conditional_expression=c_ast.CFunctionCall( function_name='defined', arguments=[ c_ast.CVariable('CONFIG_SOMETHING_ELSE'), ], ), content=pre_ast.CompositeBlock([]), ) ], else_content=pre_ast.CompositeBlock([]), ), ]), ) self.assertEqual(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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [expected])
def test_parse_sizeof(self): source = 'sizeof(struct s*)' actual = self.parser.parseString(source, parseAll=True) expected = c_ast.CFunctionCall( function_name='sizeof', arguments=[c_ast.CLiteral('struct s*')], ) self.assertEquals(actual.asList(), [expected])
def test_str_with_function_with_multicharacter_binary_operator(self): function_call = c_ast.CFunctionCall( function_name='<=', arguments=[33, 42], ) actual = str(function_call) expected = '33 <= 42' self.assertEqual(actual, expected)
def test_str_with_function_with_unary_operator(self): function_call = c_ast.CFunctionCall( function_name='+', arguments=[42], ) actual = str(function_call) expected = '+42' self.assertEqual(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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [expected])
def test_parse_multidimensional_array_expression(self): source = 't[x][y]' actual = self.parser.parseString(source, parseAll=True) 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.assertEqual(actual.asList(), [expected])
def test_str_with_function_with_ternary_operator(self): function_call = c_ast.CFunctionCall( function_name='?:', arguments=[24, 33, 42], ) actual = str(function_call) expected = '24 ? 33 : 42' self.assertEqual(actual, expected)
def test_parse_alignof_with_double_underscores_of_array(self): source = '__alignof__(unsigned int[42])' actual = self.parser.parseString(source, parseAll=True) expected = c_ast.CFunctionCall( function_name='__alignof__', arguments=[c_ast.CLiteral('unsigned int[42]')], ) self.assertEquals(actual.asList(), [expected])
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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [expected])
def test_parse_negative_integer_with_suffix(self): source = '-272l' expected = c_ast.CFunctionCall( function_name='-', arguments=[c_ast.CNumber(272)], ) actual = self.parser.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [expected])
def _construct_ternary_or_more(expression_tokens): arguments = expression_tokens[::2] operators = expression_tokens[1::2] function_name = ''.join(operators) return c_ast.CFunctionCall( function_name=function_name, arguments=arguments, )
def _create_cast_expression(target, expression): return c_ast.CFunctionCall( function_name='()', arguments=[ c_ast.CLiteral(target), expression, ], )