def test_to_expression_should_equal_self(self): expressions = [ Expression(Type.int(), 1), Expression(Type.decimal(), 1.1), Expression(Type.boolean(), False), Expression(Type.vector(), [1.1, 2.2, -1.1]), Expression(Type.list_of(Type.int()), [1, 2, 3, 4]), Expression(Type.list_of(Type.int()), []), Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0]), Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]]), Expression(Type.int(), 1, "a"), Expression(Type.decimal(), 1.1, "a"), Expression(Type.boolean(), False, "a"), Expression(Type.vector(), [1.1, 2.2, -1.1], "a"), Expression(Type.drone(), Drone("DRONE", DefaultDroneConfig()), "a"), Expression(Type.list_of(Type.int()), [1, 2, 3, 4], "a"), Expression(Type.list_of(Type.int()), [], "a"), Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0], "a"), Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]], "a") ] for expression in expressions: self.assertEqual(expression, expression.to_expression())
def test_eq(self): vector_elems1 = [ None, VectorElem("a", Expression(Type.vector(), [1.0, 2.0, 3.0], "a"), 0), VectorElem("b", Expression(Type.vector(), [1.0, 2.0, 3.0], "b"), 0), VectorElem("a", Expression(Type.vector(), [2.0, 2.0, 3.0], "a"), 0), VectorElem("a", Expression(Type.vector(), [1.0, 2.0, 3.0], "a"), 1), VectorElem("b[1]", Expression(Type.vector(), [1.0, 2.0, 3.0], "a"), 0) ] vector_elems2 = [ None, VectorElem("a", Expression(Type.vector(), [1.0, 2.0, 3.0], "a"), 0), VectorElem("b", Expression(Type.vector(), [1.0, 2.0, 3.0], "b"), 0), VectorElem("a", Expression(Type.vector(), [2.0, 2.0, 3.0], "a"), 0), VectorElem("a", Expression(Type.vector(), [1.0, 2.0, 3.0], "a"), 1), VectorElem("b[1]", Expression(Type.vector(), [1.0, 2.0, 3.0], "a"), 0) ] for i in range(len(vector_elems1)): for j in range(len(vector_elems2)): if i == j: self.assertEqual(vector_elems1[i], vector_elems2[j]) else: self.assertNotEqual(vector_elems1[i], vector_elems2[j])
def visitPlusMinus(self, ctx: xDroneParser.PlusMinusContext) -> Expression: expr1, expr2 = self.visit(ctx.expr(0)), self.visit(ctx.expr(1)) if self._is_int_or_decimal(expr1.type) and self._is_int_or_decimal( expr2.type): result_type, func = self._get_int_decimal_result_type( expr1.type, expr2.type) if ctx.PLUS(): result_value = func(expr1.value + expr2.value) else: # MINUS result_value = func(expr1.value - expr2.value) elif expr1.type == Type.vector() and expr2.type == Type.vector(): result_type = Type.vector() if ctx.PLUS(): result_value = [ e1 + e2 for e1, e2 in zip(expr1.value, expr2.value) ] else: # MINUS result_value = [ e1 - e2 for e1, e2 in zip(expr1.value, expr2.value) ] else: raise CompileError( "Expression {} and {} have wrong types to perform addition or subtraction" .format(expr1, expr2)) return Expression(result_type, result_value)
def visitMultiDivide(self, ctx: xDroneParser.MultiDivideContext) -> Expression: expr1, expr2 = self.visit(ctx.expr(0)), self.visit(ctx.expr(1)) if self._is_int_or_decimal(expr1.type) and self._is_int_or_decimal( expr2.type): result_type, func = self._get_int_decimal_result_type( expr1.type, expr2.type) if ctx.MULTI(): result_value = func(expr1.value * expr2.value) else: # DIV if expr2.value == 0: raise CompileError("Division by zero") result_value = func(expr1.value / expr2.value) elif self._is_int_or_decimal( expr1.type) and expr2.type == Type.vector(): result_type = Type.vector() if ctx.MULTI(): result_value = [expr1.value * e for e in expr2.value] else: # DIV raise CompileError( "Expression {} and {} have wrong types to perform multiplication or division" .format(expr1, expr2)) elif expr1.type == Type.vector() and self._is_int_or_decimal( expr2.type): result_type = Type.vector() if ctx.MULTI(): result_value = [e * expr2.value for e in expr1.value] else: # DIV result_value = [e / expr2.value for e in expr1.value] else: raise CompileError( "Expression {} and {} have wrong types to perform multiplication or division" .format(expr1, expr2)) return Expression(result_type, result_value)
def test_to_expression_should_return_correct_value(self): expression = Expression(Type.vector(), [1.0, 2.0, 3.0], "a") expected = Expression(Type.decimal(), 1.0) self.assertEqual(expected, VectorElem("a", expression, 0).to_expression()) expression = Expression(Type.vector(), [1.0, 2.0, 3.0], "b[1]") expected = Expression(Type.decimal(), 3.0) self.assertEqual(expected, VectorElem("b[1]", expression, 2).to_expression())
def test_str(self): self.assertEqual("Expression: { type: int, value: 1, ident: None }", str(Expression(Type.int(), 1))) self.assertEqual( "Expression: { type: decimal, value: 1.1, ident: None }", str(Expression(Type.decimal(), 1.1))) self.assertEqual( "Expression: { type: boolean, value: False, ident: None }", str(Expression(Type.boolean(), False))) self.assertEqual( "Expression: { type: vector, value: [1.1, 2.2, -1.1], ident: None }", str(Expression(Type.vector(), [1.1, 2.2, -1.1]))) self.assertEqual( "Expression: { type: list[int], value: [1, 2, 3, 4], ident: None }", str(Expression(Type.list_of(Type.int()), [1, 2, 3, 4]))) self.assertEqual( "Expression: { type: list[int], value: [], ident: None }", str(Expression(Type.list_of(Type.int()), []))) self.assertEqual( "Expression: { type: list[list[vector]], value: [[[1.1, 2.2, -1.1], [1, 2, -1]]], ident: None }", str( Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]]))) self.assertEqual("Expression: { type: int, value: 1, ident: a }", str(Expression(Type.int(), 1, "a"))) self.assertEqual("Expression: { type: decimal, value: 1.1, ident: a }", str(Expression(Type.decimal(), 1.1, "a"))) self.assertEqual( "Expression: { type: boolean, value: False, ident: a }", str(Expression(Type.boolean(), False, "a"))) self.assertEqual( "Expression: { type: vector, value: [1.1, 2.2, -1.1], ident: a }", str(Expression(Type.vector(), [1.1, 2.2, -1.1], "a"))) self.assertEqual( "Expression: { type: drone, value: Drone: { name: DRONE, config: DroneConfig: " "{ init_position: (0, 0, 0), speed_mps: 1, rotate_speed_dps: 90, takeoff_height_meters: 1 } " "}, ident: a }", str( Expression(Type.drone(), Drone("DRONE", DefaultDroneConfig()), "a"))) self.assertEqual( "Expression: { type: list[int], value: [1, 2, 3, 4], ident: a }", str(Expression(Type.list_of(Type.int()), [1, 2, 3, 4], "a"))) self.assertEqual( "Expression: { type: list[int], value: [], ident: a }", str(Expression(Type.list_of(Type.int()), [], "a"))) self.assertEqual( "Expression: { type: list[list[vector]], value: [[[1.1, 2.2, -1.1], [1, 2, -1]]], ident: a }", str( Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]], "a")))
def test_assign_list_elem_with_different_type_should_give_error(self): types = [ Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.list_of(Type.int())) ] for t1 in types: for t2 in types: if t1 == t2: continue with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ {} a; {} b; list[{}] c <- [a]; c[0] <- b; }} """.format(t1, t2, t1)) self.assertTrue( "Assigned value {} should have type {}, but is {}".format( Expression(t2, t2.default_value, ident="b"), t1.type_name, t2.type_name) in str(context.exception))
def test_list_elem_assign_with_wrong_index_should_give_error(self): types = [ Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int())) ] for type in types: with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ {} a; list[int] b; b[a] <- 1; }} """.format(type)) self.assertTrue( "Expression {} should have type int, but is {}".format( Expression(type, type.default_value, ident="a"), type.type_name) in str(context.exception))
def test_repeated_declare_and_assign_drone_constant_should_give_error( self): types = [ Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.list_of(Type.int())) ] for type in types: with self.assertRaises(CompileError) as context: generate_commands( """ main () {{ {} a; {} DRONE <- a; }} """.format(type.type_name, type.type_name), drone_config_map={"DRONE": DefaultDroneConfig()}) self.assertTrue( "Identifier DRONE already declared" in str(context.exception))
def test_declare_and_assign_with_different_type_should_give_error(self): types = [ Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.list_of(Type.int())) ] for t1 in types: for t2 in types: if t1 == t2: continue with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ {} a; {} b <- a; }} """.format(t1, t2)) self.assertTrue( "Identifier b has been declared as {}, but assigned as {}". format(t2.type_name, t1.type_name) in str( context.exception))
def test_list_insert_with_wrong_type_value_should_give_error(self): types = [ Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int())) ] for t1 in types: for t2 in types: if t1 == t2: continue with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ {} a; list[{}] b; b.insert(a); }} """.format(t1, t2)) self.assertTrue( "List {} has been declared as {}, but inserted with element type {}" .format(Expression(Type.list_of(t2), [], ident="b"), Type.list_of(t2), t1) in str(context.exception))
def visitVectorZ(self, ctx: xDroneParser.VectorZContext) -> VectorElem: expr = self.visit(ctx.expr()) if expr.type != Type.vector(): raise CompileError( "Expression {} should have type vector, but is {}".format( expr, expr.type)) return VectorElem(expr.ident, expr, 2)
def test_eq(self): expressions1 = [ None, Expression(Type.int(), 1), Expression(Type.decimal(), 1.1), Expression(Type.boolean(), False), Expression(Type.vector(), [1.1, 2.2, -1.1]), Expression(Type.list_of(Type.int()), [1, 2, 3, 4]), Expression(Type.list_of(Type.int()), []), Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0]), Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]]), Expression(Type.int(), 1, "a"), Expression(Type.decimal(), 1.1, "a"), Expression(Type.boolean(), False, "a"), Expression(Type.vector(), [1.1, 2.2, -1.1], "a"), Expression(Type.drone(), Drone("DRONE", DefaultDroneConfig()), "a"), Expression(Type.list_of(Type.int()), [1, 2, 3, 4], "a"), Expression(Type.list_of(Type.int()), [], "a"), Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0], "a"), Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]], "a") ] expressions2 = [ None, Expression(Type.int(), 1), Expression(Type.decimal(), 1.1), Expression(Type.boolean(), False), Expression(Type.vector(), [1.1, 2.2, -1.1]), Expression(Type.list_of(Type.int()), [1, 2, 3, 4]), Expression(Type.list_of(Type.int()), []), Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0]), Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]]), Expression(Type.int(), 1, "a"), Expression(Type.decimal(), 1.1, "a"), Expression(Type.boolean(), False, "a"), Expression(Type.vector(), [1.1, 2.2, -1.1], "a"), Expression(Type.drone(), Drone("DRONE", DefaultDroneConfig()), "a"), Expression(Type.list_of(Type.int()), [1, 2, 3, 4], "a"), Expression(Type.list_of(Type.int()), [], "a"), Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0], "a"), Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]], "a") ] for i in range(len(expressions1)): for j in range(len(expressions2)): if i == j: self.assertEqual(expressions1[i], expressions2[j]) else: self.assertNotEqual(expressions1[i], expressions2[j])
def test_str(self): self.assertEqual( "ListElem: { ident: a, " + "container: Expression: { type: vector, value: [1.0, 2.0, 3.0], ident: a }, " + "index: 0, expression: Expression: { type: decimal, value: 1.0, ident: None } }", str( VectorElem("a", Expression(Type.vector(), [1.0, 2.0, 3.0], "a"), 0)))
def test_declare_and_assign_vector_should_change_symbol_table(self): actual = SymbolTable() generate_commands(""" main () { vector a <- (1.0, 2.0, -3.0); } """, symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), [1, 2, -3], ident="a")) self.assertEqual(expected, actual)
def test_to_expression_should_return_correct_value(self): expressions = [ None, Expression(Type.int(), 1, "a"), Expression(Type.decimal(), 1.1, "a"), Expression(Type.boolean(), False, "a"), Expression(Type.vector(), [1.1, 2.2, -1.1], "a"), Expression(Type.drone(), Drone("DRONE", DefaultDroneConfig()), "a"), Expression(Type.list_of(Type.int()), [1, 2, 3, 4], "a"), Expression(Type.list_of(Type.int()), [], "a"), Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0], "a"), Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]], "a") ] for expression in expressions: self.assertEqual(expression, Identifier("a", expression).to_expression())
def test_to_expression_should_return_correct_value(self): expression = Expression(Type.list_of(Type.decimal()), [1.0, 2.0, 3.0, 4.0], "a") expected = Expression(Type.decimal(), 1.0, "a[0]") self.assertEqual(expected, ListElem("a", expression, 0).to_expression()) expression = Expression(Type.list_of(Type.list_of(Type.vector())), [[[1.1, 2.2, -1.1], [1, 2, -1]]], "a") expected = Expression(Type.list_of(Type.vector()), [[1.1, 2.2, -1.1], [1, 2, -1]], "a[0]") self.assertEqual(expected, ListElem("a", expression, 0).to_expression()) expression = Expression(Type.list_of(Type.boolean()), [True, False], "b[1]") expected = Expression(Type.boolean(), False, "b[1][1]") self.assertEqual(expected, ListElem("b[1]", expression, 1).to_expression())
def test_eq(self): types1 = [ None, Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int())), Type.list_of(Type.list_of(Type.decimal())) ] types2 = [ None, Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int())), Type.list_of(Type.list_of(Type.decimal())) ] for i in range(len(types1)): for j in range(len(types2)): if i == j: self.assertEqual(types1[i], types2[j]) else: self.assertNotEqual(types1[i], types2[j]) self.assertEqual(Type.empty_list(), Type.empty_list()) for type in types1: if isinstance(type, ListType): self.assertEqual(Type.empty_list(), type) self.assertEqual(type, Type.empty_list()) else: self.assertNotEqual(Type.empty_list(), type) self.assertNotEqual(type, Type.empty_list())
def test_return_in_main_should_give_error(self): types = [Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int()))] for type in types: with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ {} a; return a; }} """.format(type)) self.assertTrue("Cannot return in the Main function" in str(context.exception))
def test_vector_with_int_should_return_correct_value(self): actual = SymbolTable() generate_commands(""" main () { vector a <- (1, 2.0, -3); } """, symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), [1.0, 2.0, -3.0], ident="a")) self.assertEqual(expected, actual)
def test_assign_vector_elem_to_variable_should_update_symbol_table(self): actual = SymbolTable() generate_commands(""" main () { vector a; vector b; a.x <- 1; a.y <- 2; a.z <- -2; b.x <- 1.0; b.y <- 2.0; b.z <- -2.0; } """, symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), [1.0, 2.0, -2.0], ident="a")) expected.store("b", Expression(Type.vector(), [1.0, 2.0, -2.0], ident="b")) self.assertEqual(expected, actual)
def test_assign_ident_vector_should_update_symbol_table(self): actual = SymbolTable() generate_commands(""" main () { vector a; a <- (1.0, -1.0, +1.0); } """, symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), [1, -1, 1], ident="a")) self.assertEqual(expected, actual)
def test_container_not_list_should_give_error(self): none_list_exprs = [ Expression(Type.int(), 1, "a"), Expression(Type.decimal(), 1.0, "a"), Expression(Type.boolean(), True, "a"), Expression(Type.string(), "abc", "a"), Expression(Type.vector(), [1.0, 1.0, 1.0], "a"), Expression(Type.drone(), Drone("DRONE", DefaultDroneConfig()), "a") ] for none_list_expr in none_list_exprs: with self.assertRaises(AssertionError) as context: ListElem("a", none_list_expr, 0)
def visitVector(self, ctx: xDroneParser.VectorContext) -> Expression: expr1, expr2, expr3 = self.visit(ctx.expr(0)), self.visit( ctx.expr(1)), self.visit(ctx.expr(2)) for expr in [expr1, expr2, expr3]: if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr, expr.type)) return Expression( Type.vector(), [float(expr1.value), float(expr2.value), float(expr3.value)])
def test_define_functions_should_change_function_table(self): types = [Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int()))] for type in types: actual = FunctionTable() generate_commands(""" function func() return {} {{}} procedure proc() {{}} main () {{}} """.format(type), function_table=actual) expected = FunctionTable() expected.store("func", Function("func", [], type, [])) expected.store("proc", Function("proc", [], None, [])) self.assertEqual(expected, actual)
def test_define_functions_with_parameter_should_change_function_table(self): types = [Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int()))] for type1 in types: for type2 in types: actual = FunctionTable() generate_commands(""" function func({} a, {} b) return int {{}} procedure proc({} a, {} b) {{}} main () {{}} """.format(type1, type2, type1, type2), function_table=actual) expected = FunctionTable() expected.store("func", Function("func", [Parameter("a", type1), Parameter("b", type2)], Type.int(), [])) expected.store("proc", Function("proc", [Parameter("a", type1), Parameter("b", type2)], None, [])) self.assertEqual(expected, actual)
def test_return_not_exist_in_function_should_give_error(self): types = [Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int()))] for type in types: with self.assertRaises(CompileError) as context: generate_commands(""" function func() return {} {{ }} main () {{ {} a <- func(); }} """.format(type, type)) self.assertTrue("Function func has returned type {}, but nothing is returned" .format(type) in str(context.exception))
def test_vector_elem_assign_with_int_should_update_symbol_table_correctly( self): actual = SymbolTable() generate_commands(""" main () { vector a <- (10, 20, -30); a.x <- 1; a.y <- 2; a.z <- -3; } """, symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), [1.0, 2.0, -3.0], ident="a")) self.assertEqual(expected, actual)
def test_for_with_wrong_type_ident_should_give_error(self): types = [Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int()))] for type in types: with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ {} i; for i from 0 to 9 step 2 {{ }} }} """.format(type)) self.assertTrue("Identifier i has been declared as {}, but assigned as int" .format(type) in str(context.exception))
def test_return_correct_type_in_function_should_return_correct_value(self): types = [Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.decimal()), Type.list_of(Type.list_of(Type.int()))] for type in types: actual = SymbolTable() generate_commands(""" function func() return {} {{ {} a; return a; }} main () {{ {} a <- func(); }} """.format(type, type, type), symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(type, type.default_value, ident="a")) self.assertEqual(expected, actual)