예제 #1
0
        /// <summary>
        /// Visits the specified binary expression.
        /// </summary>
        /// <param name="binaryExpression">The binary expression.</param>
        public override Node Visit(BinaryExpression binaryExpression)
        {
            base.Visit(binaryExpression);

            var leftType  = binaryExpression.Left.TypeInference.TargetType;
            var rightType = binaryExpression.Right.TypeInference.TargetType;

            // No need to log an error as it has been done by the initial base.Visit(
            if (leftType == null || rightType == null)
            {
                return(binaryExpression);
            }

            switch (binaryExpression.Operator)
            {
            case BinaryOperator.Multiply:
                binaryExpression.TypeInference.TargetType = GetMultiplyImplicitConversionType(binaryExpression.Span, leftType, rightType);
                break;

            case BinaryOperator.Divide:
                binaryExpression.TypeInference.TargetType = GetDivideImplicitConversionType(binaryExpression.Span, leftType, rightType);
                break;

            case BinaryOperator.Minus:
            case BinaryOperator.Plus:
            case BinaryOperator.Modulo:
            case BinaryOperator.LogicalAnd:
            case BinaryOperator.LogicalOr:
            case BinaryOperator.BitwiseOr:
            case BinaryOperator.BitwiseAnd:
            case BinaryOperator.BitwiseXor:
            case BinaryOperator.RightShift:
            case BinaryOperator.LeftShift:
                binaryExpression.TypeInference.TargetType = GetBinaryImplicitConversionType(binaryExpression.Span, leftType, rightType, false);
                break;

            case BinaryOperator.Less:
            case BinaryOperator.LessEqual:
            case BinaryOperator.Greater:
            case BinaryOperator.GreaterEqual:
            case BinaryOperator.Equality:
            case BinaryOperator.Inequality:
                var returnType = GetBinaryImplicitConversionType(binaryExpression.Span, leftType, rightType, true);
                binaryExpression.TypeInference.TargetType = TypeBase.CreateWithBaseType(returnType, ScalarType.Bool);
                break;
            }

            return(binaryExpression);
        }
예제 #2
0
        protected virtual void Visit(UnaryExpression unaryExpression)
        {
            Visit((Node)unaryExpression);

            // TODO check for
            unaryExpression.TypeInference = (TypeInference)unaryExpression.Expression.TypeInference.Clone();

            // If this is a logical not, transform the value to a bool (bool2 bool3 bool4 / matrix<bool,1,1> matrix<bool,1,2> ..etc.
            var subType = unaryExpression.Expression.TypeInference.TargetType;

            if (subType != null && unaryExpression.Operator == UnaryOperator.LogicalNot)
            {
                unaryExpression.TypeInference.TargetType = TypeBase.CreateWithBaseType(subType, ScalarType.Bool);
            }
        }
예제 #3
0
        /// <summary>
        /// Pres the process method invocation.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <param name="methodName">Name of the method.</param>
        /// <param name="declarations">The declarations.</param>
        /// <returns></returns>
        protected virtual void ProcessMethodInvocation(MethodInvocationExpression expression, string methodName, List <IDeclaration> declarations)
        {
            // Get all arguments types infered
            var argumentTypeInferences = expression.Arguments.Select(x => x.TypeInference).ToArray();
            var argumentTypes          = expression.Arguments.Select(x => x.TypeInference.TargetType).ToArray();

            // If any type could not be resolved previously, there is already an error, so return immediately
            if (argumentTypes.Any(x => x == null))
            {
                return;
            }

            var overloads = new List <FunctionOverloadScore>();

            // Use the most overriden method
            // TODO: Temporary workaround for user methods overriding builtin methods
            // Remove the builtin methods if there is any overriding
            var methodsDeclared = declarations.OfType <MethodDeclaration>().ToList();

            for (int i = 0; i < methodsDeclared.Count - 1; i++)
            {
                var leftMethod = methodsDeclared[i];
                for (int j = i + 1; j < methodsDeclared.Count; j++)
                {
                    if (leftMethod.IsSameSignature(methodsDeclared[j]))
                    {
                        methodsDeclared.RemoveAt(i);
                        i--;
                        break;
                    }
                }
            }

            // Try to match the function arguments with every overload
            foreach (var methodDeclaration in methodsDeclared)
            {
                var returnType     = methodDeclaration.ReturnType.ResolveType();
                var parameterTypes = methodDeclaration.Parameters.Select(x => x.Type.ResolveType()).ToArray();

                // Number of parameters doesn't match
                if (argumentTypes.Length > parameterTypes.Length)
                {
                    continue;
                }

                // Check for method calls that is using implicit parameter value
                if (argumentTypes.Length < parameterTypes.Length)
                {
                    bool allRemainingParametersHaveDefaultValues = true;
                    // Check for default values
                    for (int i = argumentTypes.Length; i < parameterTypes.Length; i++)
                    {
                        if (methodDeclaration.Parameters[i].InitialValue == null)
                        {
                            allRemainingParametersHaveDefaultValues = false;
                            break;
                        }
                    }

                    // If remaining parameters doesn't have any default values, then continue
                    if (!allRemainingParametersHaveDefaultValues)
                    {
                        continue;
                    }
                }

                // Higher score = more conversion (score == 0 is perfect match)
                int  score         = 0;
                bool validOverload = true;

                // Check parameters
                for (int i = 0; i < argumentTypes.Length && validOverload; ++i)
                {
                    var argType      = argumentTypes[i];
                    var expectedType = parameterTypes[i];

                    var argTypeBase      = TypeBase.GetBaseType(argType);
                    var expectedTypeBase = TypeBase.GetBaseType(expectedType);

                    if (expectedTypeBase is GenericParameterType)
                    {
                        var genericParameterType = (GenericParameterType)expectedTypeBase;

                        // TODO handle dynamic score from constraint.
                        if (methodDeclaration.CheckConstraint(genericParameterType, argType))
                        {
                            score++;
                        }
                        else
                        {
                            validOverload = false;
                        }
                    }
                    else
                    {
                        // TODO, improve the whole test by using TypeBase equality when possible

                        // Then work on scalar type conversion ( float to int, signed to unsigned, different type)
                        var fromScalarType = argTypeBase as ScalarType;
                        var toScalarType   = expectedTypeBase as ScalarType;

                        if (fromScalarType != null && toScalarType != null)
                        {
                            if (ScalarType.IsFloat(fromScalarType) && !ScalarType.IsFloat(toScalarType))
                            {
                                // Truncation from float to int
                                score += 7;
                            }
                            else if (fromScalarType != toScalarType)
                            {
                                // else different type (implicit cast is usually working)
                                score += 1;
                            }

                            if (!fromScalarType.IsUnsigned && toScalarType.IsUnsigned)
                            {
                                // int to unsigned
                                score += 2;
                            }
                        }

                        // First, try to fix the base type (i.e. the "float" of float3x1)
                        if (argTypeBase != expectedTypeBase && expectedTypeBase is ScalarType)
                        {
                            if (!(argTypeBase is ScalarType))
                            {
                                score++; // +1 for type conversion
                            }
                            argType = TypeBase.CreateWithBaseType(argType, (ScalarType)expectedTypeBase);
                        }

                        validOverload = TestMethodInvocationArgument(argTypeBase, expectedTypeBase, argType, expectedType, ref score);
                    }
                }

                if (validOverload)
                {
                    overloads.Add(
                        new FunctionOverloadScore {
                        Declaration = methodDeclaration, ParameterTypes = parameterTypes, ReturnType = returnType, Score = score
                    });
                }
            }

            // In-place sort using List.Sort would be lighter
            var bestOverload = overloads.OrderBy(x => x.Score).FirstOrDefault();

            if (bestOverload != null)
            {
                expression.TypeInference.TargetType = bestOverload.ReturnType.ResolveType();

                // Override declaration to match exactly the declaration found by method overloaded resolution
                expression.Target.TypeInference.Declaration = bestOverload.Declaration;

                // Add appropriate cast
                for (int i = 0; i < argumentTypes.Length; ++i)
                {
                    argumentTypeInferences[i].ExpectedType = (bestOverload.ParameterTypes[i] is GenericParameterType)
                                                                 ? argumentTypes[i]
                                                                 : bestOverload.ParameterTypes[i].ResolveType();
                }
            }
            else
            {
                Error(MessageCode.ErrorNoOverloadedMethod, expression.Span, methodName);
            }
        }