Exemplo n.º 1
0
 void ILSLSyntaxErrorListener.RedefinedStandardLibraryFunction(LSLSourceCodeRange location, string functionName,
                                                               IReadOnlyGenericArray <ILSLFunctionSignature> libraryFunctionSignatureOverloads)
 {
     _errorActionQueue.Enqueue(location.StartIndex,
                               () =>
                               SyntaxErrorListener.RedefinedStandardLibraryFunction(location, functionName,
                                                                                    libraryFunctionSignatureOverloads));
 }
Exemplo n.º 2
0
 void ILSLSyntaxErrorListener.NoSuitableLibraryFunctionOverloadFound(LSLSourceCodeRange location,
                                                                     string functionName,
                                                                     IReadOnlyGenericArray <ILSLReadOnlyExprNode> givenParameterExpressions)
 {
     _errorActionQueue.Enqueue(location.StartIndex,
                               () =>
                               SyntaxErrorListener.NoSuitableLibraryFunctionOverloadFound(location, functionName,
                                                                                          givenParameterExpressions));
 }
Exemplo n.º 3
0
 void ILSLSyntaxErrorListener.CallToOverloadedLibraryFunctionIsAmbiguous(LSLSourceCodeRange location,
                                                                         string functionName,
                                                                         IReadOnlyGenericArray <ILSLFunctionSignature> ambiguousMatches,
                                                                         IReadOnlyGenericArray <ILSLReadOnlyExprNode> givenParameterExpressions)
 {
     _errorActionQueue.Enqueue(location.StartIndex,
                               () =>
                               SyntaxErrorListener.CallToOverloadedLibraryFunctionIsAmbiguous(location, functionName,
                                                                                              ambiguousMatches, givenParameterExpressions));
 }
            public LSLLibraryConstantSignature GetSignature(IReadOnlyGenericArray <string> subsets)
            {
                var f = new LSLLibraryConstantSignature(LSLType.String, Name)
                {
                    DocumentationString = Desc
                };

                f.Subsets.SetSubsets(subsets);
                return(f);
            }
            public LSLLibraryConstantSignature GetSignature(IReadOnlyGenericArray <string> subsets)
            {
                var s = Desc.Split(',');
                var t = s.Length == 3 ? LSLType.Vector : LSLType.Rotation;
                var f = new LSLLibraryConstantSignature(t, Name)
                {
                    DocumentationString = Desc
                };

                f.Subsets.SetSubsets(subsets);
                return(f);
            }
Exemplo n.º 6
0
        /// <exception cref="ArgumentNullException"><paramref name="context" /> is <c>null</c>.</exception>
        internal LSLCompilationUnitNode(LSLParser.CompilationUnitContext context, IReadOnlyGenericArray <LSLComment> comments)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            SourceRange = new LSLSourceCodeRange(context);

            SourceRangesAvailable = true;

            _comments = comments;
        }
Exemplo n.º 7
0
        /// <summary>
        ///     Construct an <see cref="LSLCompilationUnitNode" /> with the provided default state node.
        /// </summary>
        /// <param name="defaultState">The default state node to use for the default state.</param>
        /// <exception cref="ArgumentNullException"><paramref name="defaultState" /> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="defaultState" />.IsDefaultState is <c>false</c>.</exception>
        public LSLCompilationUnitNode(LSLStateScopeNode defaultState)
        {
            if (defaultState == null)
            {
                throw new ArgumentNullException("defaultState");
            }

            if (!defaultState.IsDefaultState)
            {
                throw new ArgumentException("defaultState.IsDefaultState is false", "defaultState");
            }

            DefaultState = defaultState;

            _comments = new GenericArray <LSLComment>();
        }
        /// <summary>
        ///     Find a matching overload from a list of function signatures, given the parameter expressions. return null if none
        ///     is found.
        /// </summary>
        /// <typeparam name="T">The type of <see cref="LSLFunctionSignature"/> derived object to preform matching against.</typeparam>
        /// <param name="typeComparer">
        ///     A function used to compare an <see cref="LSLParameterSignature" /> to another <see cref="ILSLExprNode" /> to check for a
        ///     match.
        ///     Should return true if the <see cref="ILSLExprNode" /> can be passed into the <see cref="LSLParameterSignature" />.
        /// </param>
        /// <param name="functionSignatures">The function signatures to search through.</param>
        /// <param name="expressionNodes">The expression nodes of the function parameters we want to pass and find an overload for.</param>
        /// <returns>A matching <see cref="LSLFunctionSignature" /> overload or null.</returns>
        public static LSLFunctionOverloadMatches <T> MatchOverloads <T>(IReadOnlyGenericArray <T> functionSignatures,
                                                                        IReadOnlyGenericArray <ILSLReadOnlyExprNode> expressionNodes, Func <LSLParameterSignature, ILSLReadOnlyExprNode, bool> typeComparer)
            where T : class, ILSLFunctionSignature
        {
            //discover candidates 'applicable' functions, using a typeComparer function/lambda to compare the signature parameters to the passed expression nodes.
            //anything that could possibly match the signature as an individual non-overloaded function is considered an overload match candidate. (see the TryMatch function of this class)
            //
            //The type comparer is allowed to match signatures with implicit parameter conversions if it wants to.
            //such as for LSL's (key to string) and (string to key) conversion.
            var matches =
                functionSignatures.Where(
                    functionSignature => TryMatch(functionSignature, expressionNodes, typeComparer).Success).ToList();


            //More than one matching signature, we need to tie break.
            if (matches.Count <= 1)
            {
                return(new LSLFunctionOverloadMatches <T>(matches));
            }


            //Prefer function declarations that have no parameters, over function declarations with one variadic parameter.
            if (expressionNodes.Count == 0)
            {
                return(new LSLFunctionOverloadMatches <T>(matches.First(x => x.ParameterCount == 0)));
            }


            //Rank and group the matches by the number implicit type conversions that occur.
            //Implicit conversion is the only real match quality degradation that can occur in LSL.
            var rankingToSignatureGroup = new Dictionary <int, List <T> >();


            foreach (var match in matches)
            {
                //the higher the match ranking, the worse it is.
                int matchRank = 0;

                int idx = 0;

                foreach (var parameter in expressionNodes)
                {
                    //Select the signature parameter to compare, if the expression index 'idx' is greater than a matches parameter count;
                    //Then that match is a variadic function, with the parameters overflowing the parameter count because multiple parameters were passed into the variadic parameter slot.
                    //If this happens, we want to continue comparing the rest of the passed variadic parameters to the type of the last parameter in the match signature, IE. The one that is variadic.
                    var signatureParameterToCompare = idx > (match.ParameterCount - 1)
                        ? match.Parameters.Last()
                        : match.Parameters[idx];

                    //If a type of the passed expression does not exactly equal the signature parameter, but the type comparer says that the expression can actually be passed in anyway.
                    //Then the type that the expression is must be implicitly convertible to the type that the parameter is, an implicit conversion has occurred.  The match quality of the signature has degraded.
                    if (signatureParameterToCompare.Type != parameter.Type &&
                        typeComparer(signatureParameterToCompare, parameter))
                    {
                        matchRank++;
                    }

                    //increment the current expression index
                    idx++;
                }

                //group by rank, using the HashMap object.
                List <T> signaturesWithTheSameRank;

                //get a reference to a group with the same rank, if one exists
                if (rankingToSignatureGroup.TryGetValue(matchRank, out signaturesWithTheSameRank))
                {
                    signaturesWithTheSameRank.Add(match);
                }
                else
                {
                    //first group seen with this rank, make a new group
                    signaturesWithTheSameRank = new List <T> {
                        match
                    };
                    rankingToSignatureGroup.Add(matchRank, signaturesWithTheSameRank);
                }
            }

            //check if all the matching signatures have the same ranking, which would mean there is not a 'best' choice.
            //we grouped by rank, so if there is just one group, then all the signatures have the same rank.
            if (rankingToSignatureGroup.Count == 1)
            {
                //all candidates share the same rank, ambiguous match because no signature can be the 'best' choice, return all matches.
                return(new LSLFunctionOverloadMatches <T>(matches));
            }

            //Find the grouping with the smallest ranking number, this is the best group to look in.
            KeyValuePair <int, List <T> >?groupingWithTheBestRank = null;

            foreach (var groupPair in rankingToSignatureGroup)
            {
                //find the lowest rank
                if (!groupingWithTheBestRank.HasValue || groupPair.Key < groupingWithTheBestRank.Value.Key)
                {
                    //assign this group if it has lower rank than the previous group.
                    groupingWithTheBestRank = groupPair;
                }
            }


            //no groupings were created, no matches at all.  This is not expected to happen.
            if (!groupingWithTheBestRank.HasValue)
            {
                return(new LSLFunctionOverloadMatches <T>(new GenericArray <T>()));
            }

            var selectedGroup = groupingWithTheBestRank.Value.Value;

            //if we found a grouping, and that grouping has more than one matching signature, we need to tie break again.
            if (selectedGroup.Count != 1)
            {
                if (
                    selectedGroup.Distinct(
                        new LambdaEqualityComparer <T>(
                            (sig, sig2) => sig.ParameterCount == sig2.ParameterCount,
                            sig => sig.ParameterCount.GetHashCode())).Count() == 1)
                {
                    //all the signatures in the grouping have a matching number of parameters, overload resolution is ambiguous, return all signatures that matched.
                    return(new LSLFunctionOverloadMatches <T>(selectedGroup));
                }


                //Otherwise find the signature in the grouping with a concrete (non-variadic) parameter count closest to the amount of parameter expressions given to call the function.

                var minDistance = selectedGroup.Min(n => Math.Abs(expressionNodes.Count - n.ConcreteParameterCount));
                var closest     =
                    selectedGroup.First(n => Math.Abs(expressionNodes.Count - n.ConcreteParameterCount) == minDistance);

                //The one with the closest amount of concrete parameters wins.
                return(new LSLFunctionOverloadMatches <T>(closest));
            }

            if (selectedGroup.Count > 1)
            {
                throw new InvalidOperationException(typeof(LSLFunctionSignatureMatcher).Name +
                                                    ".MatchOverloads: Algorithm bug check assertion.");
            }

            //There was only one signature match in the grouping, it had the lowest rank so its the best.
            return(new LSLFunctionOverloadMatches <T>(selectedGroup.First()));
        }
 /// <summary>
 ///     Find a matching overload from a list of function signatures, given the parameter expressions. return null if none
 ///     is found.
 /// </summary>
 /// <typeparam name="T">The type of <see cref="LSLFunctionSignature"/> derived object to preform matching against.</typeparam>
 /// <param name="expressionValidator">
 ///     The expression validator, which is used to determine if an expression can be passed
 ///     into a parameter of a certain type.
 /// </param>
 /// <param name="functionSignatures">The function signatures to search through.</param>
 /// <param name="expressionNodes">The expression nodes of the function parameters we want to pass and find an overload for.</param>
 /// <returns>A matching <see cref="LSLFunctionSignature" /> overload or null.</returns>
 public static LSLFunctionOverloadMatches <T> MatchOverloads <T>(IReadOnlyGenericArray <T> functionSignatures,
                                                                 IReadOnlyGenericArray <ILSLReadOnlyExprNode> expressionNodes, ILSLExpressionValidator expressionValidator)
     where T : class, ILSLFunctionSignature
 {
     return(MatchOverloads(functionSignatures, expressionNodes, (expressionValidator.ValidateFunctionParameter)));
 }
 /// <summary>
 ///     Initializes a new instance of the <see cref="LSLFunctionOverloadMatches{T}" /> class with an
 ///     <see cref="IReadOnlyGenericArray{T}" /> containing signature matches.
 /// </summary>
 /// <param name="matches">The matches.</param>
 internal LSLFunctionOverloadMatches(IReadOnlyGenericArray <T> matches)
 {
     Matches = matches;
 }
 /// <summary>
 ///     Check if a given function signature can be called with the given expressions as parameters
 /// </summary>
 /// <param name="expressionValidator">
 ///     The expression validator, which is used to determine if an expression can be passed
 ///     into a parameter of a certain type.
 /// </param>
 /// <param name="functionSignature">The function signature of the functions your passing the parameter expressions to.</param>
 /// <param name="expressions">The expressions we want to test against this function signatures defined parameters.</param>
 /// <returns>
 ///     A <see cref="LSLFunctionSignatureMatch"/> object containing information about how the parameters matched
 ///     or did not match the call signature.
 /// </returns>
 public static LSLFunctionSignatureMatch TryMatch(ILSLFunctionSignature functionSignature,
                                                  IReadOnlyGenericArray <ILSLReadOnlyExprNode> expressions, ILSLExpressionValidator expressionValidator)
 {
     return(TryMatch(functionSignature, expressions, (expressionValidator.ValidateFunctionParameter)));
 }
Exemplo n.º 12
0
        /// <summary>
        ///     Construct an <see cref="LSLCompilationUnitNode" /> with an empty default state node.
        /// </summary>
        public LSLCompilationUnitNode()
        {
            DefaultState = new LSLStateScopeNode("default");

            _comments = new GenericArray <LSLComment>();
        }
        /// <summary>
        ///     Check if a given function signature can be called with the given expressions as parameters
        /// </summary>
        /// <param name="typeComparer">A function which should return true if two types match</param>
        /// <param name="functionSignature">The function signature of the functions your passing the parameter expressions to.</param>
        /// <param name="expressions">The expressions we want to test against this function signatures defined parameters.</param>
        /// <returns>
        ///     A LSLFunctionCallSignatureMatcher.MatchStatus object containing information about how the parameters matched
        ///     or did not match the call signature.
        /// </returns>
        /// <exception cref="ArgumentNullException"><paramref name="functionSignature"/> or <paramref name="expressions"/> or <paramref name="typeComparer"/> is <c>null</c>.</exception>
        public static LSLFunctionSignatureMatch TryMatch(ILSLFunctionSignature functionSignature,
                                                         IReadOnlyGenericArray <ILSLReadOnlyExprNode> expressions, Func <LSLParameterSignature, ILSLReadOnlyExprNode, bool> typeComparer)
        {
            if (functionSignature == null)
            {
                throw new ArgumentNullException("functionSignature");
            }
            if (expressions == null)
            {
                throw new ArgumentNullException("expressions");
            }
            if (typeComparer == null)
            {
                throw new ArgumentNullException("typeComparer");
            }


            int  parameterNumber       = 0;
            bool parameterTypeMismatch = false;

            //if we supplied to many parameters, and there is not a variadic
            //parameter at the end of the signature, then there is not a match
            if (functionSignature.HasVariadicParameter == false &&
                expressions.Count > functionSignature.ParameterCount)
            {
                return(new LSLFunctionSignatureMatch(false, true, false, -1));
            }


            //not enough parameters to fill all of the concrete (non variadic) parameters in
            //we do not have enough expressions to call this function signature
            if (expressions.Count < functionSignature.ConcreteParameterCount)
            {
                return(new LSLFunctionSignatureMatch(true, false, false, -1));
            }


            //check the types of all parameters match, including variadic parameters from the signature if they are not Void
            //if the variadic parameter is Void than anything can go in it, so it is not even checked
            for (; parameterNumber < expressions.Count; parameterNumber++)
            {
                LSLParameterSignature compareWithThisSignatureParameter;

                if (parameterNumber > (functionSignature.ParameterCount - 1))
                {
                    //If this happens it means we are in a continuation of a variadic parameter, we want to continue comparing the rest of the passed
                    //expressions to the last parameter in the function signature, IE. the variadic parameter.
                    compareWithThisSignatureParameter =
                        functionSignature.Parameters[functionSignature.ParameterCount - 1];
                }
                else
                {
                    //We have not flowed over the parameter count of the signature, so theres no danger
                    //of an out of bounds index on the parameters array in the signature.
                    compareWithThisSignatureParameter = functionSignature.Parameters[parameterNumber];
                }


                //no type check required, the variadic parameter allows everything in because its type is Void, anything you put in is a match
                //from here on out.  So its safe to return from the loop now and stop checking parameters.
                if (compareWithThisSignatureParameter.Variadic && compareWithThisSignatureParameter.Type == LSLType.Void)
                {
                    break;
                }

                //use the type comparer to check for a match, there might be some special case like string literals
                //being passed into a Key parameter, this behavior is delegated for better re-usability
                if (typeComparer(compareWithThisSignatureParameter, expressions[parameterNumber]))
                {
                    continue;
                }

                //the expression could not be passed into the parameter due to a type mismatch, we are done checking the parameters
                //because we know for a fact the expressions given do not match this call signature
                parameterTypeMismatch = true;
                break;
            }


            //if there was a parameter mismatch, the last checked parameter index is the index at which the mismatch occurred
            var badParameterIndex = parameterTypeMismatch ? parameterNumber : -1;

            //we had an allowable amount of parameters, but there was a type mismatch somewhere
            return(new LSLFunctionSignatureMatch(false, false, parameterTypeMismatch, badParameterIndex));
        }