/// <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); }
/// <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); } }
/// <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); }
/// <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); } }
/// <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); } } }
/// <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 }); }
/// <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); }
/// <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); }
/// <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)); }
/// <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); } } }
/// <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); } } }
/// <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()); }
/// <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); } } }
/// <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); }