private void MultiLineComment() { // we start inside a multi-line comment. // but it could be nested while ((Peek() == '*' && PeekNext() == '/') == false && !isAtEnd()) { // Move through the body of the multi if (Peek() == '\n') { Line++; } // We are already in a comment so eating chars is safe // We start this method INSIDE the comment. if (Match('/') && Match('*')) { MultiLineComment(); } Advance(); } if (isAtEnd()) { CSLox.Error(this.Line, "Unterminated multi-line comment"); } Advance(); Advance(); }
public Unit VisitVariableExpr(Expr.Variable expr) { if (_Scopes.Count != 0 && _Scopes[_Scopes.Count - 1].ContainsKey(expr.Name.Lexeme) && _Scopes[_Scopes.Count - 1][expr.Name.Lexeme] == false) { CSLox.Error(expr.Name, "Can't read local variable in it own initalizer."); } ResolveLocal(expr, expr.Name); return(new Unit()); }
public void Interpret(Expr expression) { try { Object value = Evaluate(expression); Console.WriteLine(Stringfy(value)); } catch (RuntimeError ex) { CSLox.RuntimeError(ex); } }
private void Declare(Token name) { if (_Scopes.Count == 0) { return; } Dictionary <string, bool> scope = _Scopes[_Scopes.Count - 1]; if (scope.ContainsKey(name.Lexeme)) { CSLox.Error(name, "Already a variabled with this name in this scope ."); } scope.Add(name.Lexeme, false); }
private void String() { while (Peek() != '"' && !isAtEnd()) { if (Peek() == '\n') { Line++; } Advance(); } if (isAtEnd()) { CSLox.Error(Line, "Unterminated string"); return; } Advance(); // ignore the surrounding quotes! var value = Source.Substring(Start + 1, (Current - 1) - (Start + 1)); 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.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.QUESTION); break; case ':': AddToken(TokenType.SEMICOLON); 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('/')) { // A comment goes until the end of a line. while (Peek() != '\n' && !isAtEnd()) { Advance(); } } else if (Match('*')) { MultiLineComment(); } else { AddToken(TokenType.SLASH); } break; case ' ': case '\r': case '\t': break; // ignoring whitespace and carry on. case '\n': this.Line++; // update the line, and carry on. break; case '"': String(); break; default: if (Char.IsDigit(c)) { Number(); } else if (IsAlpha(c)) { Identifier(); } else { CSLox.Error(this.Line, $"Unexpected Character '{c}'"); } break; } }
private Exception Error(Token token, string message) { CSLox.Error(token, message); return(new ParserError(message)); }