Пример #1
0
        public void NodeChildren () {
            var de = new JSDotExpression(JSLiteral.New(1), new JSStringIdentifier("2"));
            var boe = new JSBinaryOperatorExpression(JSOperator.Add, JSLiteral.New(1), JSLiteral.New(2), T1);

            Assert.AreEqual(2, de.Children.Count());
            Assert.AreEqual(2, boe.Children.Count());
        }
Пример #2
0
        public JSILIdentifier(TypeSystem typeSystem, JSSpecialIdentifiers js)
        {
            TypeSystem = typeSystem;
            JS = js;

            GlobalNamespace = Dot("GlobalNamespace", TypeSystem.Object);
            CopyMembers = Dot("CopyMembers", TypeSystem.Void);
        }
Пример #3
0
        public JSSpecialIdentifiers (MethodTypeFactory methodTypes, TypeSystem typeSystem) {
            TypeSystem = typeSystem;
            MethodTypes = methodTypes;

            prototype = Object("prototype");
            eval = new JSFakeMethod("eval", TypeSystem.Object, new[] { TypeSystem.String }, methodTypes);
            toString = new JSFakeMethod("toString", TypeSystem.String, null, methodTypes);
            floor = new JSDotExpression(Object("Math"), new JSFakeMethod("floor", TypeSystem.Int32, null, methodTypes));
            fromCharCode = new JSDotExpression(Object("String"), new JSFakeMethod("fromCharCode", TypeSystem.Char, new[] { TypeSystem.Int32 }, methodTypes));
            charCodeAt = new JSFakeMethod("charCodeAt", TypeSystem.Int32, new[] { TypeSystem.Char }, methodTypes);
        }
Пример #4
0
        public JSSpecialIdentifiers(MethodTypeFactory methodTypes, TypeSystem typeSystem)
        {
            TypeSystem  = typeSystem;
            MethodTypes = methodTypes;

            prototype    = Object("prototype");
            eval         = new JSFakeMethod("eval", TypeSystem.Object, new[] { TypeSystem.String }, methodTypes);
            toString     = new JSFakeMethod("toString", TypeSystem.String, null, methodTypes);
            floor        = new JSDotExpression(Object("Math"), new JSFakeMethod("floor", TypeSystem.Int32, null, methodTypes));
            fromCharCode = new JSDotExpression(Object("String"), new JSFakeMethod("fromCharCode", TypeSystem.Char, new[] { TypeSystem.Int32 }, methodTypes));
            charCodeAt   = new JSFakeMethod("charCodeAt", TypeSystem.Int32, new[] { TypeSystem.Char }, methodTypes);
        }
Пример #5
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;

                return JSDotExpression.New(
                    thisArgument,
                    new JSStringIdentifier(MemberName, returnType)
                );
            }
Пример #6
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;
                }

                return(new JSBinaryOperatorExpression(
                           JSOperator.Assignment,
                           JSDotExpression.New(
                               thisArgument,
                               new JSStringIdentifier(MemberName, returnType, true)
                               ),
                           arguments[2], returnType
                           ));
            }
Пример #7
0
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetExpectedType(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) &&
                ILBlockTranslator.IsIntegral(targetType)
            ) {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                );
            } else if (
                ILBlockTranslator.IsEnum(currentType) &&
                ILBlockTranslator.IsIntegral(targetType)
            ) {
                newExpression = new JSDotExpression(
                    ce.Expression, new JSStringIdentifier("value", targetType)
                );
            } else {
                newExpression = JSIL.Cast(ce.Expression, targetType);
            }

            if (newExpression != null) {
                ParentNode.ReplaceChild(ce, newExpression);
                VisitReplacement(newExpression);
            } else {
                VisitChildren(ce);
            }
        }
Пример #8
0
        protected JSExpression Translate_Ldfld(ILExpression node, FieldReference field)
        {
            var firstArg = node.Arguments[0];
            var translated = TranslateNode(firstArg);

            // GetCallSite and CreateCallSite produce null expressions, so we want to ignore field references containing them
            if ((translated.IsNull) && !(translated is JSUntranslatableExpression) && !(translated is JSIgnoredMemberReference))
                return new JSNullExpression();

            var fieldInfo = TypeInfo.GetField(field);
            if (IsIgnoredType(field.FieldType) || (fieldInfo == null) || fieldInfo.IsIgnored)
                return new JSIgnoredMemberReference(true, fieldInfo, translated);

            JSExpression thisExpression;
            if (IsInvalidThisExpression(firstArg)) {
                if (!JSReferenceExpression.TryDereference(JSIL, translated, out thisExpression)) {
                    if (!translated.IsNull)
                        Console.Error.WriteLine("Warning: Accessing {0} without a reference as this.", field.FullName);

                    thisExpression = translated;
                }
            } else {
                thisExpression = translated;
            }

            JSExpression result = new JSDotExpression(
                thisExpression,
                new JSField(field, fieldInfo)
            );

            if (CopyOnReturn(field.FieldType))
                result = JSReferenceExpression.New(result);

            return result;
        }
Пример #9
0
        private JSForLoop ReplaceWhileLoopAndEnumerator(JSWhileLoop wl, JSExpression backingStore, JSExpression enumerator, TypeInfo enumeratorType, string arrayMember, string lengthMember)
        {
            var loopId             = _NextLoopId++;
            var arrayVariableName  = String.Format("a${0:x}", loopId);
            var indexVariableName  = String.Format("i${0:x}", loopId);
            var lengthVariableName = String.Format("l${0:x}", loopId);

            var currentPropertyReference = enumeratorType.Definition.Properties.First((p) => p.Name == "Current");
            var currentPropertyInfo      = enumeratorType.Source.GetProperty(currentPropertyReference);

            var itemType  = currentPropertyInfo.ReturnType;
            var arrayType = new ArrayType(itemType);

            var arrayVariable = new JSVariable(
                arrayVariableName, arrayType, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(arrayMember, arrayType))
                );
            var indexVariable = new JSVariable(
                indexVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSLiteral.New(0)
                );
            var lengthVariable = new JSVariable(
                lengthVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(lengthMember, TypeSystem.Int32))
                );

            var initializer = new JSVariableDeclarationStatement(
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, arrayVariable, arrayVariable.DefaultValue, arrayVariable.IdentifierType
                    ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, indexVariable, indexVariable.DefaultValue, indexVariable.IdentifierType
                    ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, lengthVariable, lengthVariable.DefaultValue, lengthVariable.IdentifierType
                    )
                );

            var condition = new JSBinaryOperatorExpression(
                JSOperator.LessThan,
                indexVariable, lengthVariable, TypeSystem.Boolean
                );

            var increment = new JSUnaryOperatorExpression(
                JSOperator.PostIncrement,
                indexVariable, TypeSystem.Int32
                );

            var result = new JSForLoop(
                initializer, condition, new JSExpressionStatement(increment),
                wl.Statements.ToArray()
                );

            result.Index = wl.Index;

            new PropertyAccessReplacer(
                enumerator, new JSProperty(currentPropertyReference, currentPropertyInfo),
                new JSIndexerExpression(
                    arrayVariable, indexVariable,
                    itemType
                    )
                ).Visit(result);

            return(result);
        }
Пример #10
0
        protected JSExpression Translate_Ldsfld(ILExpression node, FieldReference field)
        {
            var fieldInfo = TypeInfo.GetField(field);
            if (fieldInfo == null)
                return new JSIgnoredMemberReference(true, null, JSLiteral.New(field.FullName));
            else if (IsIgnoredType(field.FieldType) || fieldInfo.IsIgnored)
                return new JSIgnoredMemberReference(true, fieldInfo);

            JSExpression result = new JSDotExpression(
                new JSType(field.DeclaringType),
                new JSField(field, fieldInfo)
            );

            if (CopyOnReturn(field.FieldType))
                result = JSReferenceExpression.New(result);

            // TODO: When returning a value type we should be returning it by reference, but doing that would break Ldflda.
            return result;
        }
Пример #11
0
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetExpectedType(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) &&
                ILBlockTranslator.IsIntegral(targetType)
            ) {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                );
            } else if (
                ILBlockTranslator.IsEnum(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 (ILBlockTranslator.IsNumeric(targetType)) {
                    newExpression = new JSDotExpression(
                        ce.Expression, new JSStringIdentifier("value", targetType)
                    );
                } 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 (
                ILBlockTranslator.IsNumeric(targetType) &&
                ILBlockTranslator.IsNumeric(currentType)
            ) {
                if (
                    ILBlockTranslator.IsIntegral(currentType) ||
                    !ILBlockTranslator.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);
            }
        }
Пример #12
0
        public JSSpecialIdentifiers(TypeSystem typeSystem)
        {
            TypeSystem = typeSystem;

            prototype = Object("prototype");
            eval = new JSFakeMethod("eval", TypeSystem.Object, TypeSystem.String);
            toString = new JSFakeMethod("toString", TypeSystem.String);
            floor = new JSDotExpression(Object("Math"), new JSFakeMethod("floor", TypeSystem.Int64));
            fromCharCode = new JSDotExpression(Object("String"), new JSFakeMethod("fromCharCode", TypeSystem.Char, TypeSystem.Int32));
            charCodeAt = new JSFakeMethod("charCodeAt", TypeSystem.Int32, TypeSystem.Char);
        }
Пример #13
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);
        }
Пример #14
0
        public void NodeSelfAndChildren () {
            var de = new JSDotExpression(JSLiteral.New(1), new JSStringIdentifier("2"));
            var boe = new JSBinaryOperatorExpression(JSOperator.Add, JSLiteral.New(1), JSLiteral.New(2), T1);

            Assert.AreEqual(3, de.SelfAndChildren.Count());
            Assert.AreEqual(3, boe.SelfAndChildren.Count());
            Assert.AreEqual(de, de.SelfAndChildren.First());
            Assert.AreEqual(boe, boe.SelfAndChildren.First());
        }
Пример #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 "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);
        }
Пример #16
0
        protected JSExpression Translate_Ldsfld(ILExpression node, FieldReference field)
        {
            var fieldInfo = TypeInfo.GetField(field);
            if (fieldInfo == null)
                return new JSIgnoredMemberReference(true, null, JSLiteral.New(field.FullName));
            else if (IsIgnoredType(field.FieldType) || fieldInfo.IsIgnored)
                return new JSIgnoredMemberReference(true, fieldInfo);

            JSExpression result = new JSDotExpression(
                new JSType(field.DeclaringType),
                new JSField(field, fieldInfo)
            );

            if (CopyOnReturn(field.FieldType))
                result = JSReferenceExpression.New(result);

            return result;
        }
Пример #17
0
        protected JSExpression Translate_Stobj(ILExpression node, TypeReference type)
        {
            var target = TranslateNode(node.Arguments[0]);
            var targetVariable = target as JSVariable;
            var value = TranslateNode(node.Arguments[1]);

            if (targetVariable != null) {
                if (!targetVariable.IsReference)
                    Console.Error.WriteLine(String.Format("Warning: unsupported target variable for stobj: {0}", node.Arguments[0]));
            } else {
                JSExpression referent;
                if (!JSReferenceExpression.TryMaterialize(JSIL, target, out referent))
                    Console.Error.WriteLine(String.Format("Warning: unsupported target expression for stobj: {0}", node.Arguments[0]));
                else
                    target = new JSDotExpression(referent, new JSStringIdentifier("value", value.GetExpectedType(TypeSystem)));
            }

            return new JSBinaryOperatorExpression(
                JSOperator.Assignment, target, value, node.ExpectedType ?? node.InferredType
            );
        }
Пример #18
0
 public void VisitNode(JSDotExpression dot)
 {
     VisitDotExpression(dot);
 }