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_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_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_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_object( self, ): self.object_likes.update({ 'x': pre_ast.DefineObjectLike( name='x', replacement=c_ast.CFunctionCall( function_name='f', arguments=[c_ast.CNumber(42)], ), string_replacement='f(42)', ), }) self.function_likes.update({ 'f': pre_ast.DefineFunctionLike( name='f', arguments=['x'], replacement=c_ast.CVariable('x'), string_replacement='x', ), }) expression = c_ast.CVariable('x') actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(42) self.assertEqual(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.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [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_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_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_logical_or_and_negation(self): source = 'someFunction(a) || !defined(b) || c < 2' expected = c_ast.CFunctionCall( function_name='||', arguments=[ c_ast.CFunctionCall( function_name='||', arguments=[ c_ast.CFunctionCall( function_name='someFunction', arguments=[c_ast.CVariable('a')], ), c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CFunctionCall( function_name='defined', arguments=[c_ast.CVariable('b')], ) ], ), ], ), c_ast.CFunctionCall( function_name='<', arguments=[ c_ast.CVariable('c'), c_ast.CNumber(2), ], ), ], ) actual = self.parser.parseString(source, parseAll=True) self.assertEqual(actual.asList(), [expected])
def test_evaluate_nested_call_access_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.CFunctionCall( function_name='g', arguments=[], ), string_replacement='g()', ), 'g': pre_ast.DefineFunctionLike( name='g', arguments=[], replacement=c_ast.CVariable('x'), string_replacement='x', ), }) expression = c_ast.CVariable('x') actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(33) self.assertEqual(actual, expected)
def test_parse_array_expression(self): source = 't[x]' actual = self.parser.parseString(source, parseAll=True) expected = c_ast.CFunctionCall( function_name='[]', arguments=[ c_ast.CVariable('t'), c_ast.CVariable('x'), ], ) self.assertEqual(actual.asList(), [expected])
def test_parse_ternary_conditional(self): source = 'a ? b : c' actual = self.parser.parseString(source, parseAll=True) expected = c_ast.CFunctionCall( function_name='?:', arguments=[ c_ast.CVariable('a'), c_ast.CVariable('b'), c_ast.CVariable('c'), ], ) self.assertEqual(actual.asList(), [expected])
def test_evaluate_identifier_defined_to_undefined_identifier(self): self.object_likes.update({ 'foo': pre_ast.DefineObjectLike( name='foo', replacement=c_ast.CVariable('bar'), string_replacement='bar', ), }) expression = c_ast.CVariable('foo') actual = self.evaluator.evaluate(expression) expected = c_ast.CVariable('bar') self.assertEqual(actual, expected)
def test_parse_function_call_with_multiword_argument(self): source = 'f(union u)' expected = c_ast.CFunctionCall( function_name='f', arguments=[ pre_ast.CompositeBlock([ c_ast.CVariable('union'), c_ast.CVariable('u'), ]), ], ) 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_parse_define_object_with_two_expressions(self): source = '#define foo bar baz' actual = self.parser.parse(source) expected = pre_ast.File(content=pre_ast.CompositeBlock([ pre_ast.DefineObjectLike( name='foo', replacement=pre_ast.CompositeBlock([ c_ast.CVariable('bar'), c_ast.CVariable('baz'), ]), string_replacement=' bar baz', ), ]), ) self.assertEqual(actual, expected)
def test_evaluate_object_like_with_simple_recursion( self, ): self.object_likes.update({ 'x': pre_ast.DefineObjectLike( name='x', replacement=c_ast.CVariable('x'), string_replacement='x', ), }) expression = c_ast.CVariable('x') actual = self.evaluator.evaluate(expression) expected = c_ast.CVariable('x') self.assertEqual(actual, expected)
def test_parse_define_function_like_with_multiple_expressions(self): source = '#define foo() bar baz' actual = self.parser.parse(source) expected = pre_ast.File(content=pre_ast.CompositeBlock([ pre_ast.DefineFunctionLike( name='foo', arguments=[], replacement=pre_ast.CompositeBlock([ c_ast.CVariable('bar'), c_ast.CVariable('baz'), ]), string_replacement=' bar baz', ), ])) self.assertEqual(actual, expected)
def test_parse_pragma_with_argument_with_arguments(self): source = '#pragma foo(bar, baz)' actual = self.parser.parse(source) expected = pre_ast.File(content=pre_ast.CompositeBlock([ pre_ast.Pragma([ pre_ast.PragmaArgument( name='foo', arguments=[ c_ast.CVariable('bar'), c_ast.CVariable('baz'), ], ), ]), ]), ) self.assertEqual(actual, expected)
def test_expand_with_function_call(self): source = 'foo(bar, 42)' self.expression_evaluator.evaluate.return_value = c_ast.CVariable( 'baz') actual = self.macro_expander.expand(source) self.expression_evaluator.evaluate.assert_called_with( c_ast.CFunctionCall( function_name='foo', arguments=[ c_ast.CVariable('bar'), c_ast.CNumber(42), ], ), ) expected = 'baz' self.assertEqual(actual, expected)
def test_parse_parentheses_and_binary_plus(self): source = '(a) + b' actual = self.parser.parseString(source, parseAll=True) expected = c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('a'), closer=')', ), c_ast.CVariable('b'), ], ) self.assertEqual(actual.asList(), [expected])
def test_parse_with_top_level_if_elif_and_else_blocks(self): source = '\n'.join(( 'int a;', '#if CONFIG_SOMETHING', 'struct s {', ' int x;', '} y;', '#elif defined(CONFIG_SOMETHING_ELSE)', 'struct s t, u;', '#else', 'int z;', '#endif', 'int b;', )) actual = self.parser.parse(source) expected = pre_ast.File(content=pre_ast.CompositeBlock([ pre_ast.TextBlock('int a;'), pre_ast.If( conditional_blocks=[ pre_ast.ConditionalBlock( conditional_expression=c_ast.CVariable( name='CONFIG_SOMETHING', ), content=pre_ast.CompositeBlock([ pre_ast.TextBlock( '\n'.join(( 'struct s {', ' int x;', '} y;', )), ), ]), ), pre_ast.ConditionalBlock( conditional_expression=c_ast.CFunctionCall( function_name='defined', arguments=[ c_ast.CVariable('CONFIG_SOMETHING_ELSE'), ], ), content=pre_ast.CompositeBlock( [pre_ast.TextBlock('struct s t, u;')]), ), ], else_content=pre_ast.CompositeBlock( [pre_ast.TextBlock('int z;')]), ), pre_ast.TextBlock('int b;'), ]), ) self.assertEqual(actual, expected)
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_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_keep_parentheses_in_nested_expression(self): evaluator = ( macro_expression_evaluator_visitor.MacroExpressionEvaluatorVisitor( object_likes=self.object_likes, function_likes=self.function_likes, functions=self.functions, lazy_functions=self.lazy_functions, keep_parentheses=True, ) ) self.object_likes.update({ 'foo': pre_ast.DefineObjectLike( name='foo', replacement=c_ast.CNumber(42), string_replacement='42', ), 'bar': pre_ast.DefineObjectLike( name='bar', replacement=c_ast.CNumber(33), string_replacement='33', ), }) expression = c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('foo'), closer=')', ) actual = evaluator.evaluate(expression) expected = c_ast.CNestedExpression( opener='(', content=c_ast.CNumber(42), closer=')', ) 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_transform_result_to_integer_as_hex( self, ): expression = c_ast.CVariable('0x33') actual = self.evaluator.evaluate(expression) expected = c_ast.CNumber(51) self.assertEqual(actual, expected)
def test_visit_nested_expression(self): expression = c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('a'), closer=')', ) actual = self.expression_evaluator.evaluate(expression) self.assertEqual(actual, 'b')