Пример #1
0
        public void InvocationChildNames()
        {
            var ie = JSInvocationExpression.InvokeMethod(
                new JSStringIdentifier("Method"),
                new JSStringIdentifier("ThisReference"),
                new JSExpression[] {
                new JSStringIdentifier("Argument")
            }
                );

            var pairs = new List <KeyValuePair <JSNode, string> >();

            using (var e = ie.Children.EnumeratorTemplate)
                while (e.MoveNext())
                {
                    pairs.Add(new KeyValuePair <JSNode, string>(e.Current, e.CurrentName));
                }

            Assert.AreEqual(4, pairs.Count);

            Assert.AreEqual(ie.Method, pairs[1].Key);
            Assert.AreEqual("Method", pairs[1].Value);

            Assert.AreEqual(ie.ThisReference, pairs[2].Key);
            Assert.AreEqual("ThisReference", pairs[2].Value);
        }
Пример #2
0
            public override JSExpression Translate(ILBlockTranslator translator, JSExpression[] arguments)
            {
                var thisArgument = FixupThisArgument(arguments[1], translator.TypeSystem);

                var returnType = ReturnType;

                if (returnType == null)
                {
                    returnType = translator.TypeSystem.Void;
                }

                var argumentValues = arguments.Skip(2).ToArray();
                var memberName     = MemberName;

                if ((TypeArguments != null) && (TypeArguments.Length > 0))
                {
                    memberName += "`" + TypeArguments.Length;
                }

                return(JSInvocationExpression.InvokeMethod(
                           new JSFakeMethod(
                               memberName, returnType,
                               (from av in argumentValues select av.GetActualType(translator.TypeSystem)).ToArray(),
                               translator.MethodTypes, TypeArguments
                               ), thisArgument,
                           arguments.Skip(2).ToArray()
                           ));
            }
Пример #3
0
 protected JSInvocationExpression CastToInteger(JSExpression booleanExpression)
 {
     return(JSInvocationExpression.InvokeMethod(
                JS.valueOf(TypeSystem.SByte),
                booleanExpression, null, true
                ));
 }
        public void VisitNode(JSNewArrayElementReference naer)
        {
            var isInsideLoop     = (Stack.Any((node) => node is JSLoopStatement));
            var parentPassByRef  = ParentNode as JSPassByReferenceExpression;
            var parentInvocation = Stack.OfType <JSInvocationExpression>().FirstOrDefault();
            var doesValueEscape  = DoesValueEscapeFromInvocation(parentInvocation, naer, true);

            if (
                isInsideLoop &&
                (parentPassByRef != null) &&
                (parentInvocation != null) &&
                !doesValueEscape
                )
            {
                var replacement = CreateHoistedVariable(
                    (hoistedVariable) => JSInvocationExpression.InvokeMethod(
                        new JSFakeMethod("retarget", hoistedVariable.GetActualType(TypeSystem), new TypeReference[] { TypeSystem.Object, TypeSystem.Int32 }, MethodTypes),
                        hoistedVariable, new JSExpression[] { naer.Array, naer.Index }
                        ),
                    naer.GetActualType(TypeSystem),
                    naer.MakeUntargeted()
                    );

                ParentNode.ReplaceChild(naer, replacement);
                VisitReplacement(replacement);
            }

            VisitChildren(naer);
        }
Пример #5
0
        public static JSExpression GetItem(TypeReference targetType, TypeInfo targetTypeInfo, JSExpression target, JSExpression index, MethodTypeFactory methodTypes, bool proxy = false)
        {
            var targetGit     = (GenericInstanceType)targetType;
            var getMethodName = "get_Item";
            var getMethod     = (JSIL.Internal.MethodInfo)targetTypeInfo.Members.First(
                (kvp) => kvp.Key.Name == getMethodName
                ).Value;

            if (proxy)
            {
                return(new JSNewPackedArrayElementProxy(
                           target, index, targetGit.GenericArguments[0]
                           ));
            }

            // We have to construct a custom reference to the method in order for ILSpy's
            //  SubstituteTypeArgs method not to explode later on
            var getMethodReference = CecilUtil.RebindMethod(getMethod.Member, targetGit, targetGit.GenericArguments[0]);

            var result = JSInvocationExpression.InvokeMethod(
                new JSType(targetType),
                new JSMethod(getMethodReference, getMethod, methodTypes),
                target,
                new JSExpression[] { index },
                constantIfArgumentsAre: proxy
                );

            return(result);
        }
        public void VisitNode(JSNewExpression newexp)
        {
            var type = newexp.GetActualType(TypeSystem);

            var isStruct         = TypeUtil.IsStruct(type);
            var isInsideLoop     = (Stack.Any((node) => node is JSLoopStatement));
            var parentInvocation = ParentNode as JSInvocationExpression;
            var doesValueEscape  = DoesValueEscapeFromInvocation(parentInvocation, newexp, false);

            if (isStruct &&
                isInsideLoop &&
                (parentInvocation != null) &&
                !doesValueEscape
                )
            {
                var replacement = CreateHoistedVariable(
                    (hoistedVariable) => new JSCommaExpression(
                        JSInvocationExpression.InvokeMethod(
                            type, new JSMethod(newexp.ConstructorReference, newexp.Constructor, MethodTypes, null), hoistedVariable,
                            newexp.Arguments.ToArray(), false
                            ),
                        hoistedVariable
                        ),
                    type
                    );

                ParentNode.ReplaceChild(newexp, replacement);
                VisitReplacement(replacement);
            }
            else
            {
                VisitChildren(newexp);
            }
        }
Пример #7
0
        public JSInvocationExpression NewDelegate(TypeReference delegateType, JSExpression thisReference, JSExpression targetMethod)
        {
            var targetDotExpression = targetMethod as JSDotExpressionBase;
            var jsMethod            = targetDotExpression != null ? targetDotExpression.Member as JSMethod : null;

            JSExpression[] invocationExpressionArguments;

            if (jsMethod == null)
            {
                // Not sure if it is possible.
                invocationExpressionArguments = new[] { thisReference, targetMethod };
            }
            else
            {
                var jsMethodAccess = targetMethod as JSMethodAccess;
                var arguments      = jsMethod == null
                    ? null
                    : jsMethod.Reference.Parameters.Select(
                    (parameter, index) => (JSExpression) new JSRawOutputIdentifier(parameter.ParameterType, "arguments[{0}]", index))
                                     .ToArray();

                bool isFromDelegate = jsMethod.Reference.Name == "Invoke" && TypeUtil.IsDelegateType(jsMethod.Reference.DeclaringType);

                JSExpression methodInvocation;
                if (isFromDelegate)
                {
                    methodInvocation = targetMethod;
                }
                else if (jsMethod.Method.IsStatic)
                {
                    methodInvocation = new JSDeferredExpression(JSInvocationExpression.InvokeStatic(jsMethod.Reference.DeclaringType, jsMethod, arguments));
                }
                else if (jsMethodAccess == null || jsMethodAccess.IsVirtual)
                {
                    methodInvocation = new JSDeferredExpression(JSInvocationExpression.InvokeMethod(jsMethod.Reference.DeclaringType, jsMethod, thisReference, arguments));
                }
                else
                {
                    methodInvocation = new JSDeferredExpression(JSInvocationExpression.InvokeBaseMethod(jsMethod.Reference.DeclaringType, jsMethod, thisReference, arguments));
                }

                invocationExpressionArguments = new[] {
                    thisReference,
                    methodInvocation,
                    new JSDeferredExpression(new JSMethodOfExpression(jsMethod.Reference, jsMethod.Method, jsMethod.MethodTypes, jsMethod.GenericArguments))
                };
            }

            return(JSInvocationExpression.InvokeStatic(
                       new JSDotExpression(
                           new JSType(delegateType),
                           new JSFakeMethod("New", delegateType, new[] { TypeSystem.Object, TypeSystem.Object }, MethodTypes)),
                       invocationExpressionArguments,
                       true));
        }
Пример #8
0
            public override JSExpression Translate(ILBlockTranslator translator, JSExpression[] arguments)
            {
                var thisArgument = FixupThisArgument(arguments[1], translator.TypeSystem);

                var returnType = ReturnType;

                if (returnType == null)
                {
                    returnType = translator.TypeSystem.Void;
                }

                var argumentValues = arguments.Skip(2).ToArray();
                var memberName     = MemberName;

                if ((TypeArguments != null) && (TypeArguments.Length > 0))
                {
                    memberName += "`" + TypeArguments.Length;
                }

                var thisArgumentKnownType = JSType.ExtractType(thisArgument);

                if (thisArgumentKnownType != null)
                {
                    var replacement = translator.DoJSILMethodReplacement(
                        thisArgumentKnownType.FullName, memberName,
                        null,
                        // FIXME
                        null,
                        argumentValues
                        );
                    if (replacement != null)
                    {
                        return(replacement);
                    }
                }

                return(JSInvocationExpression.InvokeMethod(
                           new JSFakeMethod(
                               memberName, returnType,
                               (from av in argumentValues select av.GetActualType(translator.TypeSystem)).ToArray(),
                               translator.MethodTypes, TypeArguments,
                               escape: true
                               ), thisArgument,
                           arguments.Skip(2).ToArray()
                           ));
            }
Пример #9
0
        public void VisitNode(JSIndexerExpression ie)
        {
            var indexType = ie.Index.GetActualType(TypeSystem);

            if (
                !TypeUtil.IsIntegral(indexType) &&
                IsEnumOrNullableEnum(indexType)
                )
            {
                var cast = JSInvocationExpression.InvokeMethod(
                    JS.valueOf(TypeSystem.Int32), ie.Index, null, true
                    );

                ie.ReplaceChild(ie.Index, cast);
            }

            VisitChildren(ie);
        }
Пример #10
0
        public void VisitNode(JSSwitchStatement ss)
        {
            var conditionType = ss.Condition.GetActualType(TypeSystem);

            if (
                !TypeUtil.IsIntegral(conditionType) &&
                IsEnumOrNullableEnum(conditionType)
                )
            {
                var cast = JSInvocationExpression.InvokeMethod(
                    JS.valueOf(TypeSystem.Int32), ss.Condition, null, true
                    );

                ss.ReplaceChild(ss.Condition, cast);
            }

            VisitChildren(ss);
        }
Пример #11
0
        public void VisitNode(JSUnaryOperatorExpression uoe)
        {
            var type   = uoe.Expression.GetActualType(TypeSystem);
            var isEnum = IsEnumOrNullableEnum(type);

            if (isEnum)
            {
                var castToInt = JSInvocationExpression.InvokeMethod(
                    JS.valueOf(TypeSystem.Int32), uoe.Expression, null, true
                    );

                if (LogicalOperators.Contains(uoe.Operator))
                {
                    uoe.ReplaceChild(uoe.Expression, castToInt);
                }
                else if (uoe.Operator == JSOperator.Negation)
                {
                    uoe.ReplaceChild(uoe.Expression, castToInt);
                }
                else if (uoe.Operator is JSUnaryMutationOperator)
                {
                    if (
                        (uoe.Operator == JSOperator.PreIncrement) ||
                        (uoe.Operator == JSOperator.PreDecrement)
                        )
                    {
                        var assignment = MakeUnaryMutation(
                            uoe.Expression,
                            (uoe.Operator == JSOperator.PreDecrement)
                                ? JSOperator.Subtract
                                : JSOperator.Add,
                            type
                            );

                        ParentNode.ReplaceChild(uoe, assignment);
                        VisitReplacement(assignment);
                        return;
                    }
                    else if (
                        (uoe.Operator == JSOperator.PostIncrement) ||
                        (uoe.Operator == JSOperator.PostDecrement)
                        )
                    {
                        // FIXME: Terrible hack
                        var tempVariable = TemporaryVariable.ForFunction(
                            Stack.Last() as JSFunctionExpression, type
                            );
                        var makeTempCopy = new JSBinaryOperatorExpression(
                            JSOperator.Assignment, tempVariable, uoe.Expression, type
                            );
                        var assignment = MakeUnaryMutation(
                            uoe.Expression,
                            (uoe.Operator == JSOperator.PostDecrement)
                                ? JSOperator.Subtract
                                : JSOperator.Add,
                            type
                            );

                        var comma = new JSCommaExpression(
                            makeTempCopy,
                            assignment,
                            tempVariable
                            );

                        ParentNode.ReplaceChild(uoe, comma);
                        VisitReplacement(comma);
                        return;
                    }
                    else
                    {
                        throw new NotImplementedException("Unary mutation of enum not supported: " + uoe.ToString());
                    }
                }
            }

            VisitChildren(uoe);
        }
Пример #12
0
        public void VisitNode(JSInvocationExpression ie)
        {
            var type           = ie.JSType;
            var method         = ie.JSMethod;
            var thisExpression = ie.ThisReference;

            if (method != null)
            {
                if (
                    (type != null) &&
                    (type.Type.FullName == "System.Object")
                    )
                {
                    switch (method.Method.Member.Name)
                    {
                    case ".ctor": {
                        var replacement = new JSNullExpression();
                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }

                    case "GetType": {
                        JSNode replacement;

                        var thisType = JSExpression.DeReferenceType(thisExpression.GetActualType(TypeSystem), false);
                        if ((thisType is GenericInstanceType) && thisType.FullName.StartsWith("System.Nullable"))
                        {
                            replacement = new JSType(thisType);
                        }
                        else
                        {
                            replacement = JSIL.GetTypeOf(thisExpression);
                        }

                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }
                    }
                }
                else if (
                    IsNullable(type.Type)
                    )
                {
                    var t        = (type.Type as GenericInstanceType).GenericArguments[0];
                    var @null    = JSLiteral.Null(t);
                    var @default = new JSDefaultValueLiteral(t);

                    switch (method.Method.Member.Name)
                    {
                    case ".ctor":
                        JSExpression value;
                        if (ie.Arguments.Count == 0)
                        {
                            value = @null;
                        }
                        else
                        {
                            value = ie.Arguments[0];
                        }

                        var boe = new JSBinaryOperatorExpression(
                            JSOperator.Assignment, ie.ThisReference, value, type.Type
                            );
                        ParentNode.ReplaceChild(ie, boe);
                        VisitReplacement(boe);

                        break;

                    case "GetValueOrDefault":
                        var isNull = new JSBinaryOperatorExpression(
                            JSOperator.Equal, ie.ThisReference, @null, TypeSystem.Boolean
                            );

                        JSTernaryOperatorExpression ternary;
                        if (ie.Arguments.Count == 0)
                        {
                            ternary = new JSTernaryOperatorExpression(
                                isNull, @default, ie.ThisReference, type.Type
                                );
                        }
                        else
                        {
                            ternary = new JSTernaryOperatorExpression(
                                isNull, ie.Arguments[0], ie.ThisReference, type.Type
                                );
                        }

                        ParentNode.ReplaceChild(ie, ternary);
                        VisitReplacement(ternary);

                        break;

                    default:
                        throw new NotImplementedException(method.Method.Member.FullName);
                    }

                    return;
                }
                else if (
                    (type != null) &&
                    TypeUtil.TypesAreEqual(TypeSystem.String, type.Type) &&
                    (method.Method.Name == "Concat")
                    )
                {
                    if (ie.Arguments.Count > 2)
                    {
                        if (ie.Arguments.All(
                                (arg) => TypeUtil.TypesAreEqual(
                                    TypeSystem.String, arg.GetActualType(TypeSystem)
                                    )
                                ))
                        {
                            var boe = JSBinaryOperatorExpression.New(
                                JSOperator.Add,
                                ie.Arguments,
                                TypeSystem.String
                                );

                            ParentNode.ReplaceChild(
                                ie,
                                boe
                                );

                            VisitReplacement(boe);
                        }
                    }
                    else if (
                        ie.Arguments.Count == 2
                        )
                    {
                        var lhs     = ie.Arguments[0];
                        var lhsType = TypeUtil.DereferenceType(lhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, lhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, lhsType)
                                ))
                        {
                            lhs = JSInvocationExpression.InvokeMethod(lhsType, JS.toString, lhs, null);
                        }

                        var rhs     = ie.Arguments[1];
                        var rhsType = TypeUtil.DereferenceType(rhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, rhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, rhsType)
                                ))
                        {
                            rhs = JSInvocationExpression.InvokeMethod(rhsType, JS.toString, rhs, null);
                        }

                        var boe = new JSBinaryOperatorExpression(
                            JSOperator.Add, lhs, rhs, TypeSystem.String
                            );

                        ParentNode.ReplaceChild(
                            ie, boe
                            );

                        VisitReplacement(boe);
                    }
                    else if (
                        TypeUtil.GetTypeDefinition(ie.Arguments[0].GetActualType(TypeSystem)).FullName == "System.Array"
                        )
                    {
                    }
                    else
                    {
                        var firstArg = ie.Arguments.FirstOrDefault();

                        ParentNode.ReplaceChild(
                            ie, firstArg
                            );

                        if (firstArg != null)
                        {
                            VisitReplacement(firstArg);
                        }
                    }
                    return;
                }
                else if (
                    TypeUtil.IsDelegateType(method.Reference.DeclaringType) &&
                    (method.Method.Name == "Invoke")
                    )
                {
                    var newIe = new JSDelegateInvocationExpression(
                        thisExpression, ie.GetActualType(TypeSystem), ie.Arguments.ToArray()
                        );
                    ParentNode.ReplaceChild(ie, newIe);

                    VisitReplacement(newIe);
                    return;
                }
                else if (
                    (method.Reference.DeclaringType.FullName == "System.Type") &&
                    (method.Method.Name == "GetTypeFromHandle")
                    )
                {
                    var typeObj = ie.Arguments.FirstOrDefault();
                    ParentNode.ReplaceChild(ie, typeObj);

                    VisitReplacement(typeObj);
                    return;
                }
                else if (
                    (method.Reference.DeclaringType.Name == "RuntimeHelpers") &&
                    (method.Method.Name == "InitializeArray")
                    )
                {
                    var array       = ie.Arguments[0];
                    var arrayType   = array.GetActualType(TypeSystem);
                    var field       = ie.Arguments[1].SelfAndChildrenRecursive.OfType <JSField>().First();
                    var initializer = JSArrayExpression.UnpackArrayInitializer(arrayType, field.Field.Member.InitialValue);

                    var copy = JSIL.ShallowCopy(array, initializer, arrayType);
                    ParentNode.ReplaceChild(ie, copy);
                    VisitReplacement(copy);
                    return;
                }
                else if (
                    method.Reference.DeclaringType.FullName == "System.Reflection.Assembly"
                    )
                {
                    switch (method.Reference.Name)
                    {
                    case "GetExecutingAssembly": {
                        var assembly = Method.DeclaringType.Module.Assembly;
                        var asmNode  = new JSAssembly(assembly);
                        ParentNode.ReplaceChild(ie, asmNode);
                        VisitReplacement(asmNode);

                        return;
                    }

                    case "GetType": {
                        switch (method.Method.Parameters.Length)
                        {
                        case 1:
                        case 2:
                            JSExpression throwOnFail = new JSBooleanLiteral(false);
                            if (method.Method.Parameters.Length == 2)
                            {
                                throwOnFail = ie.Arguments[1];
                            }

                            var invocation = JSIL.GetTypeFromAssembly(
                                ie.ThisReference, ie.Arguments[0], throwOnFail
                                );
                            ParentNode.ReplaceChild(ie, invocation);
                            VisitReplacement(invocation);

                            return;
                        }

                        break;
                    }
                    }
                }
                else if (
                    method.Method.DeclaringType.Definition.FullName == "System.Array" &&
                    (ie.Arguments.Count == 1)
                    )
                {
                    switch (method.Method.Name)
                    {
                    case "GetLength":
                    case "GetUpperBound": {
                        var index = ie.Arguments[0] as JSLiteral;
                        if (index != null)
                        {
                            var newDot = JSDotExpression.New(thisExpression, new JSStringIdentifier(
                                                                 String.Format("length{0}", Convert.ToInt32(index.Literal)),
                                                                 TypeSystem.Int32
                                                                 ));

                            if (method.Method.Name == "GetUpperBound")
                            {
                                var newExpr = new JSBinaryOperatorExpression(
                                    JSOperator.Subtract, newDot, JSLiteral.New(1), TypeSystem.Int32
                                    );
                                ParentNode.ReplaceChild(ie, newExpr);
                            }
                            else
                            {
                                ParentNode.ReplaceChild(ie, newDot);
                            }
                        }
                        break;
                    }

                    case "GetLowerBound":
                        ParentNode.ReplaceChild(ie, JSLiteral.New(0));
                        break;
                    }
                }
            }

            VisitChildren(ie);
        }
Пример #13
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType     = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum   = IsEnumOrNullableEnum(leftType);
            var rightType    = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum  = IsEnumOrNullableEnum(rightType);
            var resultType   = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            var eitherIsEnum = leftIsEnum || rightIsEnum;

            var assignmentOperator = boe.Operator as JSAssignmentOperator;
            JSBinaryOperator replacementOperator;

            if (LogicalOperators.Contains(boe.Operator))
            {
                if (eitherIsEnum)
                {
                    if (leftIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Left, null, true
                            );

                        boe.ReplaceChild(boe.Left, cast);
                    }

                    if (rightIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Right, null, true
                            );

                        boe.ReplaceChild(boe.Right, cast);
                    }
                }
            }
            else if (BitwiseOperators.Contains(boe.Operator))
            {
                var parentCast = ParentNode as JSCastExpression;
                if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType)))
                {
                    var cast = JSCastExpression.New(
                        boe, resultType, TypeSystem, true
                        );

                    ParentNode.ReplaceChild(boe, cast);
                    VisitReplacement(cast);
                }
            }
            else if (
                (assignmentOperator != null) &&
                ReverseCompoundAssignments.TryGetValue(assignmentOperator, out replacementOperator) &&
                leftIsEnum
                )
            {
                var replacement = new JSBinaryOperatorExpression(
                    JSOperator.Assignment, boe.Left,
                    JSCastExpression.New(
                        new JSBinaryOperatorExpression(
                            replacementOperator, boe.Left, boe.Right, TypeSystem.Int32
                            ), leftType, TypeSystem, true
                        ),
                    leftType
                    );

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
Пример #14
0
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetActualType(TypeSystem);
            var targetType  = ce.NewType;

            JSExpression newExpression = null;

            if (targetType.MetadataType == MetadataType.Char)
            {
                newExpression = JSInvocationExpression.InvokeStatic(
                    JS.fromCharCode, new[] { ce.Expression }, true
                    );
            }
            else if (
                (currentType.MetadataType == MetadataType.Char) &&
                TypeUtil.IsIntegral(targetType)
                )
            {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                    );
            }
            else if (
                IntroduceEnumCasts.IsEnumOrNullableEnum(currentType)
                )
            {
                var enumInfo = TypeInfo.Get(currentType);

                if (targetType.MetadataType == MetadataType.Boolean)
                {
                    EnumMemberInfo enumMember;
                    if (enumInfo.ValueToEnumMember.TryGetValue(0, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.NotEqual, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else if (enumInfo.ValueToEnumMember.TryGetValue(1, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.Equal, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else
                    {
                        newExpression = new JSUntranslatableExpression(String.Format(
                                                                           "Could not cast enum of type '{0}' to boolean because it has no zero value or one value",
                                                                           currentType.FullName
                                                                           ));
                    }
                }
                else if (TypeUtil.IsNumeric(targetType))
                {
                    newExpression = JSInvocationExpression.InvokeStatic(
                        JS.Number(targetType), new[] { ce.Expression }, true
                        );
                }
                else if (targetType.FullName == "System.Enum")
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    // Debugger.Break();
                }
            }
            else if (
                targetType.MetadataType == MetadataType.Boolean
                )
            {
                newExpression = new JSBinaryOperatorExpression(
                    JSBinaryOperator.NotEqual,
                    ce.Expression, new JSDefaultValueLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                TypeUtil.IsNumeric(targetType) &&
                TypeUtil.IsNumeric(currentType)
                )
            {
                if (
                    TypeUtil.IsIntegral(currentType) ||
                    !TypeUtil.IsIntegral(targetType)
                    )
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    newExpression = JSInvocationExpression.InvokeStatic(JS.floor, new[] { ce.Expression }, true);
                }
            }
            else
            {
                newExpression = JSIL.Cast(ce.Expression, targetType);
            }

            if (newExpression != null)
            {
                ParentNode.ReplaceChild(ce, newExpression);
                VisitReplacement(newExpression);
            }
            else
            {
                // Debugger.Break();
                VisitChildren(ce);
            }
        }
Пример #15
0
        public void VisitNode(JSInvocationExpression ie)
        {
            var type           = ie.JSType;
            var method         = ie.JSMethod;
            var thisExpression = ie.ThisReference;

            if (method != null)
            {
                if (
                    (type != null) &&
                    (type.Type.FullName == "System.Object")
                    )
                {
                    switch (method.Method.Member.Name)
                    {
                    case ".ctor": {
                        var replacement = new JSNullExpression();
                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }

                    case "ReferenceEquals": {
                        var lhs = ie.Arguments[0];
                        var rhs = ie.Arguments[1];

                        var lhsType = lhs.GetActualType(TypeSystem);
                        var rhsType = rhs.GetActualType(TypeSystem);

                        JSNode replacement;

                        // Structs can never compare equal with ReferenceEquals
                        if (TypeUtil.IsStruct(lhsType) || TypeUtil.IsStruct(rhsType))
                        {
                            replacement = JSLiteral.New(false);
                        }
                        else
                        {
                            replacement = new JSBinaryOperatorExpression(
                                JSOperator.Equal,
                                lhs, rhs,
                                TypeSystem.Boolean
                                );
                        }

                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }

                    case "GetType": {
                        JSNode replacement;

                        var thisType = JSExpression.DeReferenceType(thisExpression.GetActualType(TypeSystem), false);
                        if ((thisType is GenericInstanceType) && thisType.FullName.StartsWith("System.Nullable"))
                        {
                            var git = (GenericInstanceType)thisType;

                            replacement = new JSTernaryOperatorExpression(
                                new JSBinaryOperatorExpression(
                                    JSOperator.NotEqual,
                                    thisExpression, new JSNullLiteral(thisType),
                                    TypeSystem.Boolean
                                    ),
                                new JSTypeOfExpression(git.GenericArguments[0]),
                                JSIL.ThrowNullReferenceException(),
                                new TypeReference("System", "Type", TypeSystem.Object.Module, TypeSystem.Object.Scope, false)
                                );
                        }
                        else
                        {
                            replacement = JSIL.GetTypeOf(thisExpression);
                        }

                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }
                    }
                }
                else if (
                    (type != null) &&
                    (type.Type.FullName == "System.ValueType")
                    )
                {
                    switch (method.Method.Member.Name)
                    {
                    case "Equals": {
                        var replacement = JSIL.StructEquals(ie.ThisReference, ie.Arguments.First());
                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }
                    }
                }
                else if (
                    (type != null) &&
                    IsNullable(type.Type)
                    )
                {
                    var t        = (type.Type as GenericInstanceType).GenericArguments[0];
                    var @null    = JSLiteral.Null(t);
                    var @default = new JSDefaultValueLiteral(t);

                    switch (method.Method.Member.Name)
                    {
                    case ".ctor":
                        JSExpression value;
                        if (ie.Arguments.Count == 0)
                        {
                            value = @null;
                        }
                        else
                        {
                            value = ie.Arguments[0];
                        }

                        var boe = new JSBinaryOperatorExpression(
                            JSOperator.Assignment, ie.ThisReference, value, type.Type
                            );
                        ParentNode.ReplaceChild(ie, boe);
                        VisitReplacement(boe);

                        break;

                    case "GetValueOrDefault": {
                        var replacement = JSIL.ValueOfNullableOrDefault(
                            ie.ThisReference,
                            (ie.Arguments.Count == 0)
                                    ? @default
                                    : ie.Arguments[0]
                            );

                        if (ParentNode is JSResultReferenceExpression)
                        {
                            // HACK: Replacing the invocation inside a result reference is incorrect, so we need to walk up the stack
                            //  and replace the result reference with the ternary instead.
                            _ResultReferenceReplacement = replacement;
                        }
                        else
                        {
                            ParentNode.ReplaceChild(ie, replacement);
                            VisitReplacement(replacement);
                        }

                        break;
                    }

                    case "get_HasValue": {
                        var replacement = JSIL.NullableHasValue(ie.ThisReference);
                        if (ParentNode is JSResultReferenceExpression)
                        {
                            _ResultReferenceReplacement = replacement;
                        }
                        else
                        {
                            ParentNode.ReplaceChild(ie, replacement);
                            VisitReplacement(replacement);
                        }

                        break;
                    }

                    case "get_Value": {
                        var replacement = JSIL.ValueOfNullable(ie.ThisReference);
                        if (ParentNode is JSResultReferenceExpression)
                        {
                            _ResultReferenceReplacement = replacement;
                        }
                        else
                        {
                            ParentNode.ReplaceChild(ie, replacement);
                            VisitReplacement(replacement);
                        }

                        break;
                    }

                    case "Equals":
                        JSBinaryOperatorExpression equality = new JSBinaryOperatorExpression(JSOperator.Equal, ie.ThisReference, ie.Parameters.First().Value, type.Type);
                        ParentNode.ReplaceChild(ie, equality);
                        VisitReplacement(equality);
                        break;

                    default:
                        throw new NotImplementedException(method.Method.Member.FullName);
                    }

                    return;
                }
                else if (
                    (type != null) &&
                    TypeUtil.TypesAreEqual(TypeSystem.String, type.Type) &&
                    (method.Method.Name == "Concat")
                    )
                {
                    if (ie.Arguments.Count > 2)
                    {
                        if (ie.Arguments.All(
                                (arg) => TypeUtil.TypesAreEqual(
                                    TypeSystem.String, arg.GetActualType(TypeSystem)
                                    )
                                ))
                        {
                            var boe = JSBinaryOperatorExpression.New(
                                JSOperator.Add,
                                ie.Arguments,
                                TypeSystem.String
                                );

                            ParentNode.ReplaceChild(
                                ie,
                                boe
                                );

                            VisitReplacement(boe);
                        }
                    }
                    else if (
                        // HACK: Fix for #239, only convert concat call into + if both sides are non-null literals
                        (ie.Arguments.Count == 2)
                        )
                    {
                        var lhs = ie.Arguments[0];
                        var rhs = ie.Arguments[1];

                        var isAddOk = (lhs is JSStringLiteral) && (rhs is JSStringLiteral);

                        var lhsType = TypeUtil.DereferenceType(lhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, lhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, lhsType)
                                ))
                        {
                            lhs     = JSInvocationExpression.InvokeMethod(lhsType, JS.toString, lhs, null);
                            isAddOk = true;
                        }

                        var rhsType = TypeUtil.DereferenceType(rhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, rhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, rhsType)
                                ))
                        {
                            rhs     = JSInvocationExpression.InvokeMethod(rhsType, JS.toString, rhs, null);
                            isAddOk = true;
                        }

                        if (isAddOk)
                        {
                            var boe = new JSBinaryOperatorExpression(
                                JSOperator.Add, lhs, rhs, TypeSystem.String
                                );

                            ParentNode.ReplaceChild(
                                ie, boe
                                );

                            VisitReplacement(boe);
                        }
                    }
                    else if (
                        TypeUtil.GetTypeDefinition(ie.Arguments[0].GetActualType(TypeSystem)).FullName == "System.Array"
                        )
                    {
                    }
                    else
                    {
                        var firstArg = ie.Arguments.FirstOrDefault();

                        ParentNode.ReplaceChild(
                            ie, firstArg
                            );

                        if (firstArg != null)
                        {
                            VisitReplacement(firstArg);
                        }
                    }
                    return;
                }
                else if (
                    TypeUtil.IsDelegateType(method.Reference.DeclaringType) &&
                    (method.Method.Name == "Invoke")
                    )
                {
                    var newIe = new JSDelegateInvocationExpression(
                        thisExpression, ie.GetActualType(TypeSystem), ie.Arguments.ToArray()
                        );
                    ParentNode.ReplaceChild(ie, newIe);

                    VisitReplacement(newIe);
                    return;
                }
                else if (
                    (method.Reference.DeclaringType.Name == "RuntimeHelpers") &&
                    (method.Method.Name == "InitializeArray")
                    )
                {
                    var array       = ie.Arguments[0];
                    var arrayType   = array.GetActualType(TypeSystem);
                    var field       = ie.Arguments[1].SelfAndChildrenRecursive.OfType <JSField>().First();
                    var initializer = JSArrayExpression.UnpackArrayInitializer(arrayType, field.Field.Member.InitialValue);

                    var copy = JSIL.ShallowCopy(array, initializer, arrayType);
                    ParentNode.ReplaceChild(ie, copy);
                    VisitReplacement(copy);
                    return;
                }
                else if (
                    method.Reference.DeclaringType.FullName == "System.Reflection.Assembly"
                    )
                {
                    switch (method.Reference.Name)
                    {
                    case "GetExecutingAssembly": {
                        var assembly = Method.DeclaringType.Module.Assembly;
                        var asmNode  = new JSReflectionAssembly(assembly);
                        ParentNode.ReplaceChild(ie, asmNode);
                        VisitReplacement(asmNode);

                        return;
                    }
                    }
                }
                else if (
                    method.Method.DeclaringType.Definition.FullName == "System.Array" &&
                    (ie.Arguments.Count == 1)
                    )
                {
                    switch (method.Method.Name)
                    {
                    case "GetLength":
                    case "GetUpperBound": {
                        var index = ie.Arguments[0] as JSLiteral;
                        if (index != null)
                        {
                            var newDot = JSDotExpression.New(thisExpression, new JSStringIdentifier(
                                                                 String.Format("length{0}", Convert.ToInt32(index.Literal)),
                                                                 TypeSystem.Int32
                                                                 ));

                            if (method.Method.Name == "GetUpperBound")
                            {
                                var newExpr = new JSBinaryOperatorExpression(
                                    JSOperator.Subtract, newDot, JSLiteral.New(1), TypeSystem.Int32
                                    );
                                ParentNode.ReplaceChild(ie, newExpr);
                            }
                            else
                            {
                                ParentNode.ReplaceChild(ie, newDot);
                            }
                        }
                        break;
                    }

                    case "GetLowerBound":
                        ParentNode.ReplaceChild(ie, JSLiteral.New(0));
                        break;
                    }
                }
            }

            VisitChildren(ie);
        }
Пример #16
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType     = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum   = IsEnumOrNullableEnum(leftType);
            var rightType    = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum  = IsEnumOrNullableEnum(rightType);
            var resultType   = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            var eitherIsEnum = leftIsEnum || rightIsEnum;

            var assignmentOperator = boe.Operator as JSAssignmentOperator;
            JSBinaryOperator           replacementOperator;
            JSBinaryOperatorExpression replacement;

            if (LogicalOperators.Contains(boe.Operator))
            {
                if (eitherIsEnum)
                {
                    if (leftIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Left, null, true
                            );

                        boe.ReplaceChild(boe.Left, cast);
                    }

                    if (rightIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Right, null, true
                            );

                        boe.ReplaceChild(boe.Right, cast);
                    }
                }
            }
            else if (BitwiseOperators.Contains(boe.Operator))
            {
                var parentCast        = ParentNode as JSCastExpression;
                var parentReinterpret = Stack.Skip(2).FirstOrDefault() as JSChangeTypeExpression;

                if (resultIsEnum &&
                    ((parentCast == null) || (parentCast.NewType != resultType)) &&
                    ((parentReinterpret == null) || (parentReinterpret.NewType != resultType))
                    )
                {
                    var cast = CastToEnumType(boe, resultType);

                    ParentNode.ReplaceChild(boe, cast);
                    VisitReplacement(cast);
                }
            }
            else if (
                leftIsEnum &&
                ((replacement = DeconstructMutationAssignment(boe, TypeSystem, TypeSystem.Int32)) != null)
                )
            {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
        private JSExpression ConstructInvocation(
            JSPropertyAccess pa, JSExpression argument = null
            )
        {
            JSExpression[] arguments;

            if (argument == null)
            {
                arguments = new JSExpression[0];
            }
            else
            {
                arguments = new JSExpression[] { argument }
            };

            var originalMethod    = pa.OriginalMethod;
            var declaringType     = originalMethod.Reference.DeclaringType;
            var declaringTypeDef  = TypeUtil.GetTypeDefinition(originalMethod.Reference.DeclaringType);
            var thisReferenceType = pa.ThisReference.GetActualType(TypeSystem);
            var isSelf            = TypeUtil.TypesAreAssignable(
                TypeInfo, thisReferenceType, declaringType
                );

            // ILSpy converts compound assignments from:
            //  x.set_Value(x.get_Value + n)
            // to
            //  x.get_Value += n;
            // so we have to detect this and reconstruct the correct method
            //  references.
            var actualMethod = originalMethod;
            var correctName  = String.Format(
                "{0}_{1}", pa.IsWrite ? "set" : "get",
                pa.Property.Property.ShortName
                );

            if (!actualMethod.Reference.Name.Contains(correctName))
            {
                var dt = originalMethod.Method.DeclaringType;

                var actualMethodInfo = dt.Members.Values
                                       .OfType <MethodInfo>().FirstOrDefault(
                    (m) => (
                        m.Name.Contains(correctName) &&
                        m.DeclaringType == originalMethod.Method.DeclaringType
                        )
                    );

                MethodReference actualMethodReference = actualMethodInfo.Member;
                if (originalMethod.Reference is GenericInstanceMethod)
                {
                    throw new InvalidDataException("Reconstructing an invocation of a generic instance method? Shouldn't be possible.");
                }
                else if (declaringType is GenericInstanceType)
                {
                    var declaringGit = (GenericInstanceType)declaringType;
                    var returnType   = actualMethodReference.ReturnType;

                    if (TypeUtil.IsOpenType(returnType))
                    {
                        var actualReturnType = JSExpression.SubstituteTypeArgs(TypeInfo, actualMethodReference.ReturnType, actualMethodReference);
                        returnType = actualReturnType;
                    }

                    actualMethodReference = new MethodReference(
                        actualMethodReference.Name, returnType, declaringGit
                        );
                }

                actualMethod = new JSMethod(
                    actualMethodReference, actualMethodInfo,
                    originalMethod.MethodTypes, originalMethod.GenericArguments
                    );
            }

            bool needsExplicitThis = !pa.IsVirtualCall && ILBlockTranslator.NeedsExplicitThis(
                declaringType, declaringTypeDef,
                originalMethod.Method.DeclaringType,
                isSelf, thisReferenceType,
                originalMethod.Method
                );

            JSInvocationExpressionBase invocation;

            if (pa.Property.Property.IsStatic)
            {
                invocation = JSInvocationExpression.InvokeStatic(
                    actualMethod.Reference.DeclaringType,
                    actualMethod,
                    arguments
                    );
            }
            else if (needsExplicitThis)
            {
                invocation = JSInvocationExpression.InvokeBaseMethod(
                    actualMethod.Reference.DeclaringType,
                    actualMethod, pa.ThisReference,
                    arguments
                    );
            }
            else
            {
                invocation = JSInvocationExpression.InvokeMethod(
                    pa.OriginalType, actualMethod, pa.ThisReference, arguments
                    );
            }

            JSExpression replacement;

            if (TypeUtil.IsStruct(pa.Property.Property.ReturnType))
            {
                replacement = new JSResultReferenceExpression(invocation);
            }
            else
            {
                replacement = invocation;
            }

            return(replacement);
        }
Пример #18
0
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetActualType(TypeSystem);
            var targetType  = ce.NewType;

            JSExpression newExpression = null;
            var          innerCast     = ce.Expression as JSCastExpression;

            if (targetType.FullName == "System.ValueType")
            {
                var replacement = ce.Expression;
                ParentNode.ReplaceChild(ce, replacement);
                VisitReplacement(replacement);
                return;
            }
            else if (
                TypeUtil.IsIntegralOrEnum(currentType) &&
                (targetType.MetadataType == MetadataType.Char)
                )
            {
                newExpression = JSInvocationExpression.InvokeStatic(
                    JS.fromCharCode, new[] { ce.Expression }, true
                    );
            }
            else if (
                (currentType.MetadataType == MetadataType.Char) &&
                TypeUtil.IsIntegral(targetType)
                )
            {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                    );
            }
            else if (
                IntroduceEnumCasts.IsEnumOrNullableEnum(currentType)
                )
            {
                TypeInfo enumInfo;
                var      isNullable = TypeUtil.IsNullable(currentType);

                if (isNullable)
                {
                    int temp;
                    var git = (GenericInstanceType)TypeUtil.FullyDereferenceType(currentType, out temp);
                    enumInfo = TypeInfo.Get(git.GenericArguments[0]);
                }
                else
                {
                    enumInfo = TypeInfo.Get(currentType);
                }

                if (enumInfo == null)
                {
                    throw new InvalidOperationException("Unable to extract enum type from typereference " + currentType);
                }

                if (targetType.MetadataType == MetadataType.Boolean)
                {
                    newExpression = new JSBinaryOperatorExpression(
                        JSOperator.NotEqual,
                        JSCastExpression.New(ce.Expression, TypeSystem.Int32, TypeSystem, true, true),
                        new JSIntegerLiteral(0, typeof(Int32)),
                        TypeSystem.Boolean
                        );
                }
                else if (TypeUtil.IsNumeric(targetType))
                {
                    if (isNullable)
                    {
                        newExpression = new JSNullableCastExpression(ce.Expression, new JSType(targetType));
                    }
                    else if (
                        ce.Expression is JSCastExpression &&
                        (((JSCastExpression)ce.Expression).Expression.GetActualType(TypeSystem).MetadataType == MetadataType.Int64 ||
                         ((JSCastExpression)ce.Expression).Expression.GetActualType(TypeSystem).MetadataType == MetadataType.UInt64)
                        )
                    {
                        newExpression = ce.Expression;
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(targetType), ce.Expression, null, true
                            );
                    }
                }
                else if (targetType.FullName == "System.Enum")
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    // Debugger.Break();
                }
            }
            else if (
                (targetType.MetadataType == MetadataType.Boolean) &&
                (ce.Expression is JSAsExpression) &&
                ((JSAsExpression)ce.Expression).GetActualType(TypeSystem) is GenericParameter
                )
            {
                // C# expressions such as (t is T) (where T is a generic parameter). See issue #150.
                // Tested with AsWithGenericParameter.cs
                newExpression = new JSBinaryOperatorExpression(
                    JSOperator.NotEqual,
                    ce.Expression, new JSNullLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                (targetType.MetadataType == MetadataType.Boolean) &&
                // A cast from Object to Boolean can occur in two forms:
                // An implied conversion, where an object expression is treated as a boolean (logicnot operation, etc).
                //  In this case, we want to do 'obj != null' to make it a boolean.
                // An explicit conversion, where an object expression is unboxed to boolean.
                //  In this case we want to leave it as-is.
                (ce.IsCoercion || (currentType.FullName != "System.Object"))
                )
            {
                newExpression = new JSBinaryOperatorExpression(
                    JSOperator.NotEqual,
                    ce.Expression, new JSDefaultValueLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                TypeUtil.IsNumeric(targetType) &&
                TypeUtil.IsNumeric(currentType) &&
                !TypeUtil.TypesAreEqual(targetType, currentType, true)
                )
            {
                TypeReference innerType = null;
                if (innerCast != null)
                {
                    innerType = innerCast.Expression.GetActualType(TypeSystem);
                }

                if (
                    TypeUtil.TypesAreAssignable(TypeInfo, targetType, innerType) &&
                    (
                        (TypeUtil.IsFloatingPoint(targetType) == TypeUtil.IsFloatingPoint(currentType)) &&
                        (TypeUtil.IsFloatingPoint(targetType) == TypeUtil.IsFloatingPoint(innerType))
                    ) &&
                    (TypeUtil.IsSigned(targetType) == TypeUtil.IsSigned(innerType)) &&
                    (TypeUtil.SizeOfType(targetType) <= TypeUtil.SizeOfType(currentType)) &&
                    (TypeUtil.SizeOfType(targetType) >= TypeUtil.SizeOfType(innerType))
                    )
                {
                    // HACK: Turn pointless conversions like '(int32)(int64)(1 + 2)' into '(1 + 2)'
                    newExpression = innerCast.Expression;
                }
                else if (currentType.MetadataType == MetadataType.Int64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else if (targetType.MetadataType == MetadataType.UInt64)
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToUInt64", TypeSystem.UInt64, new TypeReference[] { }, MethodTypeFactory),
                            ce.Expression);
                    }
                    else
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToNumber", targetType, new TypeReference[] { TypeSystem.Double, TypeSystem.Boolean }, MethodTypeFactory),
                            ce.Expression,
                            GetInt64ConversionArgs(targetType));
                    }
                }
                else if (currentType.MetadataType == MetadataType.UInt64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else if (targetType.MetadataType == MetadataType.Int64)
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToInt64", TypeSystem.Int64, new TypeReference[] { }, MethodTypeFactory),
                            ce.Expression);
                    }
                    else
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToNumber", targetType, new TypeReference[] { TypeSystem.Double, TypeSystem.Boolean }, MethodTypeFactory),
                            ce.Expression,
                            GetInt64ConversionArgs(targetType));
                    }
                }
                else if (targetType.MetadataType == MetadataType.Int64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeStatic(
                            new JSType(TypeSystem.Int64),
                            new JSFakeMethod("FromNumber", TypeSystem.Int64, new[] { currentType }, MethodTypeFactory),
                            new[] { ce.Expression }, true
                            );
                    }
                }
                else if (targetType.MetadataType == MetadataType.UInt64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeStatic(
                            new JSType(TypeSystem.UInt64),
                            new JSFakeMethod("FromNumber", TypeSystem.UInt64, new[] { currentType }, MethodTypeFactory),
                            new[] { ce.Expression }, true
                            );
                    }
                }
                else if (TypeUtil.IsIntegral(currentType))
                {
                    if (!TypeUtil.IsIntegral(targetType))
                    {
                        // Integer -> float conversion
                        newExpression = new JSIntegerToFloatExpression(ce.Expression, targetType);
                    }
                    else if (TypeUtil.SizeOfType(currentType) < TypeUtil.SizeOfType(targetType))
                    {
                        // Widening integer -> integer conversion
                        newExpression = ce.Expression;
                    }
                    else
                    {
                        newExpression = null;
                    }
                }
                else if (TypeUtil.IsIntegral(targetType))
                {
                    newExpression = new JSTruncateExpression(ce.Expression);
                }
                else if (TypeUtil.SizeOfType(targetType) < TypeUtil.SizeOfType(currentType))
                {
                    // Narrowing double -> float conversion
                    newExpression = new JSDoubleToFloatExpression(ce.Expression);
                }
                else
                {
                    // Widening float -> double conversion
                    newExpression = new JSFloatToDoubleExpression(ce.Expression);
                }
            }
            else
            {
                // newExpression = JSIL.Cast(ce.Expression, targetType);
            }

            if ((newExpression != null) && (newExpression != ce))
            {
                ParentNode.ReplaceChild(ce, newExpression);
                VisitReplacement(newExpression);
            }
            else
            {
                // Debugger.Break();
                VisitChildren(ce);
            }
        }
Пример #19
0
 protected JSInvocationExpression CastToInteger(JSExpression charExpression)
 {
     return(JSInvocationExpression.InvokeMethod(
                JS.charCodeAt, charExpression, new[] { JSLiteral.New(0) }, true
                ));
 }
Пример #20
0
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetActualType(TypeSystem);
            var targetType  = ce.NewType;

            JSExpression newExpression = null;

            if (targetType.FullName == "System.ValueType")
            {
                var replacement = ce.Expression;
                ParentNode.ReplaceChild(ce, replacement);
                VisitReplacement(replacement);
                return;
            }
            else if (targetType.MetadataType == MetadataType.Char)
            {
                newExpression = JSInvocationExpression.InvokeStatic(
                    JS.fromCharCode, new[] { ce.Expression }, true
                    );
            }
            else if (
                (currentType.MetadataType == MetadataType.Char) &&
                TypeUtil.IsIntegral(targetType)
                )
            {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                    );
            }
            else if (
                IntroduceEnumCasts.IsEnumOrNullableEnum(currentType)
                )
            {
                var enumInfo   = TypeInfo.Get(currentType);
                var isNullable = TypeUtil.IsNullable(currentType);

                if (targetType.MetadataType == MetadataType.Boolean)
                {
                    EnumMemberInfo enumMember;
                    if (enumInfo.ValueToEnumMember.TryGetValue(0, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.NotEqual, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else if (enumInfo.ValueToEnumMember.TryGetValue(1, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.Equal, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else
                    {
                        newExpression = new JSUntranslatableExpression(String.Format(
                                                                           "Could not cast enum of type '{0}' to boolean because it has no zero value or one value",
                                                                           currentType.FullName
                                                                           ));
                    }
                }
                else if (TypeUtil.IsNumeric(targetType))
                {
                    if (isNullable)
                    {
                        newExpression = JSIL.ValueOfNullable(
                            ce.Expression
                            );
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(targetType), ce.Expression, null, true
                            );
                    }
                }
                else if (targetType.FullName == "System.Enum")
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    // Debugger.Break();
                }
            }
            else if (
                (targetType.MetadataType == MetadataType.Boolean) &&
                // A cast from Object to Boolean can occur in two forms:
                // An implied conversion, where an object expression is treated as a boolean (logicnot operation, etc).
                //  In this case, we want to do 'obj != null' to make it a boolean.
                // An explicit conversion, where an object expression is unboxed to boolean.
                //  In this case we want to leave it as-is.
                (ce.IsCoercion || (currentType.FullName != "System.Object"))
                )
            {
                newExpression = new JSBinaryOperatorExpression(
                    JSBinaryOperator.NotEqual,
                    ce.Expression, new JSDefaultValueLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                TypeUtil.IsNumeric(targetType) &&
                TypeUtil.IsNumeric(currentType)
                )
            {
                if (
                    TypeUtil.IsIntegral(currentType) ||
                    !TypeUtil.IsIntegral(targetType)
                    )
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    newExpression = new JSTruncateExpression(ce.Expression);
                }
            }
            else
            {
                // newExpression = JSIL.Cast(ce.Expression, targetType);
            }

            if (newExpression != null)
            {
                ParentNode.ReplaceChild(ce, newExpression);
                VisitReplacement(newExpression);
            }
            else
            {
                // Debugger.Break();
                VisitChildren(ce);
            }
        }