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_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.parse(source) 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_array_expression(self): source = 't[x]' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='[]', arguments=[ c_ast.CVariable('t'), c_ast.CVariable('x'), ], ) 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 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.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 test_parse_parentheses_and_binary_plus(self): source = '(a) + b' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name='+', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('a'), closer=')', ), c_ast.CVariable('b'), ], ) self.assertASTEqual(actual, expected)
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_visit_nested_expression(self): expression = c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('a'), closer=')', ) actual = self.expression_evaluator.evaluate(expression) self.assertEqual(actual, 1)
def test_parse_defined_function_like(self): source = 'defined(CONFIG_SOMETHING)' expected = c_ast.CFunctionCall( function_name='defined', arguments=[c_ast.CVariable('CONFIG_SOMETHING')], ) actual = self.parser.parse(source) 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_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_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_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 test_parse_variable_in_parentheses(self): source = '(x)' expected = c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('x'), 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_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_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_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_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 test_parse_binary_operators_with_parentheses_on_right(self): source = 'x < 4 || (y == 4 && z < 1)' expected = c_ast.CFunctionCall( function_name='||', arguments=[ c_ast.CFunctionCall( function_name='<', arguments=[ c_ast.CVariable('x'), c_ast.CNumber(4), ], ), c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall( function_name='&&', arguments=[ c_ast.CFunctionCall( function_name='==', arguments=[ c_ast.CVariable('y'), c_ast.CNumber(4), ], ), c_ast.CFunctionCall( function_name='<', arguments=[ c_ast.CVariable('z'), c_ast.CNumber(1), ], ), ], ), closer=')', ), ], ) 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_variable(self): source = 'CONFIG_SOMETHING' expected = c_ast.CVariable('CONFIG_SOMETHING') actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_visit_variable(self): variable = c_ast.CVariable('c') actual = self.expression_evaluator.evaluate(variable) self.assertEqual(actual, 2)