Exemplo n.º 1
0
    def visit_call_expr(self, expr):
        callee = self.evaluate(expr.callee)
        arguments = []
        for argument in expr.arguments:
            arguments.append(self.evaluate(argument))

        if not isinstance(callee, LoxCallable):
            raise RuntimeException(expr.paren, "Can only call functions and classes.")

        function = callee
        if not len(arguments) == function.arity():
            raise RuntimeException(expr.paren, f"Expected {function.arity()} arguments but got {len(arguments)}.")

        return function.call(self, arguments)
Exemplo n.º 2
0
    def visit_class_stmt(self, stmt):
        superclass = None
        if stmt.superclass is not None:
            superclass = self.evaluate(stmt.superclass)
            if not type(superclass) == LoxClass:
                raise RuntimeException(stmt.superclass.name, "Superclass must be a class.")

        self.environment.define(stmt.name.lexem, None)

        if stmt.superclass is not None:
            self.environment = Environment(self.environment)
            self.environment.define("super", superclass)

        methods = {}

        for method in stmt.methods:
            function = LoxFunction(method, self.environment, method.name.lexem == "init")
            methods[method.name.lexem] = function

        klass = LoxClass(stmt.name.lexem, superclass, methods)

        if stmt.superclass is not None:
            self.environment = self.environment.enclosing

        self.environment.assign(stmt.name, klass)
        return None
Exemplo n.º 3
0
    def get(self, name):
        if name.lexem in self.values.keys():
            return self.values[name.lexem]

        if self.enclosing is not None:
            return self.enclosing.get(name)

        raise RuntimeException(name, f"Undefined variable '{name.lexem}'.")
Exemplo n.º 4
0
    def visit_set_expr(self, expr):
        object = self.evaluate(expr.object)

        if not type(object) is LoxInstance:
            raise RuntimeException(expr.name, "Only instances have fields.")

        value = self.evaluate(expr.value)
        object.set(expr.name, value)
        return value
Exemplo n.º 5
0
    def get(self, name):
        if self.fields.keys().__contains__(name.lexem):
            return self.fields[name.lexem]

        method = self.klass.find_method(name.lexem)
        if method is not None:
            return method.bind(self)

        raise RuntimeException(name, f"Undefined property {name.lexem}.")
Exemplo n.º 6
0
    def assign(self, name, value):
        if name.lexem in self.values.keys():
            self.values[name.lexem] = value
            return

        if self.enclosing is not None:
            self.enclosing.assign(name, value)
            return

        raise RuntimeException(name, f"Undefined variable '{name.lexem}'.")
Exemplo n.º 7
0
    def visit_super_expr(self, expr):
        distance = self.locals[expr]
        superclass = self.environment.get_at(distance, "super")
        object = self.environment.get_at(distance - 1, "this")

        method = superclass.find_method(expr.method.lexem)
        if method is None:
            raise RuntimeException(expr.method, f"Undefined property {expr.method.lexem}.")

        return method.bind(object)
Exemplo n.º 8
0
    def visit_binary_expr(self, expr):
        left = self.evaluate(expr.left)
        right = self.evaluate(expr.right)

        operator_type = expr.operator.type
        if operator_type == TokenType.MINUS:
            self.check_number_operands(expr.operator, left, right)
            return left - right
        elif operator_type == TokenType.SLASH:
            self.check_number_operands(expr.operator, left, right)
            return left / right
        elif operator_type == TokenType.STAR:
            self.check_number_operands(expr.operator, left, right)
            return left * right
        elif operator_type == TokenType.MODULO:
            self.check_number_operands(expr.operator, left, right)
            return left % right
        elif operator_type == TokenType.PLUS:
            if type(left) == float and type(right) == float:
                return left + right
            elif (type(left) == str or type(left) == float) and (type(right) == str or type(right) == float):
                return str(left) + str(right)
            else:
                raise RuntimeException(expr.operator, "Operators must be two numbers or strings.")
        elif operator_type == TokenType.GREATER:
            self.check_number_operands(expr.operator, left, right)
            return left > right
        elif operator_type == TokenType.GREATER_EQUAL:
            self.check_number_operands(expr.operator, left, right)
            return left >= right
        elif operator_type == TokenType.LESS:
            self.check_number_operands(expr.operator, left, right)
            return left < right
        elif operator_type == TokenType.LESS_EQUAL:
            self.check_number_operands(expr.operator, left, right)
            return left <= right
        elif operator_type == TokenType.EQUAL_EQUAL:
            return self.is_equal(left, right)
        elif operator_type == TokenType.BANG_EQUAL:
            return not self.is_equal(left, right)
Exemplo n.º 9
0
 def check_number_operands(operator, left, right):
     if type(left) == float and type(right) == float:
         return
     else:
         raise RuntimeException(operator, "Operands must be a number.")
Exemplo n.º 10
0
 def check_number_operand(operator, operand):
     if type(operand) == float:
         return
     else:
         raise RuntimeException(operator, "Operand must be a number.")
Exemplo n.º 11
0
 def visit_get_expr(self, expr):
     object = self.evaluate(expr.object)
     if type(object) is LoxInstance:
         return object.get(expr.name)
     else:
         raise RuntimeException(expr.name, "Only instances have properties.")