def test_declare_int_should_change_symbol_table(self): actual = SymbolTable() generate_commands(""" main () { int a; } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.int(), 0, ident="a")) self.assertEqual(expected, actual)
def test_declare_and_assign_boolean_should_change_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { boolean a <- true; } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.boolean(), True, ident="a")) self.assertEqual(expected, actual)
def test_declare_and_assign_string_should_change_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { string a <- "\0a"; } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.string(), "\0a", ident="a")) self.assertEqual(expected, actual)
def test_declare_and_assign_decimal_should_change_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { decimal a <- 1.0; } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.decimal(), 1.0, ident="a")) self.assertEqual(expected, actual)
def test_declare_and_assign_vector_should_change_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { vector a <- (1.0, 2.0, -3.0); } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), [1, 2, -3], ident="a")) self.assertEqual(expected, actual)
def test_declare_and_assign_list_should_change_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { list[int] a <- [1, 2, -3]; } """, actual) expected = SymbolTable() expected.store( "a", Expression(Type.list_of(Type.int()), [1, 2, -3], ident="a")) self.assertEqual(expected, actual)
def test_assign_vector_elem_to_temp_vector_should_not_change_symbol_table( self): actual = SymbolTable() generate_commands( """ main () { (0.0, 0.0, 0.0).x <- 1.0; } """, actual) expected = SymbolTable() self.assertEqual(expected, actual)
def test_assign_ident_string_should_update_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { string a; a <- "1"; } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.string(), "1", ident="a")) self.assertEqual(expected, actual)
def test_assign_ident_decimal_should_update_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { decimal a; a <- -1.5e10; } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.decimal(), -1.5e10, ident="a")) 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); } """, actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), [1, -1, 1], ident="a")) self.assertEqual(expected, actual)
def test_assign_ident_list_should_update_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { list[int] a; a <- [1, -1, +1]; } """, actual) expected = SymbolTable() expected.store( "a", Expression(Type.list_of(Type.int()), [1, -1, 1], ident="a")) self.assertEqual(expected, actual)
def test_declare_with_different_variable_name_should_change_symbol_table( self): for name in [ "a", "A", "_a", "_1", "_A", "abc", "Abc", "a12", "aA1", "_aA1" ]: actual = SymbolTable() generate_commands( """ main () {{ int {}; }} """.format(name), actual) expected = SymbolTable() expected.store(name, Expression(Type.int(), 0, ident=name)) self.assertEqual(expected, actual)
def test_eq(self): st1 = SymbolTable() st2 = SymbolTable() self.assertTrue(st1 == st2) st1.store("a", Expression(Type.int(), 0)) self.assertFalse(st1 == st2) st2.store("a", Expression(Type.int(), 0)) self.assertTrue(st1 == st2) self.assertNotEqual(SymbolTable(), None)
def test_assign_vector_elem_to_variable_should_update_symbol_table(self): for index, vector in zip(["x", "y", "z"], [[-1.0, 0, 0], [0, -2.0, 0], [0, 0, -3.0]]): actual = SymbolTable() generate_commands( """ main () {{ vector a; a.{} <- (-1.0, -2.0, -3.0).{}; }} """.format(index, index), actual) expected = SymbolTable() expected.store("a", Expression(Type.vector(), vector, ident="a")) self.assertEqual(expected, actual)
def test_assign_list_elem_to_variable_should_update_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { list[int] a <- [0, 1, 2]; a[0] <- 1; a[2] <- a[0]; } """, actual) expected = SymbolTable() expected.store( "a", Expression(Type.list_of(Type.int()), [1, 1, 1], ident="a")) self.assertEqual(expected, actual)
def test_update(self): st = SymbolTable() self.assertRaises(AssertionError, st.update, "a", 1) st.store("a", Expression(Type.int(), 1)) st.update("a", 2) self.assertEqual(Type.int(), st.get_expression("a").type) self.assertEqual(2, st.get_expression("a").value)
def test_assign_list_elem_to_temp_vector_should_not_change_symbol_table( self): for code in [ "[0.0][0] <- 1.0", "[0][0] <- 1", "[[\"a\"]][0] <- [\"b\"]", "[0.0, 1.0][0] <- 1.0" ]: actual = SymbolTable() generate_commands( """ main () {{ {}; }} """.format(code), actual) expected = SymbolTable() self.assertEqual(expected, actual)
def test_assign_list_elem_with_vector_should_update_symbol_table(self): actual = SymbolTable() generate_commands( """ main () { list[vector] a <- [(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)]; a[0] <- (7.0, 8.0, 9.0); a[1].x <- 10.0; a[1].y <- 11.0; a[1].z <- 12.0; } """, actual) expected = SymbolTable() expected.store( "a", Expression(Type.list_of(Type.vector()), [[7, 8, 9], [10, 11, 12]], ident="a")) self.assertEqual(expected, actual)
def test_assign_list_elem_to_variable_nested_should_update_symbol_table( self): actual = SymbolTable() generate_commands( """ main () { list[list[int]] a <- [[0, 1], [2, 3]]; a[0] <- [4, 5]; a[1][0] <- 6; a[1][1] <- 7; } """, actual) expected = SymbolTable() expected.store( "a", Expression(Type.list_of(Type.list_of(Type.int())), [[4, 5], [6, 7]], ident="a")) self.assertEqual(expected, actual)
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.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), actual) expected = SymbolTable() expected.store("a", Expression(Type.list_of(type), [], ident="a")) self.assertEqual(expected, actual)
def test_store(self): st = SymbolTable() st.store("a", Expression(Type.int(), 1)) self.assertTrue("a" in st) self.assertEqual(Type.int(), st.get_expression("a").type) self.assertEqual(1, st.get_expression("a").value) self.assertRaises(AssertionError, st.store, "a", Expression(Type.int(), 1))
def test_str(self): st = SymbolTable() st.store("a", Expression(Type.int(), 0)) st.store("b", Expression(Type.list_of(Type.boolean()), [True])) expected = "SymbolTable: {\n" + \ " a -> Expression: { type: int, value: 0, ident: None }\n" + \ " b -> Expression: { type: list[boolean], value: [True], ident: None }\n" + \ "}" self.assertEqual(expected, str(st))
def test_contains(self): st = SymbolTable() self.assertFalse("a" in st) st.store("a", Expression(Type.int(), 0)) self.assertTrue("a" in st)
def test_get_expression(self): st = SymbolTable() st.store("a", Expression(Type.list_of(Type.int()), [1])) self.assertEqual([1], st.get_expression("a").value) self.assertEqual(1, st.get_expression("a").value[0]) self.assertEqual(Type.list_of(Type.int()), st.get_expression("a").type)
def __init__(self, symbol_table): super().__init__() self.symbol_table = SymbolTable( ) if symbol_table is None else symbol_table
class Interpreter(Transformer): def __init__(self, symbol_table): super().__init__() self.symbol_table = SymbolTable( ) if symbol_table is None else symbol_table # def __default__(self, command, children, meta): # logging.error("Ignoring unsupported command %s with children %s" % (command, children)) # raise Discard() ######## prog ######## def prog(self, children): return children ######## commands ######## def commands(self, children): return children ######## command ######## def takeoff(self, children) -> List[Command]: return [Command.takeoff()] def land(self, children) -> List[Command]: return [Command.land()] def up(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.up(expr.value)] def down(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.down(expr.value)] def left(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.left(expr.value)] def right(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.right(expr.value)] def forward(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.forward(expr.value)] def backward(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.backward(expr.value)] def rotate_left(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.rotate_left(radians(expr.value))] def rotate_right(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.rotate_right(radians(expr.value))] def wait(self, children) -> List[Command]: expr, = children if expr.type != Type.int() and expr.type != Type.decimal(): raise CompileError( "Expression {} should have type int or decimal, but is {}". format(expr.value, expr.type)) return [Command.wait(expr.value)] def declare(self, children) -> List[Command]: type, identifier = children ident = identifier.ident if ident in self.symbol_table: raise CompileError("Identifier {} already declared".format(ident)) self.symbol_table.store( ident, Expression(type, type.default_value, ident=ident)) return [] def declare_assign(self, children) -> List[Command]: type, identifier, expr = children ident = identifier.ident if ident in self.symbol_table: raise CompileError("Identifier {} already declared".format(ident)) if expr.type != type: raise CompileError( "Identifier {} has been declared as {}, but assigned as {}". format(ident, type, expr.type)) expr_with_ident = Expression(expr.type, expr.value, ident) self.symbol_table.store(ident, expr_with_ident) return [] def assign_ident(self, children) -> List[Command]: identifier, expr = children ident = identifier.ident if ident not in self.symbol_table: raise CompileError( "Identifier {} has not been declared".format(ident)) assigned_type = expr.type declared_type = self.symbol_table.get_expression(ident).type if assigned_type != declared_type: raise CompileError( "Identifier {} has been declared as {}, but assigned as {}". format(ident, declared_type, assigned_type)) self.symbol_table.update(ident, expr.value) return [] def _update_nested_ident(self, ident, expr, index) -> None: if ident is not None: if "[" in ident: tokens = ident.split("[") ident = tokens[0] indices = [int(token.replace("]", "")) for token in tokens[1:]] else: indices = [] assert ident in self.symbol_table new_list = self.symbol_table.get_expression(ident).value curr = new_list for i in indices: curr = curr[i] curr[index] = expr.value self.symbol_table.update(ident, new_list) def assign_list_elem(self, children) -> List[Command]: list_elem, expr = children ident = list_elem.ident list = list_elem.container index = list_elem.index assigned_type = expr.type declared_type = list.type.elem_type if assigned_type != declared_type: raise CompileError( "Assigned value {} should have type {}, but is {}".format( expr.value, declared_type, assigned_type)) self._update_nested_ident(ident, expr, index) return [] def assign_vector_elem(self, children) -> List[Command]: vector_elem, expr = children ident = vector_elem.ident vector = vector_elem.container index = vector_elem.index if expr.type != Type.decimal(): raise CompileError( "Assigned value {} should have type decimal, but is {}".format( expr.value, expr.type)) self._update_nested_ident(ident, expr, index) return [] def repeat(self, children) -> List[Command]: expr = children[0] commands = children[1:] if expr.type != Type.int(): raise CompileError( "Expression {} should have type int, but is {}".format( expr.value, expr.type)) times = expr.value return commands * times ######## func ######## # TODO ######## func_command ######## # TODO ######## param_list ######## # TODO ######## func_call ######## # TODO ######## arg_list ######## # TODO ######## ident ######## def ident(self, children) -> Identifier: ident = "".join([str(child) for child in children]) if ident in self.symbol_table: return Identifier(str(ident), self.symbol_table.get_expression(ident)) return Identifier(str(ident), None) ######## list_elem ######## def list_elem(self, children) -> ListElem: expr1, expr2 = children if not isinstance(expr1.type, ListType): raise CompileError( "Expression {} has type {} is not a list".format( expr1, expr1.type)) if expr2.type != Type.int(): raise CompileError( "Expression {} should have type int, but is {}".format( expr2, expr2.type)) if expr2.value >= len(expr1.value): raise CompileError( "List {} has length {}, but has been assessed with out-of-range index {}" .format(expr1.ident, len(expr1.value), expr2.value)) return ListElem(expr1.ident, expr1, expr2.value) ######## vector_elem ######## def vector_x(self, children) -> VectorElem: expr, = children if expr.type != Type.vector(): raise CompileError( "Expression {} should have type vector, but is {}".format( expr, expr.type)) return VectorElem(expr.ident, expr, 0) def vector_y(self, children) -> VectorElem: expr, = children if expr.type != Type.vector(): raise CompileError( "Expression {} should have type vector, but is {}".format( expr, expr.type)) return VectorElem(expr.ident, expr, 1) def vector_z(self, children) -> VectorElem: expr, = children if expr.type != Type.vector(): raise CompileError( "Expression {} should have type vector, but is {}".format( expr, expr.type)) return VectorElem(expr.ident, expr, 2) ######## type ######## def int_type(self, children) -> Type: return Type.int() def decimal_type(self, children) -> Type: return Type.decimal() def string_type(self, children) -> Type: return Type.string() def boolean_type(self, children) -> Type: return Type.boolean() def vector_type(self, children) -> Type: return Type.vector() def list_type(self, children) -> Type: elem_type, = children return Type.list_of(elem_type) ######## expr ######## def expr(self, children) -> Expression: child, = children assert isinstance(child, AbstractExpression) if isinstance(child, Identifier) and child.ident not in self.symbol_table: # child.expression is None iff child.ident not in self.symbol_table raise CompileError("Identifier {} has not been declared".format( child.ident)) expr = child.to_expression() assert expr is not None and isinstance(expr, Expression) return expr def int_expr(self, children) -> Expression: signed_int, = children return Expression(Type.int(), int(signed_int)) def decimal_expr(self, children) -> Expression: signed_float, = children return Expression(Type.decimal(), float(signed_float)) def string_expr(self, children) -> Expression: escaped_string, = children quotation_removed = str(escaped_string)[1:-1] return Expression(Type.string(), quotation_removed) def true_expr(self, children) -> Expression: return Expression(Type.boolean(), True) def false_expr(self, children) -> Expression: return Expression(Type.boolean(), False) def list(self, children) -> Expression: exprs = children if len(exprs) == 0: return Expression(Type.empty_list(), []) if not all(e.type == exprs[0].type for e in exprs): raise CompileError( "Elements in list {} should have the same type".format(exprs)) return Expression(Type.list_of(exprs[0].type), [e.value for e in exprs]) def vector(self, children) -> Expression: expr1, expr2, expr3 = children for expr in [expr1, expr2, expr3]: if expr.type != Type.decimal(): raise CompileError( "Expression {} should have type decimal, but is {}".format( expr, expr.type)) return Expression(Type.vector(), [expr1.value, expr2.value, expr3.value])