コード例 #1
0
ファイル: Scanner.cs プロジェクト: gajcowan/cox
        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);
        }
コード例 #2
0
ファイル: Scanner.cs プロジェクト: gajcowan/cox
        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));
        }
コード例 #3
0
ファイル: Resolver.cs プロジェクト: gajcowan/cox
 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);
 }
コード例 #4
0
ファイル: Resolver.cs プロジェクト: gajcowan/cox
        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);
        }
コード例 #5
0
ファイル: Resolver.cs プロジェクト: gajcowan/cox
 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);
 }
コード例 #6
0
ファイル: Interpreter.cs プロジェクト: gajcowan/cox
        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);
            }
        }
コード例 #7
0
ファイル: Resolver.cs プロジェクト: gajcowan/cox
        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);
        }
コード例 #8
0
ファイル: Resolver.cs プロジェクト: gajcowan/cox
        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);
        }
コード例 #9
0
ファイル: Scanner.cs プロジェクト: gajcowan/cox
        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;
            }
        }
コード例 #10
0
ファイル: Parser.cs プロジェクト: gajcowan/cox
 private ParseError Error(Token token, String message)
 {
     Cox.Error(token, message);
     return(new ParseError());
 }