public void Apply(DeltinScriptParser.Call_parametersContext context) { PickyParameter[] inputParameters = ParametersFromContext(context); // Compare parameter counts. if (!SetParameterCount(inputParameters.Length)) { return; } // Match overloads. OverloadMatch[] matches = new OverloadMatch[CurrentOptions.Count]; for (int i = 0; i < matches.Length; i++) { matches[i] = MatchOverload(CurrentOptions[i], inputParameters, context); } // Choose the best option. OverloadMatch bestOption = BestOption(matches); Values = bestOption.OrderedParameters.Select(op => op?.Value).ToArray(); ParameterRanges = bestOption.OrderedParameters.Select(op => op?.ExpressionRange).ToArray(); GetAdditionalData(); }
private void CheckAccessLevel(OverloadMatch match) { if (!SemanticsHelper.AccessLevelMatches(match.Option.AccessLevel, match.Option.ContainingType, _parseInfo.ThisType)) { _parseInfo.Script.Diagnostics.Error(string.Format("'{0}' is inaccessable due to its access level.", Overload.GetLabel(_parseInfo.TranslateInfo, LabelInfo.OverloadError)), _targetRange); } }
private OverloadMatch BestOption(OverloadMatch[] matches) { // If there are any methods with no errors, set that as the best option. OverloadMatch bestOption = matches.FirstOrDefault(match => !match.HasError) ?? matches.FirstOrDefault(match => !match.HasDeterminingError); if (bestOption != null) { Overload = bestOption.Option; } else { bestOption = matches.First(match => match.Option == Overload); } // Add the diagnostics of the best option. bestOption.AddDiagnostics(parseInfo.Script.Diagnostics); CheckAccessLevel(); for (int i = 0; i < bestOption.OrderedParameters.Length; i++) { if (bestOption.Option.Parameters[i].Type is PortableLambdaType portableLambda && bestOption.OrderedParameters[i].Value is ILambdaApplier applier) { applier.GetLambdaStatement(portableLambda); } } return(bestOption); }
public FunctionInvokeResult(ParseInfo parseInfo, DocRange targetRange, bool usedAsExpression, IMethod function, IExpression[] parameterValues, object[] additionalParameterData, OverloadMatch match) { Function = function; ParameterValues = parameterValues; AdditionalParameterData = additionalParameterData; _match = match; _parseInfo = parseInfo; _targetRange = targetRange; _usedAsExpression = usedAsExpression; _asyncInfo = parseInfo.AsyncInfo; }
private bool ExtractInferredGenerics(OverloadMatch match, CodeType parameterType, CodeType expressionType) { if (expressionType is UnknownLambdaType) { // A second pass will be required. match.InferSuccessful = false; return(false); } bool result = true; // If the parameter type is an AnonymousType, add the link for the expression type if it doesn't already exist. if (parameterType is AnonymousType pat && pat.Context == match.Option.Trackee) { var typeLinker = match.TypeArgLinker; // If the AnonymousType does not exist in the links, add a new link. if (!typeLinker.Links.ContainsKey(pat)) { typeLinker.Links.Add(pat, expressionType); // Add to the generics array if the generics were not provided. if (!_genericsProvided) { match.TypeArgs[match.Option.TypeArgIndexFromAnonymousType(pat)] = expressionType; } } // Otherwise, the link exists. If the expression type is not equal to the link type, add an error. else if (!expressionType.Is(typeLinker.Links[pat])) { match.InferSuccessful = result = false; } } // Recursively match generics. for (int i = 0; i < parameterType.Generics.Length; i++) { // Make sure the expression's type's structure is usable. if (i < expressionType.Generics.Length) { // Recursively check the generics. if (!ExtractInferredGenerics(match, parameterType.Generics[i], expressionType.Generics[i])) { result = false; } } else if (parameterType.Generics[i].Attributes.ContainsGenerics) { match.InferSuccessful = result = false; } } return(result); }
private OverloadMatch BestOption(OverloadMatch[] matches) { // If there are any methods with no errors, set that as the best option. OverloadMatch bestOption = matches.FirstOrDefault(match => !match.HasError) ?? matches.FirstOrDefault(match => !match.HasDeterminingError); if (bestOption != null) { Overload = bestOption.Option; } else { bestOption = matches.First(match => match.Option == Overload); } // Add the diagnostics of the best option. bestOption.AddDiagnostics(parseInfo.Script.Diagnostics); CheckAccessLevel(); return(bestOption); }
private OverloadMatch BestOption(OverloadMatch[] matches) { // If there are any methods with no errors, set that as the best option. OverloadMatch bestOption = matches.FirstOrDefault(match => !match.HasError) ?? matches.FirstOrDefault(match => !match.HasDeterminingError); if (bestOption != null) { Overload = bestOption.Option; } else { bestOption = matches.First(match => match.Option == Overload); } // Add the diagnostics of the best option. bestOption.AddDiagnostics(parseInfo.Script.Diagnostics); CheckAccessLevel(); // Apply the lambdas and method group parameters. // Iterate through each parameter. for (int i = 0; i < bestOption.OrderedParameters.Length; i++) { // If the CodeParameter type is a lambda type, get the lambda statement with it. if (bestOption.Option.Parameters[i].Type is PortableLambdaType portableLambda) { bestOption.OrderedParameters[i].LambdaInfo?.FinishAppliers(portableLambda); } // Otherwise, get the lambda statement with the default. else { bestOption.OrderedParameters[i].LambdaInfo?.FinishAppliers(); } } return(bestOption); }
private OverloadMatch MatchOverload(IParameterCallable option, PickyParameter[] inputParameters, DeltinScriptParser.Call_parametersContext context) { PickyParameter lastPicky = null; OverloadMatch match = new OverloadMatch(option); match.OrderedParameters = new PickyParameter[option.Parameters.Length]; // Iterate through the option's parameters. for (int i = 0; i < inputParameters.Length; i++) { if (inputParameters[i].ParameterOrdered(option.Parameters[i])) { // If the picky parameters end but there is an additional picky parameter, throw a syntax error. if (lastPicky != null && inputParameters[i].Name == null) { match.Error($"Named argument '{lastPicky.Name}' is used out-of-position but is followed by an unnamed argument", lastPicky.NameRange); } else { match.OrderedParameters[i] = inputParameters[i]; // Next contextual parameter if (i == inputParameters.Length - 1 && i < option.Parameters.Length - 1) { match.LastContextualParameterIndex = i + 1; } } } else { // Picky parameter ends. lastPicky = inputParameters[i]; // Set relevant picky parameter. bool nameFound = false; for (int p = 0; p < option.Parameters.Length && !nameFound; p++) { if (inputParameters[i].Name == option.Parameters[p].Name) { match.OrderedParameters[p] = inputParameters[i]; nameFound = true; } } // If the named argument's name is not found, throw an error. if (!nameFound) { match.Error($"Named argument '{lastPicky.Name}' does not exist in the function '{option.GetLabel(false)}'.", inputParameters[i].NameRange); } } } // Compare parameter types. for (int i = 0; i < match.OrderedParameters.Length; i++) { match.CompareParameterTypes(i); } // Get the missing parameters. match.GetMissingParameters(genericErrorRange, ErrorMessages, context, CallRange); return(match); }
private OverloadMatch BestOption() { // If there are any methods with no errors, set that as the best option. OverloadMatch bestOption = _matches.FirstOrDefault(match => !match.HasError) ?? _matches.FirstOrDefault(); // Apply the lambdas and method group parameters. // Iterate through each parameter. for (int i = 0; i < bestOption.OrderedParameters.Length; i++) { // If the CodeParameter type is a lambda type, get the lambda statement with it. if (bestOption.Option.Parameters[i].GetCodeType(_parseInfo.TranslateInfo) is PortableLambdaType portableLambda) { bestOption.OrderedParameters[i].LambdaInfo?.FirstPass((PortableLambdaType)portableLambda.GetRealType(bestOption.TypeArgLinker)); } // Otherwise, get the lambda statement with the default. else { bestOption.OrderedParameters[i].LambdaInfo?.FirstPass(); } } // Type-arg inference will need a second pass after we apply the lambdas, // since lambda types are not known until we apply them. if (!bestOption.InferSuccessful) { bool secondPass = true; // Extract inferred generics (again) for (int i = 0; i < bestOption.OrderedParameters.Length; i++) { var parameterValue = bestOption.OrderedParameters[i].Value; if (parameterValue != null) { secondPass = secondPass && ExtractInferredGenerics( bestOption, bestOption.Option.Parameters[i].GetCodeType(_parseInfo.TranslateInfo), parameterValue.Type()); } } // Update the inference status. Will be true if ExtractInferredGenerics returned true with every iteration. secondPass = secondPass && bestOption.TypeArgLinkerCompleted; bestOption.InferSuccessful = secondPass; bestOption.UpdateAllParameters(); // Clear the match's TypeArgLinker. if (!secondPass) { bestOption.TypeArgLinker = InstanceAnonymousTypeLinker.Empty; } } // Finalize lambdas for (int i = 0; i < bestOption.OrderedParameters.Length; i++) { // If the CodeParameter type is a lambda type, get the lambda statement with it. if (bestOption.Option.Parameters[i].GetCodeType(_parseInfo.TranslateInfo) is PortableLambdaType portableLambda) { bestOption.OrderedParameters[i].LambdaInfo?.SecondPass((PortableLambdaType)portableLambda.GetRealType(bestOption.TypeArgLinker)); } // Otherwise, get the lambda statement with the default. else { bestOption.OrderedParameters[i].LambdaInfo?.SecondPass(); } } // Add the diagnostics of the best option. bestOption.AddDiagnostics(_parseInfo.Script.Diagnostics); CheckAccessLevel(bestOption); return(bestOption); }
private OverloadMatch MatchOverload(IOverload option, PickyParameter[] inputParameters, List <ParameterValue> context) { PickyParameter lastPicky = null; // If the generics were provided ('_genericsProvided'), get the type linker from the option. OverloadMatch match = new OverloadMatch(option, _genericsProvided ? option.GetTypeLinker(_generics) : null, _parseInfo, _targetRange); match.OrderedParameters = new PickyParameter[option.Parameters.Length]; // Check type arg count. if (_genericsProvided && _generics.Length != option.TypeArgCount) { match.IncorrectTypeArgCount(_parseInfo.TranslateInfo, _targetRange); } // Iterate through the option's parameters. for (int i = 0; i < inputParameters.Length; i++) { // Out of range if (i >= option.Parameters.Length) { if (i == option.Parameters.Length) { match.Error(string.Format(_errorMessages.BadParameterCount, inputParameters.Length), _targetRange); } continue; } // Non-picky else if (inputParameters[i].ParameterOrdered(option.Parameters[i])) { // If the picky parameters end but there is an additional picky parameter, throw a syntax error. if (lastPicky != null && inputParameters[i].Name == null) { match.Error($"Named argument '{lastPicky.Name}' is used out-of-position but is followed by an unnamed argument", lastPicky.NameRange); } else { match.OrderedParameters[i] = inputParameters[i]; // If _genericsFilled is false, get context-inferred type arguments. if (!_genericsProvided) { ExtractInferredGenerics(match, option.Parameters[i].GetCodeType(_parseInfo.TranslateInfo), inputParameters[i].Value.Type()); } // Next contextual parameter if (i == inputParameters.Length - 1 && i < option.Parameters.Length - 1) { match.LastContextualParameterIndex = i + 1; } } } else // Picky { // Picky parameter ends. lastPicky = inputParameters[i]; // Set relevant picky parameter. bool nameFound = false; for (int p = 0; p < option.Parameters.Length && !nameFound; p++) { if (inputParameters[i].Name == option.Parameters[p].Name) { // A matching parameter was found. match.OrderedParameters[p] = inputParameters[i]; nameFound = true; // If _genericsFilled is false, get context-inferred type arguments. if (!_genericsProvided) { ExtractInferredGenerics(match, option.Parameters[p].GetCodeType(_parseInfo.TranslateInfo), inputParameters[i].Value.Type()); } } } // If the named argument's name is not found, throw an error. if (!nameFound) { match.Error($"Named argument '{lastPicky.Name}' does not exist in the function '{option.GetLabel(_parseInfo.TranslateInfo, LabelInfo.OverloadError)}'.", inputParameters[i].NameRange); } } } // Compare parameter types. match.UpdateAllParameters(); // Make sure every type arg was accounted for. if (!_genericsProvided && !match.TypeArgLinkerCompleted) { match.InferSuccessful = false; } // Get the missing parameters. match.GetMissingParameters(_errorMessages, context, _targetRange, CallRange); return(match); }