public object visitThisExpr(Expr.This expr) { if (currentClass == ClassType.NONE) { Jingle.Error(expr.keyword, "Cannot use 'this' outside of a class."); return(null); } resolveLocal(expr, expr.keyword); return(null); }
public object visitVariableExpr(Expr.Variable expr) { if (scopes.Count > 0 && scopes[scopes.Count - 1].ContainsKey(expr.name.lexeme)) { if (scopes[scopes.Count - 1][expr.name.lexeme] == false) { Jingle.Error(expr.name, "Cannot read local variable in its own initializer."); } } resolveLocal(expr, expr.name); return(null); }
public void interpret(List <Stmt> statements) { try { foreach (Stmt statement in statements) { execute(statement); } } catch (RuntimeError error) { Jingle.runtimeError(error); } }
public object visitSuperExpr(Expr.Super expr) { if (currentClass == ClassType.NONE) { Jingle.Error(expr.keyword, "Cannot use 'super' outside of a class."); } else if (currentClass != ClassType.SUBCLASS) { Jingle.Error(expr.keyword, "Cannot use 'super' in a class with no superclass."); } resolveLocal(expr, expr.keyword); 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.Equals(stmt.superclass.name.lexeme)) { Jingle.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[scopes.Count - 1].Add("super", true); } beginScope(); scopes[scopes.Count - 1].Add("this", true); foreach (Stmt.Function method in stmt.methods) { FunctionType declaration = FunctionType.METHOD; if (method.name.lexeme.Equals("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 < 1) { return; } Dictionary <string, bool> scope = scopes[scopes.Count - 1]; if (scope.ContainsKey(name.lexeme)) { Jingle.Error(name, "Variable with this name already declared in this scope."); } else { scope.Add(name.lexeme, false); } }
public object visitReturnStmt(Stmt.Return stmt) { if (currentFunction == FunctionType.NONE) { Jingle.Error(stmt.keyword, "Cannot return from top-level code."); } if (stmt.value != null) { if (currentFunction == FunctionType.INITIALIZER) { Jingle.Error(stmt.keyword, "Cannot return a value from an initializer."); } resolve(stmt.value); } return(null); }
private void string_() { while (peek() != '"' && !isAtEnd()) { if (peek() == '\n') { line++; } advance(); } if (isAtEnd()) { Jingle.Error(line, "Unterminated string."); return; } advance(); string value = source.Substring(start + 1, current - start - 2); addToken(TokenType.STRING, value); }
private void scanToken() { char c = advance(); switch (c) { case '(': addToken(TokenType.LEFT_PAREN); break; case ')': addToken(TokenType.RIGHT_PAREN); break; case ':': addToken(TokenType.COLON); 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.MODULO); break; case '#': while (peek() != '\n' && !isAtEnd()) { advance(); } 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('/')) { addToken(TokenType.INTDIV); } else { addToken(TokenType.SLASH); } break; case ' ': case '\r': case '\t': break; case '\n': line++; break; case '"': string_(); break; default: if (isDigit(c)) { number(); } else if (isAlpha(c)) { identifier(); } else { Jingle.Error(line, "Unexpected character."); } break; } }
private ParseError error(Token token, string message) { Jingle.Error(token, message); return(new ParseError()); }