상속: JSIdentifier
예제 #1
0
        public EmulateInt64(MethodTypeFactory methodTypeFactory, TypeSystem typeSystem)
        {
            TypeSystem = typeSystem;
            MethodTypeFactory = methodTypeFactory;

            int64 = new JSType(TypeSystem.Int64);

            uint64 = new JSType(TypeSystem.UInt64);
        }
예제 #2
0
        public void VisitNode (JSType type) {
            var ct = GetCachedType(type.Type);

            if (ct != null) {
                ParentNode.ReplaceChild(type, ct);
                VisitReplacement(ct);
            } else {
                VisitChildren(type);
            }
        }
예제 #3
0
        public void VisitNode (JSPublicInterfaceOfExpression poe) {
            VisitChildren(poe);

            // Replace foo.__Type__.__PublicInterface__ with foo
            var innerTypeOf = poe.Inner as ITypeOfExpression;
            if (innerTypeOf != null) {
                var replacement = new JSType(innerTypeOf.Type);

                ParentNode.ReplaceChild(poe, replacement);
                VisitReplacement(replacement);
            }
        }
예제 #4
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 "GetType":
                            JSNode replacement;

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

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

                            return;
                    }
                } else if (
                    (type != null) &&
                    (type.Type.FullName.StartsWith("System.Nullable")) &&
                    (type.Type is GenericInstanceType)
                ) {
                    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) &&
                    ILBlockTranslator.TypesAreEqual(TypeSystem.String, type.Type) &&
                    (method.Method.Name == "Concat")
                ) {
                    if (ie.Arguments.Count > 2) {
                        if (ie.Arguments.All(
                            (arg) => ILBlockTranslator.TypesAreEqual(
                                TypeSystem.String, arg.GetExpectedType(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 = ILBlockTranslator.DereferenceType(lhs.GetExpectedType(TypeSystem));
                        if (!(
                            ILBlockTranslator.TypesAreEqual(TypeSystem.String, lhsType) ||
                            ILBlockTranslator.TypesAreEqual(TypeSystem.Char, lhsType)
                        )) {
                            lhs = JSInvocationExpression.InvokeMethod(lhsType, JS.toString, lhs, null);
                        }

                        var rhs = ie.Arguments[1];
                        var rhsType = ILBlockTranslator.DereferenceType(rhs.GetExpectedType(TypeSystem));
                        if (!(
                            ILBlockTranslator.TypesAreEqual(TypeSystem.String, rhsType) ||
                            ILBlockTranslator.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 (
                        ILBlockTranslator.GetTypeDefinition(ie.Arguments[0].GetExpectedType(TypeSystem)).FullName == "System.Array"
                    ) {
                    } else {
                        var firstArg = ie.Arguments.FirstOrDefault();

                        ParentNode.ReplaceChild(
                            ie, firstArg
                        );

                        if (firstArg != null)
                            VisitReplacement(firstArg);
                    }
                    return;
                } else if (
                    ILBlockTranslator.IsDelegateType(method.Reference.DeclaringType) &&
                    (method.Method.Name == "Invoke")
                ) {
                    var newIe = new JSDelegateInvocationExpression(
                        thisExpression, ie.GetExpectedType(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.GetExpectedType(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.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);
        }
예제 #5
0
        protected JSExpression Translate_PropertyCall(JSExpression thisExpression, JSMethod method, JSExpression[] arguments, bool @virtual, bool @static)
        {
            var propertyInfo = method.Method.DeclaringProperty;
            if (propertyInfo == null)
                return null;

            if (propertyInfo.IsIgnored)
                return new JSIgnoredMemberReference(true, propertyInfo, arguments);

            // JS provides no way to override [], so keep it as a regular method call
            if (propertyInfo.Member.IsIndexer())
                return null;

            var parms = method.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSReplacement") ??
                propertyInfo.Metadata.GetAttributeParameters("JSIL.Meta.JSReplacement");
            if (parms != null) {
                var argsDict = new Dictionary<string, JSExpression>();
                argsDict["this"] = thisExpression;
                argsDict["typeof(this)"] = new JSType(thisExpression.GetExpectedType(TypeSystem));

                foreach (var kvp in method.Method.Parameters.Zip(arguments, (p, v) => new { p.Name, Value = v })) {
                    argsDict.Add(kvp.Name, kvp.Value);
                }

                return new JSVerbatimLiteral(method, (string)parms[0].Value, argsDict, propertyInfo.ReturnType);
            }

            var thisType = GetTypeDefinition(thisExpression.GetExpectedType(TypeSystem));
            Func<JSExpression> generate = () => {
                var actualThis = @static ? new JSType(method.Method.DeclaringType.Definition) : thisExpression;

                if ((method.Reference.DeclaringType is GenericInstanceType) && !method.Reference.HasThis) {
                    actualThis = new JSType(method.Reference.DeclaringType);
                }

                if ((propertyInfo.Member.GetMethod != null) && (method.Method.Member.Name == propertyInfo.Member.GetMethod.Name)) {
                    return new JSPropertyAccess(
                        actualThis, new JSProperty(method.Reference, propertyInfo)
                    );
                } else {
                    if (arguments.Length == 0)
                        throw new InvalidOperationException("Attempting to invoke a property setter with no arguments");

                    return new JSBinaryOperatorExpression(
                        JSOperator.Assignment,
                        new JSPropertyAccess(
                            actualThis, new JSProperty(method.Reference, propertyInfo)
                        ),
                        arguments[0], propertyInfo.ReturnType
                    );
                }
            };

            // Accesses to a base property should go through a regular method invocation, since
            //  javascript properties do not have a mechanism for base access
            if (method.Method.Member.HasThis) {
                if (!TypesAreEqual(method.Method.DeclaringType.Definition, thisType) && !@virtual) {
                    return null;
                } else {
                    return generate();
                }
            }

            return generate();
        }
예제 #6
0
        protected JSExpression Translate_MethodReplacement(
            JSMethod method, JSExpression thisExpression, 
            JSExpression[] arguments, bool @virtual, bool @static, bool explicitThis
        )
        {
            var methodInfo = method.Method;
            var metadata = methodInfo.Metadata;

            if (metadata != null) {
                var parms = metadata.GetAttributeParameters("JSIL.Meta.JSReplacement");
                if (parms != null) {
                    var argsDict = new Dictionary<string, JSExpression>();
                    argsDict["this"] = thisExpression;
                    argsDict["typeof(this)"] = new JSType(thisExpression.GetExpectedType(TypeSystem));

                    foreach (var kvp in methodInfo.Parameters.Zip(arguments, (p, v) => new { p.Name, Value = v })) {
                        argsDict.Add(kvp.Name, kvp.Value);
                    }

                    return new JSVerbatimLiteral(
                        method, (string)parms[0].Value, argsDict, method.Method.ReturnType
                    );
                }
            }

            if (methodInfo.IsIgnored)
                return new JSIgnoredMemberReference(true, methodInfo, new[] { thisExpression }.Concat(arguments).ToArray());

            switch (method.Method.Member.FullName) {
                case "System.Object JSIL.Builtins::Eval(System.String)":
                    return JSInvocationExpression.InvokeStatic(
                        JS.eval, arguments
                    );
                case "System.Object JSIL.Verbatim::Expression(System.String)": {
                    var expression = arguments[0] as JSStringLiteral;
                    if (expression == null)
                        throw new InvalidOperationException("JSIL.Verbatim.Expression must recieve a string literal as an argument");

                    return new JSVerbatimLiteral(
                        method, expression.Value, null, null
                    );
                }
                case "System.Object JSIL.JSGlobal::get_Item(System.String)": {
                    var expression = arguments[0] as JSStringLiteral;
                    if (expression != null)
                        return new JSDotExpression(
                            JSIL.GlobalNamespace, new JSStringIdentifier(expression.Value, TypeSystem.Object)
                        );
                    else
                        return new JSIndexerExpression(
                            JSIL.GlobalNamespace, arguments[0], TypeSystem.Object
                        );
                }
                case "System.Object JSIL.JSLocal::get_Item(System.String)": {
                    var expression = arguments[0] as JSStringLiteral;
                    if (expression == null)
                        throw new InvalidOperationException("JSLocal must recieve a string literal as an index");

                    return new JSStringIdentifier(expression.Value, TypeSystem.Object);
                }
                case "System.Object JSIL.Builtins::get_This()":
                    return new JSIndirectVariable(Variables, "this", ThisMethodReference);
            }

            JSExpression result = Translate_PropertyCall(thisExpression, method, arguments, @virtual, @static);
            if (result == null) {
                if (@static)
                    result = JSInvocationExpression.InvokeStatic(method.Reference.DeclaringType, method, arguments);
                else if (explicitThis)
                    result = JSInvocationExpression.InvokeBaseMethod(method.Reference.DeclaringType, method, thisExpression, arguments);
                else
                    result = JSInvocationExpression.InvokeMethod(method.Reference.DeclaringType, method, thisExpression, arguments);
            }

            return result;
        }