コード例 #1
0
        private static bool TryImplicitConstantConversion(ref BoundExpression boundExpression, TypeSymbol targetType)
        {
            if (!boundExpression.IsConstant)
            {
                return(false);
            }
            if (boundExpression.ValueType == targetType)
            {
                return(false);
            }

            var targetSystemType = targetType.UdonType.SystemType;

            object constantValue = boundExpression.ConstantValue.Value;

            // if (targetSystemType == typeof(string))
            // {
            //     IConstantValue constant = new ConstantValue<string>(constantValue?.ToString() ?? "");
            //
            //     boundExpression = new BoundConstantExpression(constant, targetType, boundExpression.SyntaxNode);
            // }

            var sourceSystemType = boundExpression.ValueType.UdonType.SystemType;

            if (ConstantExpressionOptimizer.CanDoConstantConversion(sourceSystemType) &&
                ConstantExpressionOptimizer.CanDoConstantConversion(targetSystemType))
            {
                IConstantValue constant = (IConstantValue)Activator.CreateInstance(typeof(ConstantValue <>).MakeGenericType(targetSystemType), ConstantExpressionOptimizer.FoldConstantConversion(targetSystemType, constantValue));
                boundExpression = new BoundConstantExpression(constant, targetType, boundExpression.SyntaxNode);

                return(true);
            }

            if (boundExpression.ValueType.IsEnum &&
                boundExpression.ValueType.IsExtern &&
                UdonSharpUtils.IsIntegerType(targetSystemType))
            {
                boundExpression = new BoundConstantExpression(ConstantExpressionOptimizer.FoldConstantConversion(targetSystemType, constantValue), targetType);

                return(true);
            }

            return(false);
        }
コード例 #2
0
ファイル: EmitContext.cs プロジェクト: ureishi/UdonSharp
        private void CastValue(Value sourceValue, Value targetValue, bool explicitCast)
        {
            if (targetValue.UserType is TypeParameterSymbol)
            {
                throw new InvalidOperationException("Target cast type cannot be a generic type parameter");
            }

            if (sourceValue == targetValue)
            {
                return;
            }

            // Early out for exact type matches
            if (sourceValue.UserType == targetValue.UserType)
            {
                Module.AddCopy(sourceValue, targetValue);
                return;
            }

            TypeSymbol sourceType = sourceValue.UserType;
            TypeSymbol targetType = targetValue.UserType;

            void ExecuteBoundInvocation(MethodSymbol conversionMethod)
            {
                using (OpenAssignmentScope(targetValue))
                {
                    sourceValue = EmitValue(BoundInvocationExpression.CreateBoundInvocation(this, null, conversionMethod, null,
                                                                                            new BoundExpression[] { BoundAccessExpression.BindAccess(sourceValue) }));
                }

                if (sourceValue != targetValue)
                {
                    Module.AddCopy(sourceValue, targetValue);
                }
            }

            Conversion conversion = CompileContext.RoslynCompilation.ClassifyConversion(sourceType.RoslynSymbol, targetType.RoslynSymbol);

            if (conversion.IsEnumeration)
            {
                // Extern enum -> integer
                if (sourceValue.UdonType.IsEnum &&
                    UdonSharpUtils.IsIntegerType(targetType.UdonType.SystemType))
                {
                    MethodSymbol conversionMethod =
                        GetNumericConversionMethod(GetTypeSymbol(SpecialType.System_Object), targetType);
                    ExecuteBoundInvocation(conversionMethod);
                    return;
                }

                // Integer -> user enum
                // User enum -> user enum
                if (UdonSharpUtils.IsIntegerType(sourceType.UdonType.SystemType) && !targetType.IsExtern && targetType.IsEnum)
                {
                    if (sourceType.UdonType == targetType.UdonType)
                    {
                        Module.AddCopy(sourceValue, targetValue);
                        return;
                    }

                    ExecuteBoundInvocation(GetNumericConversionMethod(sourceType.UdonType, targetType.UdonType));
                    return;
                }

                // integer -> extern enum
                if (UdonSharpUtils.IsIntegerType(sourceType.UdonType.SystemType) &&
                    targetType.UdonType.IsEnum)
                {
                    Value enumArray = GetEnumArrayForType(targetType.UdonType.SystemType);

                    Value indexValue         = CastValue(sourceValue, GetTypeSymbol(SpecialType.System_Int32), true);
                    var   boundElementAccess = BoundAccessExpression.BindElementAccess(this, null, BoundAccessExpression.BindAccess(enumArray),
                                                                                       new BoundExpression[]
                    {
                        BoundAccessExpression.BindAccess(indexValue),
                    });

                    Value enumVal = EmitValue(boundElementAccess);

                    // todo: get rid of the copy again
                    Module.AddCopy(enumVal, targetValue);
                    return;
                }
            }

            if (conversion.IsNumeric ||
                (UdonSharpUtils.IsNumericType(targetType.UdonType.SystemType) && sourceType == GetTypeSymbol(SpecialType.System_Object)))
            {
                MethodSymbol conversionMethod = GetNumericConversionMethod(sourceType, targetType);

                if (conversionMethod != null)
                {
                    using (InterruptAssignmentScope())
                    {
                        // Float to int truncation handling since System.Convert rounds
                        if (UdonSharpUtils.IsFloatType(sourceType.UdonType.SystemType) &&
                            UdonSharpUtils.IsIntegerType(targetType.UdonType.SystemType))
                        {
                            TypeSymbol floatType = GetTypeSymbol(SpecialType.System_Single);
                            sourceValue = CastValue(sourceValue, floatType, true);

                            if (_mathfFloorMethodSymbol == null)
                            {
                                _mathfFloorMethodSymbol =
                                    GetTypeSymbol(typeof(Mathf)).GetMember <MethodSymbol>("Floor", this);
                            }

                            sourceValue = EmitValue(BoundInvocationExpression.CreateBoundInvocation(this, null, _mathfFloorMethodSymbol,
                                                                                                    null,
                                                                                                    new BoundExpression[] { BoundAccessExpression.BindAccess(sourceValue) }));

                            conversionMethod = GetNumericConversionMethod(floatType, targetType);
                        }
                    }

                    ExecuteBoundInvocation(conversionMethod);
                    return;
                }
            }

            if (conversion.IsUserDefined && conversion.MethodSymbol != null)
            {
                MethodSymbol conversionMethod = (MethodSymbol)GetSymbol(conversion.MethodSymbol);
                ExecuteBoundInvocation(conversionMethod);
                return;
            }

            Module.AddCopy(sourceValue, targetValue);
        }