public object visitThisExpr(Expr.This expr) { if (currentClass == ClassType.NONE) { Lox.error(expr.Keyword, "Cannot use `this` outside of class"); return(null); } resolveLocal(expr, expr.Keyword); return(null); }
public object visitVariableExpr(Expr.Variable expr) { bool initialized; if (scopes.Count > 0 && scopes.Peek().TryGetValue(expr.Name.Lexeme, out initialized) && initialized == false) { Lox.error(expr.Name, "Cannot read local variable in it's own initializer"); } resolveLocal(expr, expr.Name); return(null); }
public object visitClassStmt(Stmt.Class stmt) { ClassType enclosingClass = currentClass; currentClass = ClassType.CLASS; declare(stmt.Name); define(stmt.Name); if (stmt.SuperClass != null && stmt.Name.Lexeme == stmt.SuperClass.Name.Lexeme) { Lox.error(stmt.SuperClass.Name, "A class cannot inherit from itself"); } if (stmt.SuperClass != null) { currentClass = ClassType.SUBCLASS; resolve(stmt.SuperClass); } if (stmt.SuperClass != null) { beginScope(); scopes.Peek()["super"] = true; } beginScope(); scopes.Peek()["this"] = true; foreach (Stmt.Function method in stmt.Methods) { FunctionType declaration = FunctionType.METHOD; if (method.Name.Lexeme == "init") { declaration = FunctionType.INITIALIZER; } resolveFunction(method, declaration); } endScope(); if (stmt.SuperClass != null) { endScope(); } currentClass = enclosingClass; return(null); }
private void declare(Token name) { if (scopes.Count == 0) { return; } var scope = scopes.Peek(); if (scope.ContainsKey(name.Lexeme)) { Lox.error(name, "Variable with this name already delared in this scope"); } scope[name.Lexeme] = false; }
public object visitSuperExpr(Expr.Super expr) { if (currentClass == ClassType.NONE) { Lox.error(expr.Keyword, "Cannot use 'super' outisde of class"); } else if (currentClass != ClassType.SUBCLASS) { Lox.error(expr.Keyword, "Cannot use 'super' in a class with no superclass"); } resolveLocal(expr, expr.Keyword); return(null); }
public object visitReturnStmt(Stmt.Return stmt) { if (currentFunction == FunctionType.NONE) { Lox.error(stmt.Keyword, "Cannot return from top-level code"); } if (stmt.Value != null) { if (currentFunction == FunctionType.INITIALIZER) { Lox.error(stmt.Keyword, "Cannot return a value from initilizer;"); } resolve(stmt.Value); } return(null); }
private void scanString() { while (peek() != '"' && !isAtEnd()) { if (peek() == '\n') { line++; } advance(); } if (isAtEnd()) { Lox.error(line, "Unterminated string"); return; } advance(); string value = Source.Substring(start + 1, current - start - 2); addToken(TokenType.STRING, value); }
private ParseError error(Token token, string message) { Lox.error(token, message); synchronize(); return(new ParseError()); }
private void scanToken() { char c = advance(); switch (c) { case '(': addToken(TokenType.LEFT_PAREN); break; case ')': addToken(TokenType.RIGHT_PAREN); break; case '{': addToken(TokenType.LEFT_BRACE); break; case '}': addToken(TokenType.RIGHT_BRACE); break; case ',': addToken(TokenType.COMMA); break; case '.': addToken(TokenType.DOT); break; case '-': addToken(TokenType.MINUS); break; case '+': addToken(TokenType.PLUS); break; case ';': addToken(TokenType.SEMICOLON); break; case '*': addToken(TokenType.STAR); break; case '?': addToken(TokenType.QUEST); break; case ':': addToken(TokenType.COLON); break; case '!': addToken(match('=')? TokenType.BANG_EQUAL: TokenType.BANG); break; case '=': addToken(match('=')? TokenType.EQUAL_EQUAL: TokenType.EQUAL); break; case '<': addToken(match('=')? TokenType.LESS_EQUAL: TokenType.LESS); break; case '>': addToken(match('=')? TokenType.GREATER_EQUAL: TokenType.GREATER); break; case '/': if (match('/')) { while (peek() != '\n' && !isAtEnd()) { advance(); } } else { addToken(TokenType.SLASH); } break; case ' ': case '\r': case '\t': break; case '\n': line++; break; case '"': scanString(); break; default: if (isDigit(c)) { scanNumber(); } else if (isAlpha(c)) { scanIdentifier(); } else { Lox.error(line, $"Unexpected character '{c}'"); }; break; } }