def visitConcat(self, ctx: xDroneParser.ConcatContext) -> Expression: expr1, expr2 = self.visit(ctx.expr(0)), self.visit(ctx.expr(1)) if expr1.type != Type.string(): raise CompileError( "Expression {} should have type string, but is {}".format( expr1, expr1.type)) if expr2.type != Type.string(): raise CompileError( "Expression {} should have type string, but is {}".format( expr2, expr2.type)) return Expression(Type.string(), expr1.value + expr2.value)
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_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_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 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_declare_and_assign_string_should_change_symbol_table(self): actual = SymbolTable() generate_commands(""" main () { string a <- "\0a"; } """, symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.string(), "\0a", ident="a")) self.assertEqual(expected, actual)
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_assign_ident_string_should_update_symbol_table(self): actual = SymbolTable() generate_commands(""" main () { string a; a <- "1"; } """, symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.string(), "1", ident="a")) self.assertEqual(expected, actual)
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_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 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_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)
def test_return_value_in_procedure_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(""" procedure proc() {{ {} a; return a; }} main () {{ proc(); }} """.format(type)) self.assertTrue("Procedure proc should not return anything, but {} is returned" .format(Expression(type, type.default_value, ident=None)) in str(context.exception))
def test_for_with_wrong_type_step_expr_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 () {{ int i; {} a; for i from 0 to 9 step a {{ }} }} """.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_define_functions_with_duplicated_parameter_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 type1 in types: for type2 in types: with self.assertRaises(CompileError) as context: generate_commands(""" function func({} a, {} a) return int {{}} main () {{}} """.format(type1, type2, type1, type2)) self.assertTrue("Parameter names are duplicated in ['a', 'a']" in str(context.exception)) with self.assertRaises(CompileError) as context: generate_commands(""" procedure proc({} a, {} a) {{}} main () {{}} """.format(type1, type2, type1, type2)) self.assertTrue("Parameter names are duplicated in ['a', 'a']" in str(context.exception))
def test_return_wrong_type_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 t1 in types: for t2 in types: if t1 == t2: continue with self.assertRaises(CompileError) as context: generate_commands(""" function func() return {} {{ {} a; return a; }} main () {{ {} a <- func(); }} """.format(t1, t2, t1)) self.assertTrue("Function func has returned type {}, but {} is returned" .format(t1, t2) in str(context.exception))
def test_movement_with_other_type_should_give_error(self): types = [ Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), 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; a.takeoff(); a.land(); }} """.format(type)) self.assertTrue( "Expression {} should have type drone, but is {}".format( Expression(type, type.default_value, ident="a"), type.type_name) in str(context.exception))
def test_call_function_with_wrong_type_argument_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(""" function func({} i) return {} {{ return(i); }} main () {{ {} a; {} b <- func(a); }} """.format(t1, t1, t2, t1)) self.assertTrue("Arguments when calling function or procedure func should have types ['{}'], " "but is ['{}']".format(t1, t2) in str(context.exception))
def test_wait_with_incorrect_parameter_should_give_error(self): types = [ Type.boolean(), Type.string(), 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; wait(a); }} """.format(type.type_name)) self.assertTrue( "Expression {} should have type int or decimal, but is {}". format(Expression(type, type.default_value, ident="a"), type.type_name) in str(context.exception))
def test_list_remove_from_non_list_should_give_error(self): types = [ Type.int(), Type.decimal(), Type.string(), Type.boolean(), Type.vector(), Type.drone() ] for type in types: with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ {} a; a.remove(); }} """.format(type)) self.assertTrue( "Expression {} should have type list, but is {}".format( Expression(type, type.default_value, ident="a"), type.type_name) in str(context.exception))
def test_declare_and_assign_ident_empty_list_should_update_symbol_table( 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: actual = SymbolTable() generate_commands(""" main () {{ list[{}] a <- []; }} """.format(type.type_name), symbol_table=actual) expected = SymbolTable() expected.store("a", Expression(Type.list_of(type), [], ident="a")) self.assertEqual(expected, actual)
def test_declare_and_then_assign_vector_elem_with_different_type_should_give_error( self): for type in [ Type.string(), Type.boolean(), Type.vector(), Type.drone(), Type.list_of(Type.int()), Type.list_of(Type.list_of(Type.int())) ]: for index in ["x", "y", "z"]: with self.assertRaises(CompileError) as context: generate_commands(""" main () {{ vector a; {} b; a.{} <- b; }} """.format(type.type_name, index)) self.assertTrue( "Assigned value {} should have type int or decimal, but is {}" .format(Expression(type, type.default_value, ident="b"), type.type_name) in str(context.exception))
def visitStringType(self, ctx: xDroneParser.StringTypeContext) -> Type: return Type.string()
def test_string(self): self.assertEqual(Type.string(), Type.string()) self.assertEqual("string", Type.string().type_name) self.assertEqual("", Type.string().default_value) self.assertEqual("string", str(Type.string()))
def visitStringExpr(self, ctx: xDroneParser.StringExprContext) -> Expression: escaped_string = ctx.ESCAPED_STRING().getText() quotation_removed = str(escaped_string)[1:-1] unescaped = bytes(quotation_removed, "utf-8").decode("unicode_escape") return Expression(Type.string(), unescaped)