Пример #1
0
 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);
 }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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;
        }
Пример #5
0
 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);
 }
Пример #6
0
 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);
 }
Пример #7
0
        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);
        }
Пример #8
0
 private ParseError error(Token token, string message)
 {
     Lox.error(token, message);
     synchronize();
     return(new ParseError());
 }
Пример #9
0
        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;
            }
        }