private void CharString() { while (Peek() != '\'' && !IsAtEnd()) { if (Peek() == '\\') { Advance(); } if (Peek() == '\n') { Line++; } Advance(); } // Unterminated string. if (IsAtEnd()) { Cox.Error(Line, "Unterminated string."); return; } // The closing ". Advance(); // Trim the surrounding quotes. String value = Source.Substring(Start + 1, Current - Start - 1); AddToken(TokenType.STRING, value); }
public String String() { while (Peek() != '"' && !IsAtEnd()) { if (Peek() == '\\') { Advance(); } if (Peek() == '\n') { Line++; } Advance(); } // Unterminated string. if (IsAtEnd()) { Cox.Error(Line, "Unterminated string."); return(null); } // The closing ". Advance(); // Trim the surrounding quotes. return(Source.Substring(Start + 1 , Current - Start - 2)); }
public object VisitThisExpr(This expr) { if (currentClass == ClassType.NONE) { Cox.Error(expr.Keyword, "Cannot use 'this' outside of a class."); } else { ResolveLocal(expr, expr.Keyword); } return(null); }
public object VisitVariableExpr(Variable expr) { if (scopes.Count > 0) { if (scopes.Peek().ContainsKey(expr.Name.Lexeme) && scopes.Peek()[expr.Name.Lexeme] == false) { Cox.Error(expr.Name, "Cannot read local variable in its own initializer."); } } ResolveLocal(expr, expr.Name); return(null); }
public object VisitSuperExpr(Super expr) { if (currentClass == ClassType.NONE) { Cox.Error(expr.Keyword, "Cannot use 'super' outside of a class."); } else if (currentClass != ClassType.SUBCLASS) { Cox.Error(expr.Keyword, "Cannot use 'super' in a class with no superclass."); } else { ResolveLocal(expr, expr.Keyword); } return(null); }
public void Interpret(List <Stmt> statements, Dictionary <Expr, Int32> locals) { Locals = locals; try { foreach (Stmt statement in statements) { Execute(statement); } } catch (RuntimeError error) { Cox.RuntimeError(error); } }
private void Declare(Token name) { // Don't need to track top level variables. if (scopes.Count == 0) { return; } Dictionary <String, Boolean> scope = scopes.Peek(); if (scope.ContainsKey(name.Lexeme)) { Cox.Error(name, "Variable with this name already Declared in this scope."); } scope.Add(name.Lexeme, false); }
public object VisitReturnStmt(Return stmt) { if (currentFunction == FunctionType.NONE) { Cox.Error(stmt.Keyword, "Cannot return from top-level code."); } if (stmt.Value != null) { if (currentFunction == FunctionType.INITIALIZER) { Cox.Error(stmt.Keyword, "Cannot return a value from an initializer."); } Resolve(stmt.Value); } return(null); }
protected override void ScanToken() { Char c = Advance(); switch (c) { case '[': AddToken(TokenType.LSQRBRACE); // TODO break; case ']': AddToken(TokenType.RSQRBRACE); // TODO break; case '$': AddToken(TokenType.DOLLAR); if (Match('"')) { var value = String().Substring(1); // Strip of the leading quote var scanner = new StringInterpolationScanner(value); var t = scanner.Scan(); Tokens.AddRange(t); } else { Cox.Error(Line, $"Expected '\"'"); } break; case '(': AddToken(TokenType.LPAREN); break; case ')': AddToken(TokenType.RPAREN); break; case '{': AddToken(TokenType.LBRACE); break; case '}': AddToken(TokenType.RBRACE); break; case ',': AddToken(TokenType.COMMA); break; case '.': AddToken(TokenType.DOT); break; case '-': if (Match('-')) { AddToken(TokenType.MINUS_MINUS); } else { if (Match('=')) { AddToken(TokenType.MINUS_EQUALS); } else { AddToken(TokenType.MINUS); } } break; case '+': if (Match('+')) { AddToken(TokenType.PLUS_PLUS); } else { if (Match('=')) { AddToken(TokenType.PLUS_EQUALS); } else { AddToken(TokenType.PLUS); } } break; case '*': if (Match('=')) { AddToken(TokenType.MUL_EQUALS); } else { AddToken(TokenType.MUL); } break; case '/': if (Match('=')) { AddToken(TokenType.DIV_EQUALS); } else { if (Match('/')) { // A comment goes until the end of the line. while (Peek() != '\n' && !IsAtEnd()) { Advance(); } } else { if (Match('*')) { // Multi line comment, we need to look for a */ while (!(Peek() == '*' && PeekNext() == '/') && !IsAtEnd()) { if (Peek() == '\n') { Line++; } Advance(); } if (IsAtEnd()) { Cox.Error(Line, $"End-of-File found, '*/' expected"); } else { Advance(); Advance(); } } else { AddToken(TokenType.DIV); } } } break; case ';': AddToken(TokenType.SEMICOLON); break; case ':': AddToken(TokenType.COLON); break; case '?': AddToken(TokenType.QUESTIONMARK); break; case '&': if (Match('&')) { AddToken(TokenType.AND); } else { AddToken(TokenType.BINARY_AND); } break; case '|': if (Match('|')) { AddToken(TokenType.OR); } else { AddToken(TokenType.BINARY_OR); } break; case '^': AddToken(TokenType.BINARY_XOR); break; case '~': AddToken(TokenType.BINARY_NOT); break; case '!': AddToken(Match('=') ? TokenType.BANG_EQUAL : TokenType.BANG); break; case '=': AddToken(Match('=') ? TokenType.EQUAL_EQUAL : TokenType.EQUAL); break; case '<': if (Match('<')) { AddToken(TokenType.BINARY_LEFTSHIFT); } else if (Match('=')) { AddToken(TokenType.LESS_EQUAL); } else { AddToken(TokenType.LESS); } break; case '>': if (Match('>')) { AddToken(TokenType.BINARY_RIGHTSHIFT); } else if (Match('=')) { AddToken(TokenType.GREATER_EQUAL); } else { AddToken(TokenType.GREATER); } break; case '"': { String value = String(); if (value != null) { AddToken(TokenType.STRING, value); } } break; case ' ': case '\t': case '\r': break; case '\n': Line++; break; default: if (Char.IsDigit(c)) { Number(); } else if (Char.IsLetter(c) || c == '_') { Identifier(); } else { Cox.Error(Line, $"Unexpected Character {c}"); } break; } }
private ParseError Error(Token token, String message) { Cox.Error(token, message); return(new ParseError()); }