예제 #1
0
        private TypeOOPEmulationPhase CreateTypeDefinitions(JsType type)
        {
            string name       = _metadataImporter.GetTypeSemantics(type.CSharpTypeDefinition).Name;
            bool   isGlobal   = string.IsNullOrEmpty(name);
            bool   isMixin    = MetadataUtils.IsMixin(type.CSharpTypeDefinition, _attributeStore);
            bool   export     = type.CSharpTypeDefinition.IsExternallyVisible();
            var    statements = new List <JsStatement>();

            statements.Add(JsStatement.Comment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + type.CSharpTypeDefinition.FullName));

            string typevarName = _namer.GetTypeVariableName(name);

            if (type is JsClass)
            {
                var c = (JsClass)type;
                if (isGlobal)
                {
                    statements.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.Member(JsExpression.Identifier(GetRoot(type.CSharpTypeDefinition)), m.Name), m.Definition)));
                    export = false;
                }
                else if (isMixin)
                {
                    statements.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Assign(MakeNestedMemberAccess(name + "." + m.Name), m.Definition)));
                    export = false;
                }
                else if (MetadataUtils.IsResources(c.CSharpTypeDefinition, _attributeStore))
                {
                    statements.Add(GenerateResourcesClass(c));
                }
                else
                {
                    var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock);

                    if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter))
                    {
                        var typeParameterNames = c.CSharpTypeDefinition.TypeParameters.Select(tp => _namer.GetTypeParameterName(tp)).ToList();
                        var stmts = new List <JsStatement> {
                            JsStatement.Var(InstantiatedGenericTypeVariableName, unnamedCtor)
                        };
                        AddClassMembers(c, InstantiatedGenericTypeVariableName, stmts);
                        stmts.AddRange(c.StaticInitStatements);
                        stmts.Add(JsStatement.Return(JsExpression.Identifier(InstantiatedGenericTypeVariableName)));
                        var replacer = new GenericSimplifier(c.CSharpTypeDefinition, typeParameterNames, JsExpression.Identifier(InstantiatedGenericTypeVariableName));
                        for (int i = 0; i < stmts.Count; i++)
                        {
                            stmts[i] = replacer.Process(stmts[i]);
                        }
                        statements.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(typeParameterNames, JsStatement.Block(stmts))));
                        statements.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name)));
                        var args = new List <JsExpression> {
                            JsExpression.Identifier(typevarName), _linker.CurrentAssemblyExpression, JsExpression.Number(c.CSharpTypeDefinition.TypeParameterCount)
                        };
                        statements.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? InitGenericInterface : InitGenericClass), args));
                    }
                    else
                    {
                        statements.Add(JsStatement.Var(typevarName, unnamedCtor));
                        statements.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name)));
                        AddClassMembers(c, typevarName, statements);
                    }
                }
            }
            else if (type is JsEnum)
            {
                var e = (JsEnum)type;
                statements.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock)));
                statements.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(e.CSharpTypeDefinition).Name)));
            }

            if (export)
            {
                string root = GetRoot(type.CSharpTypeDefinition);
                statements.Add(JsExpression.Assign(MakeNestedMemberAccess(name, JsExpression.Identifier(root)), JsExpression.Identifier(typevarName)));
            }

            return(new TypeOOPEmulationPhase(null, statements));
        }
예제 #2
0
        public IList <JsStatement> Process(IEnumerable <JsType> types, IMethod entryPoint)
        {
            var result = new List <JsStatement>();

            var orderedTypes = OrderByNamespace(types, t => _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name).ToList();

            foreach (var t in orderedTypes)
            {
                try {
                    string name     = _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name;
                    bool   isGlobal = string.IsNullOrEmpty(name);
                    bool   isMixin  = MetadataUtils.IsMixin(t.CSharpTypeDefinition);

                    result.Add(new JsComment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + t.CSharpTypeDefinition.FullName));

                    var typeRef = JsExpression.Identifier(_namer.GetTypeVariableName(name));
                    if (t is JsClass)
                    {
                        var c = (JsClass)t;
                        if (isGlobal)
                        {
                            result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.Member(GetRoot(t.CSharpTypeDefinition, exportNonPublic: true), m.Name), m.Definition))));
                        }
                        else if (isMixin)
                        {
                            result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(MakeNestedMemberAccess(name + "." + m.Name), m.Definition))));
                        }
                        else if (MetadataUtils.IsResources(c.CSharpTypeDefinition))
                        {
                            result.Add(GenerateResourcesClass(c));
                        }
                        else
                        {
                            var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement);

                            if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter))
                            {
                                var typeParameterNames = c.CSharpTypeDefinition.TypeParameters.Select(tp => _namer.GetTypeParameterName(tp)).ToList();
                                var stmts = new List <JsStatement> {
                                    new JsVariableDeclarationStatement(InstantiatedGenericTypeVariableName, unnamedCtor)
                                };
                                AddClassMembers(c, JsExpression.Identifier(InstantiatedGenericTypeVariableName), stmts);
                                stmts.AddRange(c.StaticInitStatements);
                                stmts.Add(new JsReturnStatement(JsExpression.Identifier(InstantiatedGenericTypeVariableName)));
                                var replacer = new GenericSimplifier(c.CSharpTypeDefinition, typeParameterNames, JsExpression.Identifier(InstantiatedGenericTypeVariableName));
                                for (int i = 0; i < stmts.Count; i++)
                                {
                                    stmts[i] = replacer.Process(stmts[i]);
                                }
                                result.Add(new JsVariableDeclarationStatement(typeRef.Name, JsExpression.FunctionDefinition(typeParameterNames, new JsBlockStatement(stmts))));
                                var args = new List <JsExpression> {
                                    GetRoot(t.CSharpTypeDefinition), JsExpression.String(name), typeRef, JsExpression.Number(c.CSharpTypeDefinition.TypeParameterCount)
                                };
                                var metadata = GetMetadataDescriptor(t.CSharpTypeDefinition, false);
                                if (metadata != null)
                                {
                                    args.Add(metadata);
                                }
                                result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? RegisterGenericInterface : RegisterGenericClass), args)));
                            }
                            else
                            {
                                result.Add(new JsVariableDeclarationStatement(typeRef.Name, unnamedCtor));
                                AddClassMembers(c, typeRef, result);
                            }
                        }
                    }
                    else if (t is JsEnum)
                    {
                        var e = (JsEnum)t;
                        result.Add(new JsVariableDeclarationStatement(typeRef.Name, JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement)));
                        var values = new List <JsObjectLiteralProperty>();
                        foreach (var v in e.CSharpTypeDefinition.Fields)
                        {
                            if (v.ConstantValue != null)
                            {
                                var sem = _metadataImporter.GetFieldSemantics(v);
                                if (sem.Type == FieldScriptSemantics.ImplType.Field)
                                {
                                    values.Add(new JsObjectLiteralProperty(sem.Name, JsExpression.Number(Convert.ToDouble(v.ConstantValue))));
                                }
                                else if (sem.Type == FieldScriptSemantics.ImplType.Constant && sem.Name != null)
                                {
                                    values.Add(new JsObjectLiteralProperty(sem.Name, sem.Value is string?JsExpression.String((string)sem.Value) : JsExpression.Number(Convert.ToDouble(sem.Value))));
                                }
                            }
                            else
                            {
                                _errorReporter.Region = v.Region;
                                _errorReporter.InternalError("Enum field " + v.FullName + " is not constant.");
                            }
                        }
                        result.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, Prototype), JsExpression.ObjectLiteral(values))));
                    }
                }
                catch (Exception ex) {
                    _errorReporter.Region = t.CSharpTypeDefinition.Region;
                    _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName);
                }
            }

            var typesToRegister = orderedTypes
                                  .Where(c => !(c is JsClass && MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) &&
                                         !string.IsNullOrEmpty(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name) &&
                                         (!MetadataUtils.IsResources(c.CSharpTypeDefinition) || c.CSharpTypeDefinition.IsExternallyVisible()) &&                        // Resources classes are only exported if they are public.
                                         !MetadataUtils.IsMixin(c.CSharpTypeDefinition))
                                  .ToList();

            result.AddRange(TopologicalSortTypesByInheritance(typesToRegister)
                            .Select(c => {
                try {
                    string name = _metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name;
                    if (c.CSharpTypeDefinition.Kind == TypeKind.Enum)
                    {
                        return(CreateRegisterEnumCall(c.CSharpTypeDefinition, name, JsExpression.Identifier(_namer.GetTypeVariableName(name))));
                    }
                    if (MetadataUtils.IsResources(c.CSharpTypeDefinition))
                    {
                        return(JsExpression.Invocation(JsExpression.Member(_systemScript, RegisterType), GetRoot(c.CSharpTypeDefinition), JsExpression.String(name), JsExpression.Identifier(_namer.GetTypeVariableName(name))));
                    }
                    if (c.CSharpTypeDefinition.Kind == TypeKind.Interface)
                    {
                        return(CreateRegisterInterfaceCall(c.CSharpTypeDefinition,
                                                           name,
                                                           JsExpression.Identifier(_namer.GetTypeVariableName(name)),
                                                           GetImplementedInterfaces(c.CSharpTypeDefinition.GetDefinition()).ToList()));
                    }
                    else
                    {
                        return(CreateRegisterClassCall(c.CSharpTypeDefinition,
                                                       name,
                                                       JsExpression.Identifier(_namer.GetTypeVariableName(name)),
                                                       GetBaseClass(c.CSharpTypeDefinition),
                                                       GetImplementedInterfaces(c.CSharpTypeDefinition).ToList()));
                    }
                }
                catch (Exception ex) {
                    _errorReporter.Region = c.CSharpTypeDefinition.Region;
                    _errorReporter.InternalError(ex, "Error formatting type " + c.CSharpTypeDefinition.FullName);
                    return(JsExpression.Number(0));
                }
            })
                            .Select(expr => new JsExpressionStatement(expr)));
            result.AddRange(GetStaticInitializationOrder(orderedTypes.OfType <JsClass>(), 1)
                            .Where(c => !MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter) && !MetadataUtils.IsResources(c.CSharpTypeDefinition))
                            .SelectMany(c => c.StaticInitStatements));

            if (entryPoint != null)
            {
                if (entryPoint.Parameters.Count > 0)
                {
                    _errorReporter.Region = entryPoint.Region;
                    _errorReporter.Message(Messages._7800, entryPoint.FullName);
                }
                else
                {
                    var sem = _metadataImporter.GetMethodSemantics(entryPoint);
                    if (sem.Type != MethodScriptSemantics.ImplType.NormalMethod)
                    {
                        _errorReporter.Region = entryPoint.Region;
                        _errorReporter.Message(Messages._7801, entryPoint.FullName);
                    }
                    else
                    {
                        result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(new JsTypeReferenceExpression(entryPoint.DeclaringTypeDefinition), sem.Name))));
                    }
                }
            }

            return(result);
        }
        public IList <JsStatement> Process(IEnumerable <JsType> types, IMethod entryPoint)
        {
            var result = new List <JsStatement>();

            var orderedTypes             = OrderByNamespace(types, t => _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name).ToList();
            var exportedNamespacesByRoot = new Dictionary <string, HashSet <string> >();

            foreach (var t in orderedTypes)
            {
                try {
                    string name     = _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name;
                    bool   isGlobal = string.IsNullOrEmpty(name);
                    bool   isMixin  = MetadataUtils.IsMixin(t.CSharpTypeDefinition);
                    bool   export   = t.CSharpTypeDefinition.IsExternallyVisible();

                    result.Add(JsStatement.Comment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + t.CSharpTypeDefinition.FullName));

                    string typevarName = _namer.GetTypeVariableName(name);
                    if (t is JsClass)
                    {
                        var c = (JsClass)t;
                        if (isGlobal)
                        {
                            result.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.Member(JsExpression.Identifier(GetRoot(t.CSharpTypeDefinition)), m.Name), m.Definition)));
                            export = false;
                        }
                        else if (isMixin)
                        {
                            result.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Assign(MakeNestedMemberAccess(name + "." + m.Name), m.Definition)));
                            export = false;
                        }
                        else if (MetadataUtils.IsResources(c.CSharpTypeDefinition))
                        {
                            result.Add(GenerateResourcesClass(c));
                        }
                        else
                        {
                            var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock);

                            if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter))
                            {
                                var typeParameterNames = c.CSharpTypeDefinition.TypeParameters.Select(tp => _namer.GetTypeParameterName(tp)).ToList();
                                var stmts = new List <JsStatement> {
                                    JsStatement.Var(InstantiatedGenericTypeVariableName, unnamedCtor)
                                };
                                AddClassMembers(c, InstantiatedGenericTypeVariableName, stmts);
                                stmts.AddRange(c.StaticInitStatements);
                                stmts.Add(JsStatement.Return(JsExpression.Identifier(InstantiatedGenericTypeVariableName)));
                                var replacer = new GenericSimplifier(c.CSharpTypeDefinition, typeParameterNames, JsExpression.Identifier(InstantiatedGenericTypeVariableName));
                                for (int i = 0; i < stmts.Count; i++)
                                {
                                    stmts[i] = replacer.Process(stmts[i]);
                                }
                                result.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(typeParameterNames, JsStatement.Block(stmts))));
                                result.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name)));
                                var args = new List <JsExpression> {
                                    JsExpression.Identifier(typevarName), JsExpression.Number(c.CSharpTypeDefinition.TypeParameterCount)
                                };
                                result.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? InitGenericInterface : InitGenericClass), args));
                            }
                            else
                            {
                                result.Add(JsStatement.Var(typevarName, unnamedCtor));
                                result.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name)));
                                AddClassMembers(c, typevarName, result);
                            }
                        }
                    }
                    else if (t is JsEnum)
                    {
                        var e = (JsEnum)t;
                        result.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock)));
                        result.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(e.CSharpTypeDefinition).Name)));
                    }

                    if (export)
                    {
                        string root  = GetRoot(t.CSharpTypeDefinition);
                        var    split = SplitIntoNamespaceAndName(name);
                        if (!string.IsNullOrEmpty(split.Item1))
                        {
                            HashSet <string> hs;
                            if (!exportedNamespacesByRoot.TryGetValue(root, out hs))
                            {
                                hs = exportedNamespacesByRoot[root] = new HashSet <string>();
                            }
                            hs.Add(split.Item1);
                        }

                        result.Add(JsExpression.Assign(MakeNestedMemberAccess(name, JsExpression.Identifier(root)), JsExpression.Identifier(typevarName)));
                    }
                }
                catch (Exception ex) {
                    _errorReporter.Region = t.CSharpTypeDefinition.Region;
                    _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName);
                }
            }

            result.InsertRange(0, exportedNamespacesByRoot.OrderBy(x => x.Key).SelectMany(x => CreateNamespaces(JsExpression.Identifier(x.Key), x.Value)).ToList());

            var typesToRegister = TopologicalSortTypesByInheritance(orderedTypes)
                                  .Where(c => !(c is JsClass && MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) &&
                                         !string.IsNullOrEmpty(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name) &&
                                         !MetadataUtils.IsResources(c.CSharpTypeDefinition) &&
                                         !MetadataUtils.IsMixin(c.CSharpTypeDefinition))
                                  .ToList();

            foreach (var t in typesToRegister)
            {
                try {
                    string name        = _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name;
                    string typevarName = _namer.GetTypeVariableName(name);
                    if (t.CSharpTypeDefinition.Kind == TypeKind.Enum)
                    {
                        result.Add(CreateInitEnumCall((JsEnum)t, typevarName));
                    }
                    else
                    {
                        var c = (JsClass)t;
                        if (t.CSharpTypeDefinition.Kind == TypeKind.Interface)
                        {
                            result.Add(CreateInitInterfaceCall(c, typevarName, GetImplementedInterfaces(t.CSharpTypeDefinition.GetDefinition()).ToList()));
                        }
                        else
                        {
                            result.Add(CreateInitClassCall(c, typevarName, GetBaseClass(t.CSharpTypeDefinition), GetImplementedInterfaces(t.CSharpTypeDefinition).ToList()));
                            if (c.NamedConstructors.Count > 0)
                            {
                                result.Add(AssignNamedConstructorPrototypes(c, JsExpression.Identifier(_namer.GetTypeVariableName(name))));
                            }
                        }
                    }
                }
                catch (Exception ex) {
                    _errorReporter.Region = t.CSharpTypeDefinition.Region;
                    _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName);
                }
            }

            foreach (var t in orderedTypes)
            {
                var metadata = GetMetadataDescriptor(t.CSharpTypeDefinition, false);
                if (metadata != null)
                {
                    result.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, SetMetadata), JsExpression.Identifier(_namer.GetTypeVariableName(_metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name)), metadata));
                }
            }

            result.AddRange(GetStaticInitializationOrder(orderedTypes.OfType <JsClass>(), 1)
                            .Where(c => !MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter) && !MetadataUtils.IsResources(c.CSharpTypeDefinition))
                            .SelectMany(c => c.StaticInitStatements));

            if (entryPoint != null)
            {
                if (entryPoint.Parameters.Count > 0)
                {
                    _errorReporter.Region = entryPoint.Region;
                    _errorReporter.Message(Messages._7800, entryPoint.FullName);
                }
                else
                {
                    var sem = _metadataImporter.GetMethodSemantics(entryPoint);
                    if (sem.Type != MethodScriptSemantics.ImplType.NormalMethod)
                    {
                        _errorReporter.Region = entryPoint.Region;
                        _errorReporter.Message(Messages._7801, entryPoint.FullName);
                    }
                    else
                    {
                        result.Add(JsExpression.Invocation(JsExpression.Member(new JsTypeReferenceExpression(entryPoint.DeclaringTypeDefinition), sem.Name)));
                    }
                }
            }

            return(result);
        }