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 visitInsert(self, ctx: xDroneParser.InsertContext) -> None:
     list = self.visit(ctx.expr(0))
     if not isinstance(list.type, ListType):
         raise CompileError(
             "Expression {} should have type list, but is {}".format(
                 list, list.type))
     if ctx.AT():
         index = self.visit(ctx.expr(1))
         value = self.visit(ctx.expr(2))
     else:
         index = Expression(Type.int(), len(list.value))
         value = self.visit(ctx.expr(1))
     if index.type != Type.int():
         raise CompileError(
             "Expression {} should have type int, but is {}".format(
                 index, index.type))
     if index.value > len(list.value) or index.value < 0:
         raise CompileError(
             "List {} has length {}, but has been inserted at out-of-range index {}"
             .format(list, len(list.value), index.value))
     if not isinstance(list.type,
                       EmptyList) and value.type != list.type.elem_type:
         raise CompileError(
             "List {} has been declared as {}, but inserted with element type {}"
             .format(list, list.type, value.type))
     self._insert_nested_ident(list.ident, value, index.value)
    def visitParallel(self, ctx: xDroneParser.ParallelContext) -> None:
        parallel_commands = ParallelDroneCommands()
        for commands in ctx.commands():
            self.commands.append([])

            # scope - discard updates on existing variables, discard new variables
            new_symbol_table = copy.deepcopy(self._get_latest_symbol_table())
            self.symbol_table.append(new_symbol_table)
            self.returned.append(False)
            self.returned_value.append(None)
            self.visit(commands)
            returned_value = self.returned_value.pop(-1)
            self.returned.pop(-1)
            self.symbol_table.pop(-1)
            if returned_value is not None:
                raise CompileError(
                    "Parallel branch should not return anything, but {} is returned"
                    .format(returned_value))

            branch = self.commands.pop(-1)
            try:
                parallel_commands.add(branch)
            except RepeatDroneNameException as e:
                raise CompileError(
                    "Parallel branches should have exclusive drone names, "
                    "but {} appeared in more than one branches".format(
                        e.repeated_names))

        self._get_latest_commands().append(parallel_commands)
 def visitDel(self, ctx: xDroneParser.DelContext) -> None:
     identifier = self.visit(ctx.ident())
     ident = identifier.ident
     if identifier.ident in self.drones:
         raise CompileError(
             "Identifier {} is a drone constant, cannot be deleted".format(
                 ident))
     if ident not in self._get_latest_symbol_table():
         raise CompileError(
             "Identifier {} has not been declared".format(ident))
     self._get_latest_symbol_table().delete(ident)
 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 visitOr(self, ctx: xDroneParser.OrContext) -> Expression:
     expr1, expr2 = self.visit(ctx.expr(0)), self.visit(ctx.expr(1))
     if expr1.type != Type.boolean():
         raise CompileError(
             "Expression {} should have type boolean, but is {}".format(
                 expr1, expr1.type))
     if expr2.type != Type.boolean():
         raise CompileError(
             "Expression {} should have type boolean, but is {}".format(
                 expr2, expr2.type))
     return Expression(Type.boolean(), expr1.value or expr2.value)
 def visitDeclareAssign(self,
                        ctx: xDroneParser.DeclareAssignContext) -> None:
     type, identifier, expr = self.visit(ctx.type_()), self.visit(
         ctx.ident()), self.visit(ctx.expr())
     ident = identifier.ident
     if ident in self._get_latest_symbol_table(
     ) or identifier.ident in self.drones:
         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(type, expr.value, ident)
     self._get_latest_symbol_table().store(ident, expr_with_ident)
 def visitListElem(self, ctx: xDroneParser.ListElemContext) -> ListElem:
     expr1, expr2 = self.visit(ctx.expr(0)), self.visit(ctx.expr(1))
     if not isinstance(expr1.type, ListType):
         raise CompileError(
             "Expression {} should have type list, but is {}".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) or expr2.value < 0:
         raise CompileError(
             "List {} has length {}, but has been assessed with out-of-range index {}"
             .format(expr1, len(expr1.value), expr2.value))
     return ListElem(expr1.ident, expr1, expr2.value)
 def visitDeclare(self, ctx: xDroneParser.DeclareContext) -> None:
     type, identifier = self.visit(ctx.type_()), self.visit(ctx.ident())
     ident = identifier.ident
     if ident in self._get_latest_symbol_table() or ident in self.drones:
         raise CompileError("Identifier {} already declared".format(ident))
     self._get_latest_symbol_table().store(
         ident, Expression(type, type.default_value, ident=ident))
Esempio n. 10
0
 def visitSize(self, ctx: xDroneParser.SizeContext) -> Expression:
     expr = self.visit(ctx.expr())
     if not isinstance(expr.type, ListType):
         raise CompileError(
             "Expression {} should have type list, but is {}".format(
                 expr, expr.type))
     return Expression(Type.int(), len(expr.value))
Esempio n. 11
0
 def visitNot(self, ctx: xDroneParser.NotContext) -> Expression:
     expr = self.visit(ctx.expr())
     if expr.type != Type.boolean():
         raise CompileError(
             "Expression {} should have type boolean, but is {}".format(
                 expr, expr.type))
     return Expression(Type.boolean(), not expr.value)
Esempio n. 12
0
 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)
Esempio n. 13
0
 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)
Esempio n. 14
0
 def visitProcedureCall(self,
                        ctx: xDroneParser.ProcedureCallContext) -> None:
     call = self.visit(ctx.call())
     if call is not None:
         raise CompileError(
             "Procedure call should not return any expression, but {} is returned"
             .format(call))
     return call
Esempio n. 15
0
 def visitFunctionCall(self,
                       ctx: xDroneParser.FunctionCallContext) -> Expression:
     call = self.visit(ctx.call())
     if call is None:
         raise CompileError(
             "Function call should return an expression, but nothing is returned"
         )
     return call
Esempio n. 16
0
 def visitIdentExpr(self, ctx: xDroneParser.IdentExprContext) -> Expression:
     identifier = self.visit(ctx.ident())
     ident = identifier.ident
     if ident not in self._get_latest_symbol_table(
     ) and ident not in self.drones:
         # identifier.expression is None iff child.ident not in latest symbol table nor in drones constants
         raise CompileError(
             "Identifier {} has not been declared".format(ident))
     return identifier.to_expression()
Esempio n. 17
0
    def _get_drone_name(self, expr: Optional[Expression]):
        if expr is not None:
            if expr.type != Type.drone():
                raise CompileError(
                    "Expression {} should have type drone, but is {}".format(
                        expr, expr.type))
            if isinstance(expr.value, NullDrone):
                raise CompileError("Drone has not been assigned".format(
                    expr, expr.type))

            drone_name = expr.value.name
        elif expr is None and len(self.drones) == 1:
            drone_name = list(self.drones.keys())[0]
        else:
            raise CompileError(
                "Drone should be specified if there are multiple drones in config"
            )
        return drone_name
Esempio n. 18
0
 def visitProcedure(self, ctx: xDroneParser.ProcedureContext) -> None:
     func_identifier = self.visit(ctx.funcIdent())
     ident = func_identifier.ident
     if ident in self.function_table:
         raise CompileError(
             "Function or procedure {} already defined".format(ident))
     param_list = self.visit(ctx.paramList()) if ctx.paramList() else []
     self.function_table.store(
         ident, Function(ident, param_list, None, ctx.commands()))
Esempio n. 19
0
 def visitReturn(self, ctx: xDroneParser.ReturnContext) -> None:
     if len(self.returned) == 1:
         raise CompileError("Cannot return in the Main function")
     self.returned[-1] = True  # order important
     if ctx.expr():
         expr = self.visit(ctx.expr())
         self.returned_value[-1] = Expression(expr.type,
                                              expr.value,
                                              ident=None)
Esempio n. 20
0
 def visitAssignIdent(self, ctx: xDroneParser.AssignIdentContext) -> None:
     identifier, expr = self.visit(ctx.ident()), self.visit(ctx.expr())
     ident = identifier.ident
     if identifier.ident in self.drones:
         raise CompileError(
             "Identifier {} is a drone constant, cannot be assigned".format(
                 ident))
     if ident not in self._get_latest_symbol_table():
         raise CompileError(
             "Identifier {} has not been declared".format(ident))
     assigned_type = expr.type
     declared_type = self._get_latest_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._get_latest_symbol_table().update(ident, expr.value)
Esempio n. 21
0
 def visitCompare(self, ctx: xDroneParser.CompareContext) -> Expression:
     expr1, expr2 = self.visit(ctx.expr(0)), self.visit(ctx.expr(1))
     if expr1.type != Type.int() and expr1.type != Type.decimal():
         raise CompileError(
             "Expression {} should have type int or decimal, but is {}".
             format(expr1, expr1.type))
     if expr2.type != Type.int() and expr2.type != Type.decimal():
         raise CompileError(
             "Expression {} should have type int or decimal, but is {}".
             format(expr2, expr2.type))
     if ctx.GREATER():
         result_value = expr1.value > expr2.value
     elif ctx.GREATER_EQ():
         result_value = expr1.value >= expr2.value
     elif ctx.LESS():
         result_value = expr1.value < expr2.value
     else:  # LESS_EQ
         result_value = expr1.value <= expr2.value
     return Expression(Type.boolean(), result_value)
Esempio n. 22
0
 def visitWhile(self, ctx: xDroneParser.WhileContext) -> None:
     expr = self.visit(ctx.expr())
     if expr.type != Type.boolean():
         raise CompileError(
             "Expression {} should have type boolean, but is {}".format(
                 expr, expr.type))
     while expr.value:
         # scope - keep updates on existing variables, discard new variables
         self._visit_commands_with_scope(ctx.commands())
         expr = self.visit(ctx.expr())
Esempio n. 23
0
 def visitRemove(self, ctx: xDroneParser.RemoveContext) -> None:
     list = self.visit(ctx.expr(0))
     if not isinstance(list.type, ListType):
         raise CompileError(
             "Expression {} should have type list, but is {}".format(
                 list, list.type))
     if ctx.AT():
         index = self.visit(ctx.expr(1))
     else:
         index = Expression(Type.int(), len(list.value) - 1)
     if index.type != Type.int():
         raise CompileError(
             "Expression {} should have type int, but is {}".format(
                 index, index.type))
     if index.value >= len(list.value) or index.value < 0:
         raise CompileError(
             "List {} has length {}, but has been removed at out-of-range index {}"
             .format(list, len(list.value), index.value))
     self._remove_nested_ident(list.ident, index.value)
Esempio n. 24
0
    def visitCall(self, ctx: xDroneParser.CallContext) -> Optional[Expression]:
        func_identifier = self.visit(ctx.funcIdent())
        ident = func_identifier.ident
        arg_list = self.visit(ctx.argList()) if ctx.argList() else []
        if ident not in self.function_table:
            raise CompileError(
                "Function or procedure {} has not been defined".format(ident))
        function = self.function_table.get_function(ident)
        arg_types = [arg.type for arg in arg_list]
        param_types = [param.type for param in function.param_list]
        if arg_types != param_types:
            raise CompileError(
                "Arguments when calling function or procedure {} should have types {}, but is {}"
                .format(ident, [str(type) for type in param_types],
                        [str(type) for type in arg_types]))
        new_symbol_table = SymbolTable()
        param_idents = [param.ident for param in function.param_list]
        for param_ident, expr in zip(param_idents, arg_list):
            new_symbol_table.store(param_ident, expr)

        self.symbol_table.append(new_symbol_table)
        self.returned.append(False)
        self.returned_value.append(None)
        self.visit(function.get_commands())
        returned_value = self.returned_value.pop(-1)
        self.returned.pop(-1)
        self.symbol_table.pop(-1)
        if function.return_type is None:
            if returned_value is not None:
                raise CompileError(
                    "Procedure {} should not return anything, but {} is returned"
                    .format(ident, returned_value))
            return None
        else:
            if returned_value is None:
                raise CompileError(
                    "Function {} has returned type {}, but nothing is returned"
                    .format(ident, function.return_type))
            if returned_value.type != function.return_type:
                raise CompileError(
                    "Function {} has returned type {}, but {} is returned".
                    format(ident, function.return_type, returned_value.type))
            return returned_value
Esempio n. 25
0
 def visitList(self, ctx: xDroneParser.ListContext) -> Expression:
     exprs = [self.visit(expr) for expr in ctx.expr()]
     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(
                 [str(e) for e in exprs]))
     return Expression(Type.list_of(exprs[0].type),
                       [e.value for e in exprs])
Esempio n. 26
0
 def visitEquality(self, ctx: xDroneParser.EqualityContext) -> Expression:
     expr1, expr2 = self.visit(ctx.expr(0)), self.visit(ctx.expr(1))
     if expr1.type != expr2.type:
         raise CompileError(
             "Expressions {} and {} should have the same type".format(
                 expr1, expr2))
     if ctx.EQ():
         result_value = expr1.value == expr2.value
     else:  # NOT_EQ
         result_value = expr1.value != expr2.value
     return Expression(Type.boolean(), result_value)
Esempio n. 27
0
 def visitParamList(self,
                    ctx: xDroneParser.ParamListContext) -> List[Parameter]:
     types = [self.visit(type) for type in ctx.type_()]
     idents = [self.visit(ident).ident for ident in ctx.ident()]
     if len(idents) != len(set(idents)):
         raise CompileError(
             "Parameter names are duplicated in {}".format(idents))
     parameters = []
     for type, ident in zip(types, idents):
         parameters.append(Parameter(ident, type))
     return parameters
Esempio n. 28
0
    def visitRepeat(self, ctx: xDroneParser.RepeatContext) -> None:
        expr = self.visit(ctx.expr())
        if expr.type != Type.int():
            raise CompileError(
                "Expression {} should have type int, but is {}".format(
                    expr, expr.type))
        times = expr.value

        for _ in range(times):
            # scope - keep updates on existing variables, discard new variables
            self._visit_commands_with_scope(ctx.commands())
Esempio n. 29
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)])
Esempio n. 30
0
 def visitUp(self, ctx: xDroneParser.UpContext) -> None:
     exprs = [self.visit(expr) for expr in ctx.expr()]
     if ctx.DOT():
         drone_expr, expr = exprs
     else:
         drone_expr, expr = None, exprs[0]
     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))
     drone_name = self._get_drone_name(drone_expr)
     self._get_latest_commands().append(
         SingleDroneCommand(drone_name, Command.up(expr.value)))