예제 #1
0
        private void StringParse()
        {
            while (Peek() != '"' && !isAtEnd())
            {
                if (Peek() == '\n')
                {
                    line++;
                }
                Advance();
            }

            // Unterminated string.
            if (isAtEnd())
            {
                ElizScriptCompiler.Error(line, "Unterminated string.");
                return;
            }

            // The closing ".
            Advance();

            // Trim the surrounding quotes.
            string value = source.Substring(start + 1, current - start - 2);

            AddToken(TokenType.STRING, value);
        }
예제 #2
0
        public Void VisitThisExpr(Expr.This expr)
        {
            if (currentClass == ClassType.NONE)
            {
                ElizScriptCompiler.Error(expr.keyword,
                                         "Cannot use 'this' outside of a class.");
                return(null);
            }

            ResolveLocal(expr, expr.keyword);
            return(null);
        }
예제 #3
0
        public Void VisitClassStmt(Stmt.Class stmt)
        {
            ClassType enclosingClass = currentClass;

            currentClass = ClassType.CLASS;

            Declare(stmt.name);
            Define(stmt.name);

            if (stmt.baseclass != null && stmt.name.Lexeme.Equals(stmt.baseclass.name.Lexeme))
            {
                ElizScriptCompiler.Error(stmt.baseclass.name, "A class cannot inherit from itself.");
            }

            if (stmt.baseclass != null)
            {
                currentClass = ClassType.SUBCLASS;
                Resolve(stmt.baseclass);
            }

            if (stmt.baseclass != null)
            {
                BeginScope();
                scopes.Last()["base"] = true;
            }

            BeginScope();
            scopes.Last()["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.baseclass != null)
            {
                EndScope();
            }

            currentClass = enclosingClass;
            return(null);
        }
예제 #4
0
        public Void VisitBaseExpr(Expr.Base expr)
        {
            if (currentClass == ClassType.NONE)
            {
                ElizScriptCompiler.Error(expr.keyword, "Cannot use 'base' outside of a class.");
            }
            else if (currentClass != ClassType.SUBCLASS)
            {
                ElizScriptCompiler.Error(expr.keyword, "Cannot use 'base' in a class with no baseclass.");
            }

            ResolveLocal(expr, expr.keyword);
            return(null);
        }
예제 #5
0
 public void Interpret(List <Stmt> statements)
 {
     try
     {
         foreach (Stmt statement in statements)
         {
             Execute(statement);
         }
     }
     catch (RuntimeError error)
     {
         ElizScriptCompiler.RuntimeError(error);
     }
 }
예제 #6
0
        public Void VisitVariableExpr(Expr.Variable expr)
        {
            try
            {
                if (scopes.Count > 0 && scopes.Last()[expr.name.Lexeme] == false)
                {
                    ElizScriptCompiler.Error(expr.name,
                                             "Cannot read local variable in its own initializer.");
                }
            }
            catch { }

            ResolveLocal(expr, expr.name);

            return(null);
        }
예제 #7
0
        void Declare(Token name)
        {
            if (scopes.Count == 0)
            {
                return;
            }

            Dictionary <string, bool> scope = scopes.Last(); /*Peek()*/

            if (scope.ContainsKey(name.Lexeme))
            {
                ElizScriptCompiler.Error(name,
                                         "Variable with this name already declared in this scope.");
            }

            scope[name.Lexeme] = false;
        }
예제 #8
0
        public Void VisitReturnStmt(Stmt.Return stmt)
        {
            if (currentFunction == FunctionType.NONE)
            {
                ElizScriptCompiler.Error(stmt.keyword, "Cannot return from top-level code.");
            }

            if (stmt.value != null)
            {
                if (currentFunction == FunctionType.INITIALIZER)
                {
                    ElizScriptCompiler.Error(stmt.keyword,
                                             "Cannot return a value from an initializer.");
                }

                Resolve(stmt.value);
            }

            return(null);
        }
예제 #9
0
 private ParseError Error(Token token, String message)
 {
     ElizScriptCompiler.Error(token, message);
     return(new ParseError());
 }
예제 #10
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 '/':
                if (Match('/'))
                {
                    // A comment goes until the end of the line.
                    while (Peek() != '\n' && !isAtEnd())
                    {
                        Advance();
                    }
                }
                else
                {
                    AddToken(TokenType.SLASH);
                }
                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 ' ':
            case '\r':
            case '\t':
                // Ignore whitespace.
                break;

            case '\n':
                line++;
                break;

            case '"': StringParse(); break;

            default:
                if (IsDigit(c))
                {
                    NumberParse();
                }
                else if (IsAlpha(c))
                {
                    IdentifierParse();
                }
                else
                {
                    ElizScriptCompiler.Error(line, "Unexpected character.");
                }
                break;
            }
        }