Exemple #1
0
        /// <summary>
        /// <para>Handles *expression* "==" *expression</para>
        /// <para>*expression* "!=" *expression*</para>
        /// </summary>
        /// <returns></returns>
        private ASTExpressionBase ParseExpression4()
        {
            ASTExpressionBase expression = ParseExpression5();

            while (Match(TokenType.EQUALS_EQUALS) || Match(TokenType.NOT_EQUALS))
            {
                switch (_buffer[0].Type)
                {
                case TokenType.EQUALS_EQUALS:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression5();
                    expression = new ASTCompare(ASTCompare.OperationType.EQUALS_EQUALS, expression, expressionRight);
                }
                break;

                case TokenType.NOT_EQUALS:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression5();
                    expression = new ASTCompare(ASTCompare.OperationType.NOT_EQUALS, expression, expressionRight);
                }
                break;
                }
            }

            return(expression);
        }
Exemple #2
0
        /// <summary>
        /// <para>Handles *expression* "*" *expression*</para>
        /// <para>*expression* "/" *expression*</para>
        /// </summary>
        /// <returns></returns>
        private ASTExpressionBase ParseExpression7()
        {
            ASTExpressionBase expression = ParseExpression8();

            while (Match(TokenType.TIMES) || Match(TokenType.DIVIDE))
            {
                switch (_buffer[0].Type)
                {
                case TokenType.TIMES:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression8();
                    expression = new ASTBinaryMathOperation(ASTBinaryMathOperation.OperationType.TIMES, expression, expressionRight);
                }
                break;

                case TokenType.DIVIDE:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression8();
                    expression = new ASTBinaryMathOperation(ASTBinaryMathOperation.OperationType.DIVIDE, expression, expressionRight);
                }
                break;
                }
            }

            return(expression);
        }
Exemple #3
0
        private ASTStatementBase ParseStatement()
        {
            switch (_buffer[0].Type)
            {
            case TokenType.LEFT_BRACE: return(ParseBlock());

            case TokenType.IF: return(ParseIf());

            case TokenType.WHILE: return(ParseWhile());

            case TokenType.FOR: return(ParseFor());

            case TokenType.SWITCH: return(ParseSwitch());

            case TokenType.BREAK: return(ParseBreak());

            case TokenType.CONTINUE: return(ParseContinue());

            case TokenType.RETURN: return(ParseReturn());

            default:
            {
                ASTExpressionBase expression = ParseExpression();
                Require(TokenType.SEMICOLON);

                return(new ASTStatementExpression(expression));
            }
            }
        }
Exemple #4
0
        private ASTStatementBase ParseReturn()
        {
            Require(TokenType.RETURN);
            ASTExpressionBase returnExpression = ParseExpression();

            Require(TokenType.SEMICOLON);

            return(new ASTReturn(returnExpression));
        }
Exemple #5
0
        /// <summary>
        /// Handles *leftValue* "=" *expression* (assignment)
        /// *variable* "+=" *expression*
        /// *variable* "-=" *expression*
        /// *variable* *= *expression*
        /// *variable* /= *expression*
        /// </summary>
        /// <returns></returns>
        private ASTExpressionBase ParseExpression1()
        {
            ASTExpressionBase expression = ParseExpression2();

            while (Match(TokenType.EQUALS) || Match(TokenType.PLUS_EQUALS) || Match(TokenType.MINUS_EQUALS) || Match(TokenType.TIMES_EQUALS) || Match(TokenType.DIVIDE_EQUALS))
            {
                if (expression.Type != ExpressionType.IDENTIFIER)
                {
                    throw new ParserException("left side of an assignment must be a variable.", _lexer.Line, _lexer.Character);
                }
                switch (_buffer[0].Type)
                {
                case TokenType.EQUALS:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression1();
                    expression = GetASTAssignment(ASTAssignment.AssignmentType.ASSIGNMENT, (expression as ASTIdentifier).Name, expressionRight, expression as ASTMemberAccess);
                }
                break;

                case TokenType.PLUS_EQUALS:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression1();
                    expression = GetASTAssignment(ASTAssignment.AssignmentType.ADDITION, (expression as ASTIdentifier).Name, expressionRight, expression as ASTMemberAccess);
                }
                break;

                case TokenType.MINUS_EQUALS:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression1();
                    expression = GetASTAssignment(ASTAssignment.AssignmentType.SUBTRACTION, (expression as ASTIdentifier).Name, expressionRight, expression as ASTMemberAccess);
                }
                break;

                case TokenType.TIMES_EQUALS:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression1();
                    expression = GetASTAssignment(ASTAssignment.AssignmentType.MULTIPLICATION, (expression as ASTIdentifier).Name, expressionRight, expression as ASTMemberAccess);
                }
                break;

                case TokenType.DIVIDE_EQUALS:
                {
                    Consume();
                    ASTExpressionBase expressionRight = ParseExpression1();
                    expression = GetASTAssignment(ASTAssignment.AssignmentType.DIVISION, (expression as ASTIdentifier).Name, expressionRight, expression as ASTMemberAccess);
                }
                break;
                }
            }

            return(expression);
        }
Exemple #6
0
        /// <summary>
        /// Handles *expression* "&&" *expression* (and)
        /// </summary>
        /// <returns></returns>
        private ASTExpressionBase ParseExpression3()
        {
            ASTExpressionBase expression = ParseExpression4();

            while (Match(TokenType.AND))
            {
                Consume();
                ASTExpressionBase expressionRight = ParseExpression4();
                expression = new ASTCompare(ASTCompare.OperationType.AND, expression, expressionRight);
            }

            return(expression);
        }
Exemple #7
0
        /// <summary>
        /// Handles *expression* "," *expression*
        /// </summary>
        /// <returns></returns>
        private ASTExpressionBase ParseExpression()
        {
            ASTExpressionBase        expression     = ParseExpression1();
            List <ASTExpressionBase> expressionList = new List <ASTExpressionBase>();

            expressionList.Add(expression);

            while (Match(TokenType.COMMA))
            {
                expressionList.Add(ParseExpression1());
            }

            return(new ASTExpressionBase(expressionList));
        }
Exemple #8
0
        private ASTStatementBase ParseWhile()
        {
            Require(TokenType.WHILE);
            Require(TokenType.LEFT_PARENTHESIS);

            ASTExpressionBase condition = ParseExpression();

            Require(TokenType.RIGHT_PARENTHESIS);

            _loopLevel++;
            ASTStatementBase body = ParseStatement();

            _loopLevel--;

            return(new ASTWhile(condition, body));
        }
Exemple #9
0
 private ASTAssignment GetASTAssignment(ASTAssignment.AssignmentType type, string variable,
                                        ASTExpressionBase expression, ASTMemberAccess memberAccess)
 {
     if (!_insideClass)
     {
         if (memberAccess != null)
         {
             // assigning a member variable from outside the class
             return(new ASTMemberAssignmentInstance(type, variable, expression, memberAccess.InstanceName));
         }
         else
         {
             // assigning a local variable
             return(new ASTAssignment(type, variable, expression));
         }
     }
     else
     {
         // assigning a member variable from inside the class
         return(new ASTMemberAssignment(type, variable, expression));
     }
 }
Exemple #10
0
        private ASTStatementBase ParseFor()
        {
            Require(TokenType.FOR);
            Require(TokenType.LEFT_PARENTHESIS);

            ASTExpressionBase initializer = ParseExpression();

            Require(TokenType.SEMICOLON);

            ASTExpressionBase condition = ParseExpression();

            Require(TokenType.SEMICOLON);

            ASTExpressionBase incrementer = ParseExpression();

            Require(TokenType.RIGHT_PARENTHESIS);

            _loopLevel++;
            ASTStatementBase body = ParseStatement();

            _loopLevel--;

            return(new ASTFor(initializer, condition, incrementer, body));
        }
Exemple #11
0
        private ASTStatementBase ParseIf()
        {
            Require(TokenType.IF);
            Require(TokenType.LEFT_PARENTHESIS);

            ASTExpressionBase condition = ParseExpression();

            Require(TokenType.RIGHT_PARENTHESIS);

            ASTStatementBase ifPart   = ParseStatement();
            ASTStatementBase elsePart = null;

            if (Match(TokenType.ELSE))
            {
                Consume();
                elsePart = ParseStatement();
            }

            if (elsePart == null)
            {
                return(new ASTIf(condition, ifPart));
            }
            return(new ASTIf(condition, ifPart, elsePart));
        }
Exemple #12
0
        /// <summary>
        /// <para>Handles *identifier* "[" *tableKey* "]"</para>
        /// <para>*identifier* "(" *argumentList* ")"</para>
        /// <para>*identifier* -> *identifier* "(" *argumentList* ")"</para>
        /// </summary>
        /// <returns></returns>
        private ASTExpressionBase ParseExpression9()
        {
            ASTExpressionBase expression = ParseExpression10();

            while (Match(TokenType.LEFT_PARENTHESIS) || Match(TokenType.ARROW) || Match(TokenType.LEFT_BRACKET))
            {
                switch (_buffer[0].Type)
                {
                case TokenType.LEFT_BRACKET:
                {
                    Consume();
                    if (expression.Type != ExpressionType.IDENTIFIER)
                    {
                        throw new ParserException($"Table expected.", _lexer.Line, _lexer.Character);
                    }

                    var indexes = new List <ASTExpressionBase>();
                    while (!Match(TokenType.RIGHT_BRACKET))
                    {
                        indexes.Add(ParseExpression1());

                        if (Match(TokenType.COMMA))
                        {
                            Consume();
                        }
                    }
                    Require(TokenType.RIGHT_BRACKET);
                    expression = new ASTTableGet(expression, indexes);
                }
                break;

                case TokenType.LEFT_PARENTHESIS:
                {
                    Consume();
                    if (expression.Type != ExpressionType.IDENTIFIER)
                    {
                        throw new ParserException($"Function call expected.", _lexer.Line, _lexer.Character);
                    }

                    List <ASTExpressionBase> arguments = new List <ASTExpressionBase>();

                    while (!Match(TokenType.RIGHT_PARENTHESIS))
                    {
                        arguments.Add(ParseExpression1());

                        if (Match(TokenType.COMMA))
                        {
                            Consume();
                        }
                    }

                    Require(TokenType.RIGHT_PARENTHESIS);

                    expression = new ASTGlobalFunctionCall((expression as ASTIdentifier).Name, arguments);
                }
                break;

                case TokenType.ARROW:
                {
                    Consume();
                    if (expression.Type != ExpressionType.IDENTIFIER)
                    {
                        throw new ParserException($"class object expected.", _lexer.Line, _lexer.Character);
                    }

                    string memberName = Require(TokenType.IDENTIFIER).Text;

                    if (!Match(TokenType.LEFT_PARENTHESIS))
                    {
                        // return class variable
                        expression = new ASTMemberAccess(memberName, (expression as ASTIdentifier).Name);
                        break;
                    }

                    Require(TokenType.LEFT_PARENTHESIS);
                    List <ASTExpressionBase> arguments = new List <ASTExpressionBase>();

                    while (!Match(TokenType.RIGHT_PARENTHESIS))
                    {
                        arguments.Add(ParseExpression1());

                        if (Match(TokenType.COMMA))
                        {
                            Consume();
                        }
                    }

                    Require(TokenType.RIGHT_PARENTHESIS);

                    expression = new ASTMemberFunctionCall(memberName, (expression as ASTIdentifier).Name, arguments);
                }
                break;
                }
            }

            return(expression);
        }
Exemple #13
0
        private ASTStatementBase ParseSwitch()
        {
            Require(TokenType.SWITCH);

            if (_switchLevel > 0)
            {
                throw new ParserException("Nested switch statements are currently not supported.", _lexer.Line, _lexer.Character);
            }

            Require(TokenType.LEFT_PARENTHESIS);

            ASTExpressionBase check = ParseExpression();

            Require(TokenType.RIGHT_PARENTHESIS);

            Require(TokenType.LEFT_BRACE);

            ASTSwitch switchStatement = new ASTSwitch(check);

            while (!Match(TokenType.RIGHT_BRACE))
            {
                if (Match(TokenType.END_OF_FILE))
                {
                    throw new ParserException("'}' expected!", _lexer.Line, _lexer.Character);
                }

                if (Match(TokenType.DEFAULT))
                {
                    Require(TokenType.DEFAULT);
                    Require(TokenType.COLON);
                    _switchLevel++;
                    switchStatement.AddCase(null, ParseStatement());
                    _switchLevel--;
                    if (!Match(TokenType.RIGHT_BRACE))
                    {
                        throw new ParserException("A default case must be the final case of a switch statement.", _lexer.Line, _lexer.Character);
                    }
                    break;
                }

                Require(TokenType.CASE);
                ASTExpressionBase _case = ParseExpression();
                if (_case == null)
                {
                    throw new ParserException("Identifier expected.", _lexer.Line, _lexer.Character);
                }

                Require(TokenType.COLON);

                if (Match(TokenType.CASE) || Match(TokenType.DEFAULT))
                {
                    switchStatement.AddCase(_case, null);
                }
                else
                {
                    _switchLevel++;
                    switchStatement.AddCase(_case, ParseStatement());
                    _switchLevel--;
                }

                /* for now, I don't think forcing the scripter to use braces to have a "break;" after a case is necessary, eg. in the situation of
                 * case 5:
                 * {
                 *  print("hello");
                 *  break;
                 * }
                 *
                 * you might as well just type
                 * case 5:
                 *  print("hello");
                 *  break;
                 */
                if (Match(TokenType.BREAK))                                                   // so let's allow that
                {
                    Consume();                                                                // consume 'break'
                    Require(TokenType.SEMICOLON);                                             // require ';'
                    var currentCase = switchStatement.Cases[switchStatement.Cases.Count - 1]; // get statement of current case
                    // and add the 'break' to the end of it
                    switchStatement.Cases[switchStatement.Cases.Count - 1] = (currentCase.expression,
                                                                              new ASTBlock(new List <ASTStatementBase>
                    {
                        currentCase.statement, new ASTBreak()
                    }));
                }
            }

            Require(TokenType.RIGHT_BRACE);

            if (switchStatement.Cases.Count == 0)
            {
                throw new ParserException("Empty switch statements are not allowed.", _lexer.Line, _lexer.Character);
            }

            return(switchStatement);
        }
Exemple #14
0
        /// <summary>
        /// <para>Handles "{" *key = value* list "}"</para>
        /// <para>"(" *expression* ")"</para>
        /// <para>*identifier*</para>
        /// <para>*number*</para>
        /// <para>*string*</para>
        /// <para>"null"</para>
        /// <para>"true"</para>
        /// <para>"false"</para>
        /// </summary>
        /// <returns></returns>
        private ASTExpressionBase ParseExpression10()
        {
            switch (_buffer[0].Type)
            {
            case TokenType.LEFT_BRACE:
            {
                Consume();

                ASTTable table = new ASTTable();
                while (!Match(TokenType.RIGHT_BRACE))
                {
                    bool good = true;
                    if (Match(TokenType.LEFT_BRACKET))        // [key] = value
                    {
                        Consume();
                        if (!Match(TokenType.NUMBER) && !Match(TokenType.STRING))
                        {
                            throw new ParserException("Expected string or number key for table.", _lexer.Line, _lexer.Character);
                        }
                        ASTExpressionBase key = ParseExpression10();
                        Require(TokenType.RIGHT_BRACKET);

                        Require(TokenType.EQUALS);

                        ASTExpressionBase value = ParseExpression2();
                        good = table.InsertValue(key, value);
                    }
                    else
                    {
                        ASTExpressionBase key = ParseExpression2();
                        if (key.Type == ExpressionType.IDENTIFIER)        // key = expvalue || value
                        {
                            if (Match(TokenType.EQUALS))
                            {
                                Require(TokenType.EQUALS);
                                ASTExpressionBase value = ParseExpression2();
                                good = table.InsertValue(key, value);
                            }
                            else         // expvalue
                            {
                                good = table.InsertValue(null, key);
                            }
                        }
                        else         // value (no key)
                        {
                            good = table.InsertValue(null, key);
                        }
                    }

                    if (!good)
                    {
                        throw new ParserException("Invalid key/value pair for table (possible duplicate?).", _lexer.Line, _lexer.Character);
                    }

                    if (Match(TokenType.COMMA))
                    {
                        Consume();
                    }
                }

                table.NormalizeValues();
                Require(TokenType.RIGHT_BRACE);
                return(table);
            }

            case TokenType.LEFT_PARENTHESIS:
            {
                Consume();
                ASTExpressionBase expression = ParseExpression1();
                Require(TokenType.RIGHT_PARENTHESIS);
                return(expression);
            }

            case TokenType.IDENTIFIER:
            {
                var variable = Require(TokenType.IDENTIFIER).Text;
                return(new ASTIdentifier(variable));
            }

            case TokenType.NUMBER:
            {
                double num = Require(TokenType.NUMBER).Number;
                return(new ASTNumber(num));
            }

            case TokenType.STRING:
            {
                var str = Require(TokenType.STRING).Text;
                return(new ASTString(str));
            }

            case TokenType.NULL:
            {
                Consume();
                return(new ASTNull());
            }

            case TokenType.TRUE:
            {
                Consume();
                return(new ASTTrue());
            }

            case TokenType.FALSE:
            {
                Consume();
                return(new ASTFalse());
            }

            case TokenType.COUNT:
            {
                Consume();
                var identifier = Require(TokenType.IDENTIFIER).Text;
                return(new ASTCount(identifier));
            }

            default:
                throw new ParserException("Primary expression expected", _lexer.Line, _lexer.Character);
            }
        }