Пример #1
0
        /// <summary>
        /// Parse an expression.
        /// </summary>
        /// <param name="isRequired">Defines whether the expression is expected or not and throw an exception if it is required but not parsed.</param>
        /// <param name="expectedEndToken">Defines the expected tokens that defines the end of the expression.</param>
        /// <returns>An expression</returns>
        private Expression ParseExpression(bool isRequired, params TokenType[] expectedEndToken)
        {
            if (TokenIdentificationHelper.IsOperator(CurrentToken))
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.CannotStartWithOperator));
            }

            if (isRequired && TokenIdentificationHelper.IsStatementSeparator(CurrentToken))
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.NotValid));
            }

            var expression = ParseConditionalOrExpression(isRequired);

            if (expression == null && isRequired)
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.NotValid));
            }

            if (expectedEndToken.Any() && expression != null)
            {
                if (expectedEndToken.All(token => token != CurrentToken.TokenType))
                {
                    var expectedEndTokenStrings = new List <string>();
                    foreach (var token in expectedEndToken)
                    {
                        expectedEndTokenStrings.Add(token.GetDescription());
                    }
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.FormattedEndTokenExpected(string.Join("', '", expectedEndTokenStrings))));
                }
            }

            return(expression);
        }
Пример #2
0
        /// <summary>
        /// Try to parse a return statement.
        ///
        /// Corresponding grammar :
        ///     'RETURN' Expression?
        /// </summary>
        /// <returns>If succeed, returns a <see cref="ReturnStatement"/>.</returns>
        private ReturnStatement ParseReturnStatement()
        {
            var returnToken = CurrentToken;

            DiscardToken(TokenType.Return);

            var returnedValue = ParseExpression(false, TokenIdentificationHelper.GetStatementSeparatorsTokens());

            if (TokenIdentificationHelper.IsStatementSeparator(CurrentToken))
            {
                DiscardToken();
                return(new ReturnStatement(returnedValue)
                {
                    Line = returnToken.Line,
                    Column = returnToken.Column,
                    StartOffset = returnToken.StartOffset,
                    NodeLength = returnToken.ParsedLength
                });
            }
            else
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                return(null);
            }
        }
Пример #3
0
        /// <summary>
        /// Parse the access to a member. It could be a property or a method. This method only returns the parsed member name. The caller method will determines whether this member is a property of method invocation.
        ///
        /// Corresponding grammar :
        ///     '.' Identifier
        /// </summary>
        /// <returns>Returns a member name.</returns>
        private string ParseMemberAccessPart(bool isExpected)
        {
            if (CurrentToken.TokenType == TokenType.Dot)
            {
                var identifier = NextToken.Value;
                DiscardToken();
                if (CurrentToken.TokenType != TokenType.Identifier && CurrentToken.TokenType != TokenType.Exception)
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.ReferenceExpected));
                }
                else
                {
                    DiscardToken();
                    TokenIdentificationHelper.CheckIdentifier(identifier, PreviousToken, false, _issues);
                    return(identifier);
                }
            }

            if (isExpected)
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.MemberAccessExpected));
            }

            return(string.Empty);
        }
Пример #4
0
        /// <summary>
        /// Try to parse a break statement.
        ///
        /// Corresponding grammar :
        ///     'BREAK'
        /// </summary>
        /// <returns>If succeed, returns a <see cref="BreakStatement"/>.</returns>
        private BreakStatement ParseBreakStatement()
        {
            if (GetDoLoopIndicator() < 1)
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.InvalidBreak));
            }

            var breakToken = CurrentToken;

            DiscardToken(TokenType.Break);

            if (TokenIdentificationHelper.IsStatementSeparator(CurrentToken))
            {
                DiscardToken();
                return(new BreakStatement()
                {
                    Line = breakToken.Line,
                    Column = breakToken.Column,
                    StartOffset = breakToken.StartOffset,
                    NodeLength = breakToken.ParsedLength
                });
            }
            else
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                return(null);
            }
        }
Пример #5
0
        /// <summary>
        /// Try to parse a try catch statement.
        ///
        /// Corresponding grammar:
        ///     'TRY'
        ///         Statement_List
        ///     'CATCH'?
        ///         Statement_List
        ///     'END' 'TRY'
        /// </summary>
        /// <returns>If succeed, returns a <see cref="TryCatchStatement"/>.</returns>
        private TryCatchStatement ParseTryCatchStatement()
        {
            var tryCatchToken = CurrentToken;

            DiscardToken(TokenType.Try);
            DiscardToken(TokenType.NewLine);

            var tryStatements = ParseStatements(false, TokenType.Catch, TokenType.End);

            if (CurrentToken.TokenType == TokenType.Catch)
            {
                IncreaseCatchIndicator();
                DiscardToken(TokenType.Catch);
                DiscardToken(TokenType.NewLine);
                var catchStatements = ParseStatements(false, TokenType.End);
                DiscardToken(TokenType.End);
                DiscardToken(TokenType.Try);
                DecreaseCatchIndicator();
                if (TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
                {
                    DiscardToken();
                    return(new TryCatchStatement()
                    {
                        Line = tryCatchToken.Line,
                        Column = tryCatchToken.Column,
                        StartOffset = tryCatchToken.StartOffset,
                        NodeLength = tryCatchToken.ParsedLength
                    }
                           .WithTryBody(tryStatements)
                           .WithCatchBody(catchStatements));
                }
                else
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                    return(null);
                }
            }
            else
            {
                DiscardToken(TokenType.End);
                DiscardToken(TokenType.Try);
                if (TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
                {
                    DiscardToken();
                    return(new TryCatchStatement()
                    {
                        Line = tryCatchToken.Line,
                        Column = tryCatchToken.Column,
                        StartOffset = tryCatchToken.StartOffset,
                        NodeLength = tryCatchToken.ParsedLength
                    }
                           .WithTryBody(tryStatements));
                }
                else
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                    return(null);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Parse a namespace and/or a full type name.
        ///
        /// Corresponding grammar :
        ///     Identifier Member_Access*
        /// </summary>
        /// <returns>Returns a namespace and/or type name represented by a <see cref="ClassReferenceExpression"/>.</returns>
        private ClassReferenceExpression ParseNamespaceOrTypeName()
        {
            if (CurrentToken.TokenType != TokenType.Identifier)
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.TypeExpected));
            }

            var memberPart      = string.Empty;
            var typeFullName    = string.Empty;
            var identifierToken = CurrentToken;

            TokenIdentificationHelper.CheckIdentifier(CurrentToken.Value, CurrentToken, false, _issues);
            typeFullName += CurrentToken.Value;
            DiscardToken();

            var typeNameFound = false;

            do
            {
                memberPart = ParseMemberAccessPart(false);
                if (!string.IsNullOrEmpty(memberPart))
                {
                    typeFullName += "." + memberPart;
                }
                else
                {
                    typeNameFound = true;
                }
            } while (!typeNameFound);

            var @namespace = string.Empty;
            var className  = string.Empty;
            var typeLimit  = typeFullName.LastIndexOf(".", StringComparison.Ordinal);

            if (typeLimit != -1)
            {
                @namespace = typeFullName.Substring(0, typeLimit);
                className  = typeFullName.Substring(typeLimit + 1);
            }
            else
            {
                return(null);
            }

            return(new ClassReferenceExpression(@namespace, className)
            {
                Line = identifierToken.Line,
                Column = identifierToken.Column,
                StartOffset = identifierToken.StartOffset,
                NodeLength = identifierToken.ParsedLength
            });
        }
Пример #7
0
        /// <summary>
        /// Parse a parameter declaration.
        ///
        /// Corresponding grammar:
        ///     Identifier ('[]')?
        /// </summary>
        /// <returns>Returns a parameter declaration if it is found, or a null value.</returns>
        private ParameterDeclaration ParseParameterDeclaration()
        {
            if (CurrentToken.TokenType == TokenType.Identifier)
            {
                var identifierToken = CurrentToken;
                var parameterName   = string.Empty;
                var parameterArray  = false;

                TokenIdentificationHelper.CheckIdentifier(CurrentToken.Value, CurrentToken, false, _issues);
                parameterName = CurrentToken.Value;
                DiscardToken();

                if (CurrentToken.TokenType == TokenType.LeftBracket)
                {
                    DiscardToken();
                    DiscardToken(TokenType.RightBracket);
                    parameterArray = true;
                }

                var parameterDeclaration = new ParameterDeclaration(parameterName, parameterArray)
                {
                    Line        = identifierToken.Line,
                    Column      = identifierToken.Column,
                    StartOffset = identifierToken.StartOffset,
                    NodeLength  = identifierToken.ParsedLength
                };
                AddParameter(parameterDeclaration);
                return(parameterDeclaration);
            }
            else if (CurrentToken.TokenType != TokenType.RightParenth)
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.UnexpectedOrMissingCharacter));
            }

            return(null);
        }
Пример #8
0
        /// <summary>
        /// Parse an expression that can be either a primitive value, a variable reference, an expression between parenthesis or instantiation.
        ///
        /// Corresponding grammar :
        ///     Primitive_Value
        ///     | Identifier
        ///     | '(' Expression ')'
        ///     | 'NEW' (Bracket_Expressio | Namespace_Or_Type_Name Method_Invocation)
        /// </summary>
        /// <param name="isRequired">Defines whether it is required/expected to parse an expression. If true, throw an exception if no expression is parsed.</param>
        /// <returns>Returns an expression that corresponds to a primitive value, a variable reference, an expression between parenthesis or instantiation.</returns>
        private Expression ParsePrimaryExpressionStart(bool isRequired)
        {
            if (TokenIdentificationHelper.IsPrimitiveValue(CurrentToken))
            {
                return(ParsePrimitiveExpression());
            }
            else if (CurrentToken.TokenType == TokenType.Exception)
            {
                var exceptionToken = CurrentToken;
                if (GetCatchIndicator() < 1)
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.IllegalExceptionKeyword));
                }
                DiscardToken();
                return(new ExceptionReferenceExpression()
                {
                    Line = exceptionToken.Line,
                    Column = exceptionToken.Column,
                    StartOffset = exceptionToken.StartOffset,
                    NodeLength = exceptionToken.ParsedLength
                });
            }
            else if (CurrentToken.TokenType == TokenType.Identifier)
            {
                var identifierToken = CurrentToken;
                TokenIdentificationHelper.CheckIdentifier(CurrentToken.Value, CurrentToken, false, _issues);
                var variableReference = new VariableReferenceExpression(CurrentToken.Value)
                {
                    Line        = identifierToken.Line,
                    Column      = identifierToken.Column,
                    StartOffset = identifierToken.StartOffset,
                    NodeLength  = identifierToken.ParsedLength
                };

                if (NextToken.TokenType != TokenType.LeftParenth)
                {
                    // We validate the variable reference only if it looks like it's not a method invocation.
                    if (ValidateVariableReferenceExpression(variableReference, throwIssueForVariableNotFound: false) == null)
                    {
                        // If the variable does not exists, it's maybe a reference to a Class.
                        return(ParseStaticPropertyOrMethod());
                    }
                }

                DiscardToken();
                return(variableReference);
            }
            else if (CurrentToken.TokenType == TokenType.LeftParenth)
            {
                DiscardToken();
                var expression = ParseExpression(true, TokenType.RightParenth);
                DiscardToken(TokenType.RightParenth);
                return(expression);
            }
            else if (CurrentToken.TokenType == TokenType.New)
            {
                DiscardToken();

                if (CurrentToken.TokenType == TokenType.LeftBracket)
                {
                    // Array creation
                    var bracketToken      = CurrentToken;
                    var bracketExpression = ParseBracketExpression();
                    return(new ArrayCreationExpression()
                    {
                        Line = bracketToken.Line,
                        Column = bracketToken.Column,
                        StartOffset = bracketToken.StartOffset,
                        NodeLength = bracketToken.ParsedLength
                    }
                           .WithValues(bracketExpression));
                }
                else
                {
                    // Type creation
                    var typeName = ParseNamespaceOrTypeName();

                    if (typeName == null)
                    {
                        AddIssue(new BaZicParserException(PreviousToken.Line, PreviousToken.Column, PreviousToken.StartOffset, PreviousToken.ParsedLength, L.BaZic.Parser.Expressions.TypeExpected));
                    }

                    if (CurrentToken.TokenType != TokenType.LeftParenth)
                    {
                        AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.InstantiateExpectParenths));
                    }

                    var arguments = ParseMethodInvocation();
                    return(new InstantiateExpression(typeName)
                    {
                        Line = typeName.Line,
                        Column = typeName.Column,
                        StartOffset = typeName.StartOffset,
                        NodeLength = typeName.NodeLength
                    }
                           .WithParameters(arguments));
                }
            }
            else if (TokenIdentificationHelper.IsStatementSeparator(CurrentToken) && isRequired)
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.ExpressionOnOneLine));
            }

            return(null);
        }
Пример #9
0
        /// <summary>
        /// Try to parse a method delcaration statement.
        ///
        /// Corresponding grammar :
        ///     'EXTERN'? ('ASYNC' | 'EVENT')? 'FUNCTION' Identifier '(' Parameter_List ')'
        ///         Statement_List
        ///     'END' 'FUNCTION'
        /// </summary>
        /// <returns>If succeed, returns a <see cref="VariableDeclaration"/>.</returns>
        private MethodDeclaration ParseMethodDeclaration()
        {
            var isAsync  = false;
            var isEvent  = false;
            var isExtern = false;

            if (CurrentToken.TokenType == TokenType.Extern)
            {
                isExtern = true;
                DiscardToken();
            }

            if (CurrentToken.TokenType == TokenType.Async)
            {
                if (NextToken.TokenType == TokenType.Event)
                {
                    AddIssue(new BaZicParserException(NextToken.Line, NextToken.Column, NextToken.StartOffset, NextToken.ParsedLength, L.BaZic.Parser.Statements.AsyncEvent));
                }

                isAsync = true;
                DiscardToken();
            }
            else if (CurrentToken.TokenType == TokenType.Event)
            {
                if (NextToken.TokenType == TokenType.Async)
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.AsyncEvent));
                }

                isEvent = true;
                DiscardToken();
            }

            DiscardToken(TokenType.Function);

            var identifierToken = CurrentToken;
            var methodName      = CurrentToken.Value;

            TokenIdentificationHelper.CheckIdentifier(methodName, CurrentToken, isEvent, _issues);
            DiscardToken();

            DiscardToken(TokenType.LeftParenth);
            var methodParameters = ParseParameterList();

            DiscardToken(TokenType.RightParenth);

            if (!TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
            }

            if (isEvent && methodParameters.Length != 0)
            {
                AddIssue(new BaZicParserException(identifierToken.Line, identifierToken.Column, identifierToken.StartOffset, identifierToken.ParsedLength, L.BaZic.Parser.Statements.EventNoParameter));
            }

            while (TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
            {
                DiscardToken();
            }

            var statements = ParseStatements(false, TokenType.End);

            DiscardToken(TokenType.End);
            DiscardToken(TokenType.Function);
            var endToken = PreviousToken;

            if (TokenIdentificationHelper.IsStatementSeparator(CurrentToken))
            {
                DiscardToken();
            }
            else
            {
                AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
            }

            if (string.Compare(methodName, Consts.EntryPointMethodName, StringComparison.Ordinal) == 0) // The name is case sensitive.
            {
                if (!isExtern)
                {
                    AddIssue(new BaZicParserException(identifierToken.Line, identifierToken.Column, identifierToken.StartOffset, identifierToken.ParsedLength, L.BaZic.Parser.Statements.ExternEntryPoint));
                }
                if (isAsync)
                {
                    AddIssue(new BaZicParserException(identifierToken.Line, identifierToken.Column, identifierToken.StartOffset, identifierToken.ParsedLength, L.BaZic.Parser.Statements.AsyncEntryPoint));
                }
                if (isEvent)
                {
                    AddIssue(new BaZicParserException(identifierToken.Line, identifierToken.Column, identifierToken.StartOffset, identifierToken.ParsedLength, L.BaZic.Parser.Statements.EventEntryPoint));
                }

                if (methodParameters.Length != 1)
                {
                    AddIssue(new BaZicParserException(identifierToken.Line, identifierToken.Column, identifierToken.StartOffset, identifierToken.ParsedLength, L.BaZic.Parser.Statements.UniqueArgumentEntryPoint));
                }
                else if (!methodParameters.Single().IsArray)
                {
                    AddIssue(new BaZicParserException(identifierToken.Line, identifierToken.Column, identifierToken.StartOffset, identifierToken.ParsedLength, L.BaZic.Parser.Statements.EntryPointArgumentArrayExpected));
                }

                var entryPointDeclaration = new EntryPointMethod()
                {
                    Line        = identifierToken.Line,
                    Column      = identifierToken.Column,
                    StartOffset = identifierToken.StartOffset,
                    NodeLength  = identifierToken.ParsedLength,
                    EndOffset   = endToken.StartOffset + endToken.ParsedLength
                }
                .WithParameters(methodParameters);

                AddMethod(entryPointDeclaration, false);

                return(entryPointDeclaration.WithBody(statements));
            }

            var methodDeclaration = new MethodDeclaration(methodName, isAsync, isExtern)
            {
                Line        = identifierToken.Line,
                Column      = identifierToken.Column,
                StartOffset = identifierToken.StartOffset,
                NodeLength  = identifierToken.ParsedLength,
                EndOffset   = endToken.StartOffset + endToken.ParsedLength
            }
            .WithParameters(methodParameters);

            AddMethod(methodDeclaration, isEvent);

            return(methodDeclaration.WithBody(statements));
        }
Пример #10
0
        /// <summary>
        /// Try to parse a assign or expression statement.
        ///
        /// Corresponding grammar :
        ///     Expression ('=' Expression)?
        /// </summary>
        /// <returns>If succeed, returns a <see cref="AssignStatement"/> or <see cref="ExpressionStatement"/>.</returns>
        private Statement ParseAssignOrExpressionStatement()
        {
            var leftExpressionLine         = CurrentToken.Line;
            var leftExpressionColumn       = CurrentToken.Column;
            var leftExpressionStartOffset  = CurrentToken.StartOffset;
            var leftExpressionParsedLength = CurrentToken.ParsedLength;

            var expression = ParseExpression(false, TokenIdentificationHelper.GetStatementSeparatorsTokens());

            if (expression == null)
            {
                return(null);
            }
            else
            {
                Statement statement = null;

                if (expression is BinaryOperatorExpression binaryOperatorExpression)
                {
                    if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality)
                    {
                        if (!(binaryOperatorExpression.LeftExpression is IAssignable))
                        {
                            AddIssue(new BaZicParserException(leftExpressionLine, leftExpressionColumn, leftExpressionStartOffset, leftExpressionParsedLength, L.BaZic.Parser.Statements.NotAssignable));
                        }

                        var assignStatement = new AssignStatement(binaryOperatorExpression.LeftExpression, binaryOperatorExpression.RightExpression)
                        {
                            Line        = leftExpressionLine,
                            Column      = leftExpressionColumn,
                            StartOffset = leftExpressionStartOffset,
                            NodeLength  = leftExpressionParsedLength
                        };

                        ValidateAssignStatement(assignStatement);
                        statement = assignStatement;
                    }
                    else
                    {
                        AddIssue(new BaZicParserException(leftExpressionLine, leftExpressionColumn, leftExpressionStartOffset, leftExpressionParsedLength, L.BaZic.Parser.Statements.AssignOrCallExpected));
                        return(null);
                    }
                }
                else
                {
                    if (expression is IAssignable)
                    {
                        AddIssue(new BaZicParserException(leftExpressionLine, leftExpressionColumn, leftExpressionStartOffset, leftExpressionParsedLength, L.BaZic.Parser.Statements.AssignOrCallExpected));
                    }
                    statement = new ExpressionStatement(expression)
                    {
                        Line        = leftExpressionLine,
                        Column      = leftExpressionColumn,
                        StartOffset = leftExpressionStartOffset,
                        NodeLength  = leftExpressionParsedLength
                    };
                }

                if (TokenIdentificationHelper.IsStatementSeparator(CurrentToken))
                {
                    DiscardToken();
                    return(statement);
                }
                else
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                    return(null);
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Try to parse a condition statement.
        ///
        /// Corresponding grammar:
        ///     'IF' Expression 'THEN'
        ///         Statement_List
        ///     'ELSE'?
        ///         Statement_List
        ///     'END' 'IF'
        /// </summary>
        /// <returns>If succeed, returns a <see cref="ConditionStatement"/>.</returns>
        private ConditionStatement ParseConditionStatement()
        {
            var ifToken = CurrentToken;

            DiscardToken(TokenType.If);
            var conditionExpression = ParseExpression(true, TokenType.Then);

            DiscardToken(TokenType.Then);
            DiscardToken(TokenType.NewLine);

            var trueStatements = ParseStatements(false, TokenType.Else, TokenType.End);

            if (CurrentToken.TokenType == TokenType.Else)
            {
                DiscardToken(TokenType.Else);
                DiscardToken(TokenType.NewLine);
                var falseStatements = ParseStatements(false, TokenType.End);
                DiscardToken(TokenType.End);
                DiscardToken(TokenType.If);
                if (TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
                {
                    DiscardToken();
                    return(new ConditionStatement(conditionExpression)
                    {
                        Line = ifToken.Line,
                        Column = ifToken.Column,
                        StartOffset = ifToken.StartOffset,
                        NodeLength = ifToken.ParsedLength
                    }
                           .WithThenBody(trueStatements)
                           .WithElseBody(falseStatements));
                }
                else
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                    return(null);
                }
            }
            else
            {
                DiscardToken(TokenType.End);
                DiscardToken(TokenType.If);
                if (TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
                {
                    DiscardToken();
                    return(new ConditionStatement(conditionExpression)
                    {
                        Line = ifToken.Line,
                        Column = ifToken.Column,
                        StartOffset = ifToken.StartOffset,
                        NodeLength = ifToken.ParsedLength
                    }
                           .WithThenBody(trueStatements));
                }
                else
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                    return(null);
                }
            }
        }
Пример #12
0
        /// <summary>
        /// Parse statements.
        /// </summary>
        /// <param name="methodOrControlAccessorDeclarationAllowed">Defines whether a method or control accessor can be declared in the current block.</param>
        /// <param name="expectedEndTokens">Defines the expected tokens that defines the end of a statement.</param>
        /// <returns>Returns a list of parsed statements.</returns>
        private Statement[] ParseStatements(bool methodOrControlAccessorDeclarationAllowed, params TokenType[] expectedEndTokens)
        {
            var statements = new List <Statement>();

            EnteringScope();

            if (methodOrControlAccessorDeclarationAllowed)
            {
                _controlAccessors.AddRange(AddControlAccessors());

                foreach (var controlAccessor in _controlAccessors)
                {
                    ValidateControlsAccessors(controlAccessor);
                }
            }

            while (expectedEndTokens.All(token => token != CurrentToken.TokenType) && CurrentToken.TokenType != TokenType.EndCode)
            {
                if (!TokenIdentificationHelper.IsStatementSeparator(PreviousToken))
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.StatementExpected));
                }

                while (TokenIdentificationHelper.IsStatementSeparator(CurrentToken) && CurrentToken.TokenType != TokenType.EndCode)
                {
                    DiscardToken();
                }

                switch (CurrentToken.TokenType)
                {
                case TokenType.Variable:
                    statements.Add(ParseVariableDeclaration());
                    break;

                case TokenType.Do:
                    statements.Add(ParseLoopStatement());
                    break;

                case TokenType.If:
                    statements.Add(ParseConditionStatement());
                    break;

                case TokenType.Try:
                    statements.Add(ParseTryCatchStatement());
                    break;

                case TokenType.Throw:
                    statements.Add(ParseThrowStatement());
                    break;

                case TokenType.Return:
                    statements.Add(ParseReturnStatement());
                    break;

                case TokenType.Break:
                    statements.Add(ParseBreakStatement());
                    break;

                case TokenType.Breakpoint:
                    statements.Add(ParseBreakpointStatement());
                    break;

                case TokenType.Async:
                case TokenType.Event:
                case TokenType.Extern:
                case TokenType.Function:
                    if (!methodOrControlAccessorDeclarationAllowed)
                    {
                        AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.InvalidMethodDeclaration));
                    }

                    statements.Add(ParseMethodDeclaration());
                    break;

                default:
                    var statement = ParseAssignOrExpressionStatement();
                    if (statement != null)
                    {
                        statements.Add(statement);
                    }
                    else if (expectedEndTokens.All(token => token != CurrentToken.TokenType) && CurrentToken.TokenType != TokenType.EndCode)
                    {
                        AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.InvalidStatement));
                        DiscardToken();
                    }
                    break;
                }
            }

            ExitingScope();

            return(statements.ToArray());
        }
Пример #13
0
        /// <summary>
        /// Try to parse a loop iteration statement.
        ///
        /// Corresponding grammar:
        ///     'DO' ('WHILE' Expression)?
        ///         Statement_List
        ///     'LOOP' ('WHILE' Expression)?
        /// </summary>
        /// <returns>If succeed, returns a <see cref="IterationStatement"/>.</returns>
        private IterationStatement ParseLoopStatement()
        {
            var doToken = CurrentToken;

            DiscardToken(TokenType.Do);

            if (CurrentToken.TokenType == TokenType.While)
            {
                // DO WHILE () ... LOOP
                DiscardToken(TokenType.While);

                var conditionExpression = ParseExpression(true, TokenIdentificationHelper.GetStatementSeparatorsTokens());

                DiscardToken(TokenType.NewLine);
                IncreaseDoLoopIndicator();
                var statements = ParseStatements(false, TokenType.Loop);
                DecreaseDoLoopIndicator();

                DiscardToken(TokenType.Loop);

                if (TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
                {
                    DiscardToken();
                    return(new IterationStatement(conditionExpression, false)
                    {
                        Line = doToken.Line,
                        Column = doToken.Column,
                        StartOffset = doToken.StartOffset,
                        NodeLength = doToken.ParsedLength
                    }
                           .WithBody(statements));
                }
                else
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                    return(null);
                }
            }
            else
            {
                // DO ... LOOP WHILE
                DiscardToken(TokenType.NewLine);
                IncreaseDoLoopIndicator();
                var statements = ParseStatements(false, TokenType.Loop);
                DecreaseDoLoopIndicator();

                DiscardToken(TokenType.Loop);
                DiscardToken(TokenType.While);

                var conditionExpression = ParseExpression(true, TokenIdentificationHelper.GetStatementSeparatorsTokens());

                if (TokenIdentificationHelper.IsStatementSeparatorButNotEndCode(CurrentToken))
                {
                    DiscardToken();
                    return(new IterationStatement(conditionExpression, true)
                    {
                        Line = doToken.Line,
                        Column = doToken.Column,
                        StartOffset = doToken.StartOffset,
                        NodeLength = doToken.ParsedLength
                    }
                           .WithBody(statements));
                }
                else
                {
                    AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.LineExpected));
                    return(null);
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Try to parse a variable delcaration statement.
        ///
        /// Corresponding grammar :
        ///     'VARIABLE' Identifier '[]'? ('=' Expression)?
        /// </summary>
        /// <returns>If succeed, returns a <see cref="VariableDeclaration"/> statement.</returns>
        private Statement ParseVariableDeclaration()
        {
            DiscardToken(TokenType.Variable);

            var        identifierToken      = CurrentToken;
            var        variableName         = CurrentToken.Value;
            var        variableIsArray      = false;
            Expression variableDefaultValue = null;

            TokenIdentificationHelper.CheckIdentifier(variableName, CurrentToken, false, _issues);
            DiscardToken();

            if (CurrentToken.TokenType == TokenType.LeftBracket)
            {
                DiscardToken();
                DiscardToken(TokenType.RightBracket);
                variableIsArray = true;
            }

            if (CurrentToken.TokenType == TokenType.Equal)
            {
                DiscardToken();
                var line         = CurrentToken.Line;
                var column       = CurrentToken.Column;
                var startOffset  = CurrentToken.StartOffset;
                var parsedLength = CurrentToken.ParsedLength;
                variableDefaultValue = ParseExpression(true, TokenIdentificationHelper.GetStatementSeparatorsTokens());

                if (variableDefaultValue != null)
                {
                    if (variableIsArray && (variableDefaultValue.GetType() == typeof(BinaryOperatorExpression) || variableDefaultValue.GetType() == typeof(PrimitiveExpression) || variableDefaultValue.GetType() == typeof(ClassReferenceExpression) || variableDefaultValue.GetType() == typeof(ExceptionReferenceExpression) || variableDefaultValue.GetType() == typeof(InstantiateExpression) || variableDefaultValue.GetType() == typeof(NotOperatorExpression)))
                    {
                        AddIssue(new BaZicParserException(line, column, startOffset, parsedLength, L.BaZic.Parser.Statements.FormattedDefaultValueArrayExpected(variableName)));
                    }
                    else if (!variableIsArray && variableDefaultValue.GetType() == typeof(ArrayCreationExpression))
                    {
                        AddIssue(new BaZicParserException(line, column, startOffset, parsedLength, L.BaZic.Parser.Statements.FormattedDefaultValueNoArrayExpected(variableName)));
                    }
                    else if (variableDefaultValue.GetType() == typeof(VariableReferenceExpression))
                    {
                        ValidateVariableReferenceExpression((VariableReferenceExpression)variableDefaultValue, variableIsArray);
                    }
                }
            }

            if (TokenIdentificationHelper.IsStatementSeparator(CurrentToken))
            {
                DiscardToken();
                var variableDeclaration = new VariableDeclaration(variableName, variableIsArray);
                variableDeclaration.WithDefaultValue(variableDefaultValue);
                variableDeclaration.Line        = identifierToken.Line;
                variableDeclaration.Column      = identifierToken.Column;
                variableDeclaration.StartOffset = identifierToken.StartOffset;
                variableDeclaration.NodeLength  = identifierToken.ParsedLength;

                AddVariableToScope(variableDeclaration, false);

                return(variableDeclaration);
            }

            AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Statements.AssignOrLineExpected));
            return(null);
        }