Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
 public void interpret(List <Stmt> statements)
 {
     try
     {
         foreach (Stmt statement in statements)
         {
             execute(statement);
         }
     }
     catch (RuntimeError error)
     {
         Jingle.runtimeError(error);
     }
 }
Beispiel #4
0
        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);
        }
Beispiel #5
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.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);
        }
Beispiel #6
0
        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);
            }
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #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.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;
            }
        }
Beispiel #10
0
 private ParseError error(Token token, string message)
 {
     Jingle.Error(token, message);
     return(new ParseError());
 }