/// <summary> /// Analyze a method invocation. /// </summary> /// <param name="invokeMethod">The expression to analyze.</param> private void ValidateCoreMethodInvocation(InvokeCoreMethodExpression invokeMethod) { AnalyzeExpression(invokeMethod.TargetObject); foreach (var argument in invokeMethod.Arguments) { AnalyzeExpression(argument); } }
/// <summary> /// Parse a static reference to a property or a static method invocation. /// /// Corresponding grammar : /// Namespace_Or_Type_Name (Member_Access | Method_Invocation) /// </summary> /// <returns>Returns a <see cref="PropertyReferenceExpression"/> or <see cref="InvokeCoreMethodExpression"/>. Returns null if it doesn't looks like a valid reference or invocation.</returns> private Expression ParseStaticPropertyOrMethod() { var identifierToken = CurrentToken; if (CurrentToken.TokenType != TokenType.Identifier) { AddIssue(new BaZicParserException(CurrentToken.Line, CurrentToken.Column, CurrentToken.StartOffset, CurrentToken.ParsedLength, L.BaZic.Parser.Expressions.TypeExpected)); } var typeName = ParseNamespaceOrTypeName(); if (typeName == null) { AddIssue(new BaZicParserException(identifierToken.Line, identifierToken.Column, identifierToken.StartOffset, identifierToken.ParsedLength, L.BaZic.Optimizer.FormattedUndeclaredName(identifierToken.Value))); return(null); } if (!typeName.Namespace.Contains(".")) { AddIssue(new BaZicParserException(typeName.Line, typeName.Column, typeName.StartOffset, typeName.NodeLength, L.BaZic.Parser.Expressions.FormattedInvalidNamespaceOrVariable(typeName.Namespace))); return(null); } var lastDotIndex = typeName.Namespace.LastIndexOf('.'); var propertyOrMethodName = typeName.ClassName; var className = typeName.Namespace.Substring(lastDotIndex + 1); var @namespace = typeName.Namespace.Substring(0, lastDotIndex); if (CurrentToken.TokenType == TokenType.LeftParenth) { var invocationToken = PreviousToken; var arguments = ParseMethodInvocation(); var methodInvoke = new InvokeCoreMethodExpression(new ClassReferenceExpression(@namespace, className), propertyOrMethodName.Identifier, false) { Line = invocationToken.Line, Column = invocationToken.Column, StartOffset = invocationToken.StartOffset, NodeLength = invocationToken.ParsedLength }; methodInvoke.WithParameters(arguments); ValidateCoreMethodInvocation(methodInvoke); return(methodInvoke); } return(new PropertyReferenceExpression(new ClassReferenceExpression(@namespace, className), propertyOrMethodName.Identifier) { Line = PreviousToken.Line, Column = PreviousToken.Column, StartOffset = PreviousToken.StartOffset, NodeLength = PreviousToken.ParsedLength }); }
/// <summary> /// Generates the code for an <see cref="InvokeCoreMethodExpression"/>. /// </summary> /// <param name="expression">The expression</param> /// <returns>A BaZic code</returns> private string GenerateInvokeCoreMethodExpression(InvokeCoreMethodExpression expression) { Requires.NotNull(expression.TargetObject, nameof(expression.TargetObject)); Requires.NotNull(expression.MethodName, nameof(expression.MethodName)); var targetObject = GenerateReferenceExpression(expression.TargetObject); var arguments = new List <string>(); foreach (var argument in expression.Arguments) { arguments.Add(GenerateExpression(argument)); } var wait = string.Empty; if (expression.Await) { wait = "AWAIT "; } return($"{wait}{targetObject}.{expression.MethodName}({string.Join(", ", arguments)})"); }
/// <summary> /// Parse a part of an expression that can be a reference or primary value followed by an accesser like array indexer or method invocation. /// /// Corresponding grammar : /// Primary_Expression_Start Bracket_Expression* ((Member_Access | Method_Invocation) Bracket_Expression* )* /// </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.</returns> private Expression ParsePrimaryExpression(bool isRequired) { Expression[] bracketExpression = null; var expressionLine = CurrentToken.Line; var expressionColumn = CurrentToken.Column; var expressionStartOffset = CurrentToken.StartOffset; var expressionParsedLength = CurrentToken.ParsedLength; // Primary_Expression_Start var expression = ParsePrimaryExpressionStart(isRequired); // Bracket_Expression * do { var bracketToken = CurrentToken; bracketExpression = ParseBracketExpression(); if (bracketExpression != null) { var referenceExpression = expression as ReferenceExpression; if (referenceExpression == null) { AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.UnexpectedIndexer)); } if (bracketExpression.Length == 0) { AddIssue(new BaZicParserException(bracketToken.Line, bracketToken.Column, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.IndexerExpected)); return(null); } var arrayIndexer = new ArrayIndexerExpression(referenceExpression, bracketExpression) { Line = bracketToken.Line, Column = bracketToken.Column, StartOffset = bracketToken.StartOffset, NodeLength = bracketToken.ParsedLength }; ValidateArrayIndexerExpression(arrayIndexer); expression = arrayIndexer; } } while (bracketExpression != null); // ((Member_Access | Method_Invocation) Bracket_Expression* )* while (CurrentToken.TokenType == TokenType.Dot || CurrentToken.TokenType == TokenType.LeftParenth) { if (CurrentToken.TokenType == TokenType.Dot) { // Member_Access var memberNameToken = CurrentToken; var memberAccess = ParseMemberAccessPart(true); if (!string.IsNullOrEmpty(memberAccess)) { var referenceExpression = expression as ReferenceExpression; if (referenceExpression == null) { AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.IllegalPropertyAccess)); } expression = new PropertyReferenceExpression(referenceExpression, memberAccess) { Line = memberNameToken.Line, Column = memberNameToken.Column + 1, // +1 because we don't want to show a potential error on the dot. StartOffset = memberNameToken.StartOffset + 1, // +1 because we don't want to show a potential error on the dot. NodeLength = memberNameToken.ParsedLength }; } } else if (CurrentToken.TokenType == TokenType.LeftParenth) { // Method_Invocation var methodInvocationParameters = ParseMethodInvocation(); var propertyReferenceExpression = expression as PropertyReferenceExpression; if (expression is VariableReferenceExpression variableReferenceExpression) { var methodInvoke = new InvokeMethodExpression(variableReferenceExpression.Name.ToString(), false) { Line = variableReferenceExpression.Line, Column = variableReferenceExpression.Column, StartOffset = variableReferenceExpression.StartOffset, NodeLength = variableReferenceExpression.NodeLength } .WithParameters(methodInvocationParameters); AddMethodInvocation(methodInvoke); expression = methodInvoke; } else if (propertyReferenceExpression != null) { var methodInvoke = new InvokeCoreMethodExpression(propertyReferenceExpression.TargetObject, propertyReferenceExpression.PropertyName.ToString(), false) { Line = propertyReferenceExpression.Line, Column = propertyReferenceExpression.Column, StartOffset = propertyReferenceExpression.StartOffset, NodeLength = propertyReferenceExpression.NodeLength }; methodInvoke.WithParameters(methodInvocationParameters); ValidateCoreMethodInvocation(methodInvoke); expression = methodInvoke; } else { AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.MethodNameExpected)); } } else { AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.MethodNameExpected)); } // Bracket_Expression* do { var bracketToken = CurrentToken; bracketExpression = ParseBracketExpression(); if (bracketExpression != null) { var referenceExpression = expression as ReferenceExpression; if (referenceExpression == null) { AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.UnexpectedIndexer)); } if (bracketExpression.Length == 0) { AddIssue(new BaZicParserException(bracketToken.Line, bracketToken.Column, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.IndexerExpected)); } var arrayIndexer = new ArrayIndexerExpression(referenceExpression, bracketExpression) { Line = bracketToken.Line, Column = bracketToken.Column, StartOffset = bracketToken.StartOffset, NodeLength = bracketToken.ParsedLength }; ValidateArrayIndexerExpression(arrayIndexer); expression = arrayIndexer; } } while (bracketExpression != null); } return(expression); }