예제 #1
0
        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);
        }