def visit_this_expr(self, expr): if self.current_class == ClassType.NONE: Error.error(expr.keyword, "Cannot use 'this' outside of a class.") return None self.resolve_local(expr, expr.keyword) return None
def visit_class_stmt(self, stmt): enclosing_class = self.current_class self.current_class = ClassType.CLASS self.declare(stmt.name) self.define(stmt.name) if stmt.superclass is not None: if stmt.name.lexem == stmt.superclass.name.lexem: Error.error(stmt.superclass.name, "A class cannot inherit from itself.") else: self.current_class = ClassType.SUBCLASS self.resolve(stmt.superclass) self.begin_scope() self.scopes[-1]["super"] = True self.begin_scope() self.scopes[-1]["this"] = True for method in stmt.methods: declaration = Function.method if method.name.lexem == "init": declaration = Function.initializer self.resolve_function(method, declaration) self.end_scope() if stmt.superclass is not None: self.end_scope() self.current_class = enclosing_class return None
def interpret(self, statements): try: for statement in statements: if statement is not None: self.execute(statement) except RuntimeException as error: Error.runtime_error(error)
def visit_variable_expr(self, expr): if not len(self.scopes) == 0 and self.scopes[-1].keys().__contains__(expr.name.lexem) and \ not self.scopes[-1][expr.name.lexem]: Error.error(expr.name, "Cannot read local variable in its own initializer.") self.resolve_local(expr, expr.name) return None
def visit_super_expr(self, expr): if self.current_class == ClassType.NONE: Error.error(expr.keyword, "Cannot use 'super' outside of a class.") elif self.current_class != ClassType.SUBCLASS: Error.error( expr.keyword, "Cannot use 'super' in a class without a super class.") self.resolve_local(expr, expr.keyword) return None
def visit_return_stmt(self, stmt): if self.current_function == Function.none: Error.error(stmt.keyword, "Cannot return from top-level code") if stmt.value is not None: if self.current_function == Function.initializer: Error.error(stmt.keyword, "Cannot return from an initializer.") self.resolve(stmt.value) return None
def scan_token(self): c = self.advance() if c == '(': self.add_token(TokenType.LEFT_PAREN) elif c == ')': self.add_token(TokenType.RIGHT_PAREN) elif c == '{': self.add_token(TokenType.LEFT_BRACE) elif c == '}': self.add_token(TokenType.RIGHT_BRACE) elif c == ',': self.add_token(TokenType.COMMA) elif c == '.': self.add_token(TokenType.DOT) elif c == '-': self.add_token(TokenType.MINUS) elif c == '%': self.add_token(TokenType.MODULO) elif c == '+': self.add_token(TokenType.PLUS) elif c == ';': self.add_token(TokenType.SEMICOLON) elif c == '*': self.add_token(TokenType.STAR) elif c == '!': self.add_token( TokenType.BANG_EQUAL if self.match('=') else TokenType.BANG) elif c == '=': self.add_token( TokenType.EQUAL_EQUAL if self.match('=') else TokenType.EQUAL) elif c == '<': self.add_token( TokenType.LESS_EQUAL if self.match('=') else TokenType.LESS) elif c == '>': self.add_token(TokenType.GREATER_EQUAL if self. match('=') else TokenType.GREATER) elif c == '/': if self.match('/'): while (not self.peek() == '\n') and not self.is_at_end(): self.advance() else: self.add_token(TokenType.SLASH) elif c == ' ' or c == '\r' or c == '\t': return elif c == '"': self.string() elif c == '\n': self.line += 1 else: if c.isdigit(): self.number() elif c.isalpha() or c == '_': self.identifier() else: Error.error(self.line, "Unexpected character.")
def declare(self, name): if len(self.scopes) == 0: return scope = self.scopes[-1] if scope.keys().__contains__(name.lexem): Error.error( name, "Variable with this name already declared in this scope.") scope[name.lexem] = False
def string(self): while not self.peek() == '"' and not self.is_at_end(): if self.peek() == '\n': self.line += 1 self.advance() if self.is_at_end(): Error.error(self.line, "Unterminated string.") return self.advance() value = self.source[self.start + 1:self.current - 1] self.add_token(TokenType.STRING, value)
def error(token, message): Error.error(token, message) raise ParseError()