예제 #1
0
 public void VisitNode(JSIndexerExpression idx)
 {
     Visit(idx.Target);
     Output.OpenBracket();
     Visit(idx.Index);
     Output.CloseBracket();
 }
예제 #2
0
        protected void TranslateMethodGroup(DecompilerContext context, JavascriptFormatter output, MethodGroupInfo methodGroup)
        {
            var methods = (from m in methodGroup.Methods where !m.IsIgnored select m).ToArray();
            if (methods.Length < 1)
                return;

            foreach (var method in methods) {
                foreach (var p in method.Member.Parameters) {
                    var resolved = p.ParameterType.Resolve();
                    if ((resolved != null) &&
                        !DeclaredTypes.Contains(resolved.FullName) &&
                        (resolved.Module.Assembly == methodGroup.DeclaringType.Definition.Module.Assembly)
                    ) {
                        ForwardDeclareType(context, output, resolved);
                    }
                }
            }

            output.Identifier(
                (methods.First().IsGeneric) ? "JSIL.OverloadedGenericMethod" : "JSIL.OverloadedMethod", null
            );
            output.LPar();

            output.Identifier(methodGroup.DeclaringType.Definition);
            if (!methodGroup.IsStatic) {
                output.Dot();
                output.Keyword("prototype");
            }

            output.Comma();
            output.Value(Util.EscapeIdentifier(methodGroup.Name));
            output.Comma();
            output.OpenBracket(true);

            bool isFirst = true;
            foreach (var method in methods) {
                if (!isFirst) {
                    output.Comma();
                    output.NewLine();
                }

                output.OpenBracket();
                output.Value(Util.EscapeIdentifier(method.GetName(true)));
                output.Comma();

                output.OpenBracket();
                output.CommaSeparatedList(
                    from p in method.Member.Parameters select p.ParameterType, ListValueType.TypeIdentifier
                );
                output.CloseBracket();

                output.CloseBracket();
                isFirst = false;
            }

            output.CloseBracket(true, () => {
                output.RPar();
                output.Semicolon();
            });
        }
예제 #3
0
        protected void TranslateMethod(
            DecompilerContext context, JavascriptFormatter output, 
            MethodReference methodRef, MethodDefinition method, 
            bool stubbed, 
            HashSet<string> externalMemberNames,
            HashSet<string> staticExternalMemberNames,
            Action<JSFunctionExpression> bodyTransformer = null
        )
        {
            var methodInfo = TypeInfoProvider.GetMemberInformation<Internal.MethodInfo>(method);
            if (methodInfo == null)
                return;

            bool isReplaced = methodInfo.Metadata.HasAttribute("JSIL.Meta.JSReplacement");
            bool methodIsProxied = (methodInfo.IsFromProxy && methodInfo.Member.HasBody) &&
                !methodInfo.IsExternal && !isReplaced;

            if (methodInfo.IsExternal || (stubbed && !methodIsProxied)) {
                if (isReplaced)
                    return;

                if (externalMemberNames == null)
                    throw new ArgumentNullException("externalMemberNames");
                if (staticExternalMemberNames == null)
                    throw new ArgumentNullException("staticExternalMemberNames");

                var isProperty = methodInfo.DeclaringProperty != null;

                if (!isProperty || !methodInfo.Member.IsCompilerGenerated()) {
                    (method.IsStatic ? staticExternalMemberNames : externalMemberNames)
                        .Add(Util.EscapeIdentifier(methodInfo.GetName(true)));

                    return;
                }
            }

            if (methodInfo.IsIgnored)
                return;
            if (!method.HasBody)
                return;

            if (methodIsProxied) {
                output.Comment("Implementation from {0}", methodInfo.Member.DeclaringType.FullName);
                output.NewLine();
            }

            output.Identifier(method.DeclaringType);
            if (!method.IsStatic) {
                output.Dot();
                output.Keyword("prototype");
            }
            output.Dot();

            output.Identifier(methodInfo.GetName(true));

            output.Token(" = ");

            if (method.HasGenericParameters) {
                output.Identifier("JSIL.GenericMethod", null);
                output.LPar();
                output.NewLine();
                output.OpenBracket();

                output.CommaSeparatedList((from p in method.GenericParameters select p.Name), ListValueType.Primitive);

                output.CloseBracket();
                output.Comma();
                output.NewLine();
            }

            JSFunctionExpression function;
            function = FunctionCache.GetExpression(new QualifiedMemberIdentifier(
                methodInfo.DeclaringType.Identifier,
                methodInfo.Identifier
            ));

            if (bodyTransformer != null)
                bodyTransformer(function);

            if (function != null) {
                AstEmitter.Visit(function);
            } else {
                output.Identifier("JSIL.UntranslatableFunction", null);
                output.LPar();
                output.Value(method.FullName);
                output.RPar();
            }

            if (method.HasGenericParameters) {
                output.NewLine();
                output.RPar();
            }

            output.Semicolon();
        }
예제 #4
0
        protected void TranslateInterface(DecompilerContext context, JavascriptFormatter output, TypeDefinition iface)
        {
            output.Identifier("JSIL.MakeInterface", null);
            output.LPar();
            output.NewLine();

            output.Value(Util.EscapeIdentifier(iface.FullName, EscapingMode.String));
            output.Comma();

            output.OpenBracket();
            output.CommaSeparatedList(
                (from p in iface.GenericParameters select p.Name), ListValueType.Primitive
            );
            output.CloseBracket();
            output.Comma();

            output.OpenBrace();

            bool isFirst = true;
            foreach (var m in iface.Methods) {
                var methodInfo = TypeInfoProvider.GetMethod(m);
                if ((methodInfo != null) && methodInfo.IsIgnored)
                    continue;

                if (!isFirst) {
                    output.Comma();
                    output.NewLine();
                }

                output.Value(Util.EscapeIdentifier(m.Name));
                output.Token(": ");
                output.Identifier("Function");

                isFirst = false;
            }

            foreach (var p in iface.Properties) {
                var propertyInfo = TypeInfoProvider.GetProperty(p);
                if ((propertyInfo != null) && propertyInfo.IsIgnored)
                    continue;

                if (!isFirst) {
                    output.Comma();
                    output.NewLine();
                }

                output.Value(Util.EscapeIdentifier(p.Name));
                output.Token(": ");
                output.Identifier("Property");

                isFirst = false;
            }

            output.NewLine();
            output.CloseBrace(false);

            output.RPar();
            output.Semicolon();
            output.NewLine();
        }
예제 #5
0
        protected void ForwardDeclareType(DecompilerContext context, JavascriptFormatter output, TypeDefinition typedef)
        {
            var typeInfo = TypeInfoProvider.GetTypeInformation(typedef);
            if ((typeInfo == null) || typeInfo.IsIgnored || typeInfo.IsProxy)
                return;

            if (DeclaredTypes.Contains(typedef.FullName)) {
                Debug.WriteLine("Cycle in type references detected: {0}", typedef);
                return;
            }

            context.CurrentType = typedef;

            output.DeclareNamespace(typedef.Namespace);

            DeclaredTypes.Add(typedef.FullName);

            if (typedef.IsInterface) {
                TranslateInterface(context, output, typedef);
                return;
            } else if (typedef.IsEnum) {
                TranslateEnum(context, output, typedef);
                return;
            } else if (typeInfo.IsDelegate) {
                TranslateDelegate(context, output, typedef, typeInfo);
                return;
            }

            var declaringType = typedef.DeclaringType;
            if (declaringType != null) {
                if (!DeclaredTypes.Contains(declaringType.FullName))
                    ForwardDeclareType(context, output, declaringType);
            }

            var baseClass = typedef.Module.TypeSystem.Object;
            if (typedef.BaseType != null) {
                baseClass = typedef.BaseType;

                var resolved = baseClass.Resolve();
                if (
                    (resolved != null) &&
                    !DeclaredTypes.Contains(resolved.FullName) &&
                    (resolved.Module.Assembly == typedef.Module.Assembly)
                ) {
                    ForwardDeclareType(context, output, resolved);
                }
            }

            bool isStatic = typedef.IsAbstract && typedef.IsSealed;

            if (isStatic) {
                output.Identifier("JSIL.MakeStaticClass", null);
                output.LPar();

                output.Value(Util.EscapeIdentifier(typedef.FullName, EscapingMode.String));
                output.Comma();
                output.Value(typedef.IsPublic);

                if (typedef.HasGenericParameters) {
                    output.Comma();
                    output.OpenBracket();
                    output.CommaSeparatedList(
                        (from p in typedef.GenericParameters select p.Name), ListValueType.Primitive
                    );
                    output.CloseBracket();
                }

                output.RPar();
                output.Semicolon();
            } else {
                if (typedef.IsValueType)
                    output.Identifier("JSIL.MakeStruct", null);
                else
                    output.Identifier("JSIL.MakeClass", null);

                output.LPar();
                if (!typedef.IsValueType) {
                    output.TypeReference(baseClass);
                    output.Comma();
                }

                output.Value(Util.EscapeIdentifier(typedef.FullName, EscapingMode.String));
                output.Comma();
                output.Value(typedef.IsPublic);

                if (typedef.HasGenericParameters) {
                    output.Comma();
                    output.OpenBracket();
                    output.CommaSeparatedList(
                        (from p in typedef.GenericParameters select p.Name), ListValueType.Primitive
                    );
                    output.CloseBracket();
                }

                output.RPar();
                output.Semicolon();
            }

            foreach (var nestedTypeDef in typedef.NestedTypes) {
                if (!DeclaredTypes.Contains(nestedTypeDef.FullName))
                    ForwardDeclareType(context, output, nestedTypeDef);
            }

            output.NewLine();
        }
예제 #6
0
        protected void TranslateTypeDefinition(DecompilerContext context, JavascriptFormatter output, TypeDefinition typedef, List<Action> initializer, bool stubbed)
        {
            var typeInfo = TypeInfoProvider.GetTypeInformation(typedef);
            if (!ShouldTranslateMethods(typedef))
                return;

            context.CurrentType = typedef;

            var externalMemberNames = new HashSet<string>();
            var staticExternalMemberNames = new HashSet<string>();

            foreach (var method in typedef.Methods) {
                // We translate the static constructor explicitly later, and inject field initialization
                if (method.Name == ".cctor")
                    continue;

                TranslateMethod(
                    context, output, method, method,
                    stubbed, externalMemberNames, staticExternalMemberNames
                );
            }

            Action initializeOverloadsAndProperties = () => {
                foreach (var methodGroup in typeInfo.MethodGroups)
                    TranslateMethodGroup(context, output, methodGroup);

                foreach (var property in typedef.Properties)
                    TranslateProperty(context, output, property);
            };

            if (!stubbed)
                initializeOverloadsAndProperties();

            Func<TypeReference, bool> isInterfaceIgnored = (i) => {
                var interfaceInfo = TypeInfoProvider.GetTypeInformation(i);
                if (interfaceInfo != null)
                    return interfaceInfo.IsIgnored;
                else
                    return true;
            };

            var interfaces = (from i in typeInfo.Interfaces
                              where !i.IsIgnored
                              select i).ToArray();

            if (interfaces.Length > 0) {
                initializer.Add(() => {
                    output.Identifier("JSIL.ImplementInterfaces", null);
                    output.LPar();
                    output.Identifier(typedef);
                    output.Comma();
                    output.OpenBracket(true);
                    output.CommaSeparatedList(interfaces, ListValueType.TypeReference);
                    output.CloseBracket(true, () => {
                        output.RPar();
                        output.Semicolon();
                    });
                });
            }

            Func<FieldDefinition, bool> isFieldIgnored = (f) => {
                IMemberInfo memberInfo;
                if (typeInfo.Members.TryGetValue(MemberIdentifier.New(f), out memberInfo))
                    return memberInfo.IsIgnored;
                else
                    return true;
            };

            var structFields =
                (from field in typedef.Fields
                where !isFieldIgnored(field) &&
                    !field.HasConstant &&
                    EmulateStructAssignment.IsStruct(field.FieldType) &&
                    !field.IsStatic
                select field).ToArray();

            if (structFields.Length > 0) {
                initializer.Add(() => {
                    output.Identifier(typedef);
                    output.Dot();
                    output.Identifier("prototype");
                    output.Dot();
                    output.Identifier("__StructFields__");
                    output.Token(" = ");
                    output.OpenBracket(true);

                    bool isFirst = true;
                    foreach (var sf in structFields) {
                        if (!isFirst) {
                            output.Comma();
                            output.NewLine();
                        }

                        output.OpenBracket();
                        output.Value(sf.Name);
                        output.Comma();
                        output.Identifier(sf.FieldType);
                        output.CloseBracket();

                        isFirst = false;
                    }

                    output.CloseBracket(true, output.Semicolon);
                });
            }

            TranslateTypeStaticConstructor(context, output, typedef, typeInfo.StaticConstructor, stubbed);

            if (externalMemberNames.Count + staticExternalMemberNames.Count > 0) {
                initializer.Add(() => {
                    if (externalMemberNames.Count > 0) {
                        output.Identifier("JSIL.ExternalMembers", null);
                        output.LPar();
                        output.Identifier(typedef);
                        output.Dot();
                        output.Keyword("prototype");
                        output.Comma();
                        output.NewLine();

                        output.CommaSeparatedList(externalMemberNames, ListValueType.Primitive);
                        output.NewLine();

                        output.RPar();
                        output.Semicolon();
                    }

                    if (staticExternalMemberNames.Count > 0) {
                        output.Identifier("JSIL.ExternalMembers", null);
                        output.LPar();
                        output.Identifier(typedef);
                        output.Comma();
                        output.NewLine();

                        output.CommaSeparatedList(staticExternalMemberNames, ListValueType.Primitive);
                        output.NewLine();

                        output.RPar();
                        output.Semicolon();
                    }
                });
            }

            if (stubbed &&
                (typeInfo.MethodGroups.Count + typedef.Properties.Count) > 0
            ) {
                initializer.Add(initializeOverloadsAndProperties);
            }

            output.NewLine();

            foreach (var nestedTypedef in typedef.NestedTypes)
                TranslateTypeDefinition(context, output, nestedTypedef, initializer, stubbed);
        }
예제 #7
0
        public void EmitInterfaceDefinition(
            DecompilerContext context, IAstEmitter astEmitter, TypeDefinition iface
            )
        {
            Formatter.Identifier("JSIL.MakeInterface", EscapingMode.None);
            Formatter.LPar();
            Formatter.NewLine();

            Formatter.Value(Util.DemangleCecilTypeName(iface.FullName));
            Formatter.Comma();

            Formatter.Value(iface.IsPublic);
            Formatter.Comma();

            Formatter.OpenBracket();
            WriteGenericParameterNames(iface.GenericParameters);
            Formatter.CloseBracket();

            Formatter.Comma();
            Formatter.OpenFunction(null, (f) =>
                                   f.Identifier("$")
                                   );

            var refContext = new TypeReferenceContext {
                EnclosingType = iface,
                DefiningType  = iface
            };

            bool isFirst = true;

            foreach (var methodGroup in iface.Methods.GroupBy(md => md.Name))
            {
                foreach (var m in methodGroup)
                {
                    if (Translator.ShouldSkipMember(m))
                    {
                        continue;
                    }

                    var methodInfo = _TypeInfoProvider.GetMethod(m);

                    if ((methodInfo == null) || methodInfo.IsIgnored)
                    {
                        continue;
                    }

                    Formatter.Identifier("$", EscapingMode.None);
                    Formatter.Dot();
                    Formatter.Identifier("Method", EscapingMode.None);
                    Formatter.LPar();

                    Formatter.WriteRaw("{}");
                    Formatter.Comma();

                    Formatter.Value(Util.EscapeIdentifier(m.Name, EscapingMode.String));
                    Formatter.Comma();

                    Formatter.MethodSignature(m, methodInfo.Signature, refContext);

                    Formatter.RPar();
                    Formatter.Semicolon(true);
                }
            }

            foreach (var p in iface.Properties)
            {
                var propertyInfo = _TypeInfoProvider.GetProperty(p);
                if ((propertyInfo != null) && propertyInfo.IsIgnored)
                {
                    continue;
                }

                Formatter.Identifier("$", EscapingMode.None);
                Formatter.Dot();
                Formatter.Identifier("Property", EscapingMode.None);
                Formatter.LPar();

                Formatter.WriteRaw("{}");
                Formatter.Comma();

                Formatter.Value(Util.EscapeIdentifier(p.Name, EscapingMode.String));

                Formatter.RPar();
                Formatter.Semicolon(true);
            }

            Formatter.CloseBrace(false);

            Formatter.Comma();

            refContext = new TypeReferenceContext {
                EnclosingType = iface.DeclaringType,
                DefiningType  = iface
            };

            Formatter.OpenBracket();
            foreach (var i in iface.Interfaces)
            {
                if (!isFirst)
                {
                    Formatter.Comma();
                }

                Formatter.TypeReference(i, refContext);

                isFirst = false;
            }
            Formatter.CloseBracket();

            Formatter.RPar();

            EmitCustomAttributes(context, iface, iface, astEmitter);

            Formatter.Semicolon();
            Formatter.NewLine();
        }