Ejemplo n.º 1
0
 public bool TryCharBinaryExpression(SyntaxKind type, TypeInfo leftSymbol, TypeInfo rightSymbol, JsExpression left, JsExpression right, out JsExpression result)
 {
     if (Equals(leftSymbol.Type, Context.Instance.Char) || Equals(rightSymbol.Type, Context.Instance.Char))
     {
         switch (type)
         {
             case SyntaxKind.SubtractExpression:
             case SyntaxKind.AddExpression:
             case SyntaxKind.MultiplyExpression:
             case SyntaxKind.DivideExpression:
             case SyntaxKind.ModuloExpression:
             case SyntaxKind.BitwiseAndExpression:
             case SyntaxKind.BitwiseOrExpression:
             case SyntaxKind.LessThanExpression:
             case SyntaxKind.LessThanOrEqualExpression:
             case SyntaxKind.GreaterThanExpression:
             case SyntaxKind.GreaterThanOrEqualExpression:
             case SyntaxKind.LeftShiftExpression:
             case SyntaxKind.RightShiftExpression:
             case SyntaxKind.ExclusiveOrExpression:
             case SyntaxKind.AddAssignmentExpression:
             case SyntaxKind.SubtractAssignmentExpression:
             case SyntaxKind.MultiplyAssignmentExpression:
             case SyntaxKind.DivideAssignmentExpression:
             case SyntaxKind.ModuloAssignmentExpression:
                 result = Js.Binary(
                     ToBinaryOperator(type).Value,
                     !Equals(leftSymbol.Type, Context.Instance.Char) || Equals(rightSymbol.Type, Context.Instance.String) ? left : left.Member("charCodeAt").Invoke(Js.Primitive(0)),
                     !Equals(rightSymbol.Type, Context.Instance.Char) || Equals(leftSymbol.Type, Context.Instance.String) ? right : right.Member("charCodeAt").Invoke(Js.Primitive(0))
                 );
                 switch (type)
                 {
                     case SyntaxKind.AddAssignmentExpression:
                     case SyntaxKind.SubtractAssignmentExpression:
                     case SyntaxKind.MultiplyAssignmentExpression:
                     case SyntaxKind.DivideAssignmentExpression:
                     case SyntaxKind.ModuloAssignmentExpression:
                         result = left.Assign(Js.Reference("String").Member("fromCharCode").Invoke(result));
                         break;
                 }
                 return true;
         }                
     }
     result = null;
     return false;
 }
Ejemplo n.º 2
0
 public bool TryIntegerDivision(SyntaxKind type, TypeInfo leftSymbol, TypeInfo rightSymbol, JsExpression left, JsExpression right, out JsExpression result)
 {
     if ((type == SyntaxKind.DivideExpression || type == SyntaxKind.DivideAssignmentExpression) && 
         IsIntegerType(leftSymbol.ConvertedType) && 
         IsIntegerType(rightSymbol.ConvertedType))
     {
         result = Js.Reference(SpecialNames.Truncate).Invoke(Js.Binary(JsBinaryOperator.Divide, left, right));
         if (type == SyntaxKind.DivideAssignmentExpression)
         {
             result = left.Assign(result);
         }
         return true;
     }
     result = null;
     return false;
 }
 public void IfStatementIsCorrectlyOutput()
 {
     AssertCorrect(JsStatement.If(JsExpression.True, JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0)), null),
                   "if(true){i=0;}");
     AssertCorrect(JsStatement.If(JsExpression.True, JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0)), JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(1))),
                   "if(true){i=0;}else{i=1;}");
 }
Ejemplo n.º 4
0
        public bool TryCharUnaryExpression(SyntaxKind type, TypeInfo operandType, JsExpression operand, out JsExpression result)
        {
            if (Equals(operandType.Type, Context.Instance.Char))
            {
                switch (type)
                {
                    case SyntaxKind.PostDecrementExpression:
                    case SyntaxKind.PostIncrementExpression:
                    {
                        var old = Js.Variable("$old", operand);

                        var op = type == SyntaxKind.PostDecrementExpression ? JsBinaryOperator.Subtract : JsBinaryOperator.Add;
                        result = Js.Binary(
                            op, 
                            old.GetReference().Member("charCodeAt").Invoke(Js.Primitive(0)),
                            Js.Primitive(1)
                        );
                        result = operand.Assign(Js.Reference("String").Member("fromCharCode").Invoke(result));

                        var block = new JsBlockStatement();
                        block.Local(old);
                        block.Express(result);
                        block.Return(old.GetReference());
                        result = Wrap(block);

                        return true;
                    }
                    case SyntaxKind.PreDecrementExpression:
                    case SyntaxKind.PreIncrementExpression:
                    {
                        var op = type == SyntaxKind.PreDecrementExpression ? JsBinaryOperator.Subtract : JsBinaryOperator.Add;
                        result = Js.Binary(
                            op, 
                            operand.Member("charCodeAt").Invoke(Js.Primitive(0)),
                            Js.Primitive(1)
                        );
                        result = operand.Assign(Js.Reference("String").Member("fromCharCode").Invoke(result));
                        return true;
                    }
                }
            }
            result = null;
            return false;
        }
        private void AddClassMembers(JsClass c, JsExpression typeRef, ICompilation compilation, List <JsStatement> stmts)
        {
            ICollection <JsMethod> instanceMethods;

            if (_metadataImporter.IsTestFixture(c.CSharpTypeDefinition))
            {
                var tests = new List <Tuple <string, string, bool, int?, JsFunctionDefinitionExpression> >();
                var instanceMethodList = new List <JsMethod>();
                foreach (var m in c.InstanceMethods)
                {
                    var td = (m.CSharpMember is IMethod ? _metadataImporter.GetTestData((IMethod)m.CSharpMember) : null);
                    if (td != null)
                    {
                        tests.Add(Tuple.Create(td.Description, td.Category, td.IsAsync, td.ExpectedAssertionCount, m.Definition));
                    }
                    else
                    {
                        instanceMethodList.Add(m);
                    }
                }
                var testInvocations = new List <JsExpression>();
                foreach (var category in tests.GroupBy(t => t.Item2).Select(g => new { Category = g.Key, Tests = g.Select(x => new { Description = x.Item1, IsAsync = x.Item3, ExpectedAssertionCount = x.Item4, Function = x.Item5 }) }).OrderBy(x => x.Category))
                {
                    if (category.Category != null)
                    {
                        testInvocations.Add(JsExpression.Invocation(JsExpression.Identifier("module"), JsExpression.String(category.Category)));
                    }
                    testInvocations.AddRange(category.Tests.Select(t => JsExpression.Invocation(JsExpression.Identifier(t.IsAsync ? "asyncTest" : "test"), t.ExpectedAssertionCount != null ? new JsExpression[] { JsExpression.String(t.Description), JsExpression.Number(t.ExpectedAssertionCount.Value), _runtimeLibrary.Bind(t.Function, JsExpression.This) } : new JsExpression[] { JsExpression.String(t.Description), _runtimeLibrary.Bind(t.Function, JsExpression.This) })));
                }

                instanceMethodList.Add(new JsMethod(null, "runTests", null, JsExpression.FunctionDefinition(new string[0], new JsBlockStatement(testInvocations.Select(t => new JsExpressionStatement(t))))));

                instanceMethods = instanceMethodList;
            }
            else
            {
                instanceMethods = c.InstanceMethods;
            }

            if (instanceMethods.Count > 0)
            {
                stmts.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, Prototype), JsExpression.ObjectLiteral(instanceMethods.Select(m => new JsObjectLiteralProperty(m.Name, m.Definition != null ? RewriteMethod(m) : JsExpression.Null))))));
            }

            if (c.NamedConstructors.Count > 0)
            {
                stmts.AddRange(c.NamedConstructors.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, m.Name), m.Definition))));
                stmts.Add(new JsExpressionStatement(c.NamedConstructors.Reverse().Aggregate((JsExpression)JsExpression.MemberAccess(typeRef, Prototype), (right, ctor) => JsExpression.Assign(JsExpression.MemberAccess(JsExpression.MemberAccess(typeRef, ctor.Name), Prototype), right))));                   // This generates a statement like {C}.ctor1.prototype = {C}.ctor2.prototype = {C}.prototoype
            }

            var defaultConstructor = c.CSharpTypeDefinition.GetConstructors().SingleOrDefault(x => x.Parameters.Count == 0 && x.IsPublic);

            if (defaultConstructor != null)
            {
                JsExpression createInstance = CreateDefaultConstructorInvocation(defaultConstructor, typeRef);
                if (createInstance != null)
                {
                    stmts.Add(new JsExpressionStatement(
                                  JsExpression.Assign(
                                      JsExpression.MemberAccess(typeRef, "createInstance"),
                                      JsExpression.FunctionDefinition(new string[0],
                                                                      new JsReturnStatement(createInstance)))));
                }
            }

            stmts.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, m.Name), RewriteMethod(m)))));

            if (c.TypeArgumentNames.Count > 0)
            {
                if (c.ClassType == JsClass.ClassTypeEnum.Interface)
                {
                    stmts.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterGenericInterfaceInstance),
                                                                                typeRef,
                                                                                new JsTypeReferenceExpression(compilation.MainAssembly, c.Name),
                                                                                JsExpression.ArrayLiteral(c.TypeArgumentNames.Select(JsExpression.Identifier)),
                                                                                JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(JsExpression.ArrayLiteral(c.ImplementedInterfaces))))));
                }
                else
                {
                    stmts.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterGenericClassInstance),
                                                                                typeRef,
                                                                                new JsTypeReferenceExpression(compilation.MainAssembly, c.Name),
                                                                                JsExpression.ArrayLiteral(c.TypeArgumentNames.Select(JsExpression.Identifier)),
                                                                                JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(c.BaseClass)),
                                                                                JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(JsExpression.ArrayLiteral(c.ImplementedInterfaces))))));
                }
            }
        }
Ejemplo n.º 6
0
        private void AddClassMembers(JsClass c, JsExpression typeRef, List <JsStatement> stmts)
        {
            if (c.InstanceMethods.Count > 0)
            {
                stmts.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, Prototype), JsExpression.ObjectLiteral(c.InstanceMethods.Select(m => new JsObjectLiteralProperty(m.Name, m.Definition != null ? RewriteMethod(m) : JsExpression.Null))))));
            }

            if (c.NamedConstructors.Count > 0)
            {
                stmts.AddRange(c.NamedConstructors.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, m.Name), m.Definition))));
                stmts.Add(new JsExpressionStatement(c.NamedConstructors.Reverse().Aggregate((JsExpression)JsExpression.Member(typeRef, Prototype), (right, ctor) => JsExpression.Assign(JsExpression.Member(JsExpression.Member(typeRef, ctor.Name), Prototype), right))));                     // This generates a statement like {C}.ctor1.prototype = {C}.ctor2.prototype = {C}.prototoype
            }

            var defaultConstructor = Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition).GetConstructors().SingleOrDefault(x => x.Parameters.Count == 0 && x.IsPublic);

            if (defaultConstructor != null)
            {
                var sem = _metadataImporter.GetConstructorSemantics(defaultConstructor);
                if (sem.Type != ConstructorScriptSemantics.ImplType.UnnamedConstructor && sem.Type != ConstructorScriptSemantics.ImplType.NotUsableFromScript)
                {
                    var createInstance = MetadataUtils.CompileConstructorInvocation(defaultConstructor, null, c.CSharpTypeDefinition, null, EmptyList <ResolveResult> .Instance, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter, null, null);
                    stmts.Add(new JsExpressionStatement(
                                  JsExpression.Assign(
                                      JsExpression.Member(typeRef, "createInstance"),
                                      JsExpression.FunctionDefinition(new string[0], new JsBlockStatement(createInstance.AdditionalStatements.Concat(new[] { new JsReturnStatement(createInstance.Expression) }))))));
                }
            }

            stmts.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, m.Name), RewriteMethod(m)))));

            if (MetadataUtils.IsSerializable(c.CSharpTypeDefinition))
            {
                string typeCheckCode = MetadataUtils.GetSerializableTypeCheckCode(c.CSharpTypeDefinition);
                if (!string.IsNullOrEmpty(typeCheckCode))
                {
                    var oldReg = _errorReporter.Region;
                    _errorReporter.Region = c.CSharpTypeDefinition.Attributes.Single(a => a.AttributeType.FullName == typeof(SerializableAttribute).FullName).Region;
                    var method = MetadataUtils.CreateTypeCheckMethod(Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition), _compilation);

                    var errors = new List <string>();
                    var tokens = InlineCodeMethodCompiler.Tokenize(method, typeCheckCode, errors.Add);
                    if (errors.Count == 0)
                    {
                        var context = new DefaultRuntimeContext(c.CSharpTypeDefinition, _metadataImporter, _errorReporter, _namer);
                        var result  = InlineCodeMethodCompiler.CompileInlineCodeMethodInvocation(method, tokens, JsExpression.Identifier("obj"), new JsExpression[0],
                                                                                                 n => {
                            var type = ReflectionHelper.ParseReflectionName(n).Resolve(_compilation);
                            if (type.Kind == TypeKind.Unknown)
                            {
                                errors.Add("Unknown type '" + n + "' specified in inline implementation");
                                return(JsExpression.Null);
                            }
                            return(_runtimeLibrary.InstantiateType(type, context));
                        },
                                                                                                 t => _runtimeLibrary.InstantiateTypeForUseAsTypeArgumentInInlineCode(t, context),
                                                                                                 errors.Add);

                        stmts.Add(new JsExpressionStatement(
                                      JsExpression.Assign(
                                          JsExpression.Member(typeRef, "isInstanceOfType"),
                                          JsExpression.FunctionDefinition(new[] { "obj" }, new JsReturnStatement(result)))));

                        foreach (var e in errors)
                        {
                            _errorReporter.Message(Messages._7157, c.CSharpTypeDefinition.FullName, e);
                        }
                    }
                    _errorReporter.Region = oldReg;
                }
            }

            if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter))
            {
                var args = new List <JsExpression> {
                    typeRef, new JsTypeReferenceExpression(c.CSharpTypeDefinition), JsExpression.ArrayLiteral(c.CSharpTypeDefinition.TypeParameters.Select(tp => JsExpression.Identifier(_namer.GetTypeParameterName(tp))))
                };
                if (c.CSharpTypeDefinition.Kind == TypeKind.Class)
                {
                    args.Add(JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(GetBaseClass(c.CSharpTypeDefinition) ?? JsExpression.Null)));
                }
                args.Add(JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(JsExpression.ArrayLiteral(GetImplementedInterfaces(c.CSharpTypeDefinition)))));
                var metadata = GetMetadataDescriptor(c.CSharpTypeDefinition, true);
                if (metadata != null)
                {
                    args.Add(metadata);
                }
                stmts.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Class ? RegisterGenericClassInstance : RegisterGenericInterfaceInstance), args)));
            }
        }
Ejemplo n.º 7
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));
        }
        protected void AssertCorrect(string orig, string expected, MethodType methodType = MethodType.Normal)
        {
            int tempIndex = 0, stateIndex = 0, loopLabelIndex = 0;
            var stmt = JsBlockStatement.MakeBlock(JavaScriptParser.Parser.ParseStatement(orig));
            JsBlockStatement result;

            if (methodType == MethodType.Iterator)
            {
                int finallyHandlerIndex = 0;
                result = StateMachineRewriter.RewriteIteratorBlock(stmt, e => e.NodeType != ExpressionNodeType.Identifier, () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture), () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture), () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)), () => string.Format("$finally" + (++finallyHandlerIndex).ToString(CultureInfo.InvariantCulture)), v => JsExpression.Invocation(JsExpression.Identifier("setCurrent"), v), sm => {
                    var body = new List <JsStatement>();
                    if (sm.Variables.Count > 0)
                    {
                        body.Add(new JsVariableDeclarationStatement(sm.Variables));
                    }
                    body.AddRange(sm.FinallyHandlers.Select(h => new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(h.Item1), h.Item2))));
                    if (sm.Disposer != null)
                    {
                        body.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("dispose"), new JsFunctionDefinitionExpression(new string[0], sm.Disposer))));
                    }
                    body.Add(sm.MainBlock);
                    return(new JsBlockStatement(body));
                });
            }
            else if (methodType == MethodType.AsyncTask || methodType == MethodType.AsyncVoid)
            {
                result = StateMachineRewriter.RewriteAsyncMethod(stmt,
                                                                 e => e.NodeType != ExpressionNodeType.Identifier,
                                                                 () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture),
                                                                 () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture),
                                                                 () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)),
                                                                 "$sm",
                                                                 "$doFinally",
                                                                 methodType == MethodType.AsyncTask ? new JsVariableDeclaration("$tcs", JsExpression.New(JsExpression.Identifier("TaskCompletionSource"))) : null,
                                                                 expr => { if (methodType != MethodType.AsyncTask)
                                                                           {
                                                                               throw new InvalidOperationException("Should not set result in async void method");
                                                                           }
                                                                           return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "setResult"), expr ?? JsExpression.String("<<null>>"))); },
                                                                 expr => { if (methodType != MethodType.AsyncTask)
                                                                           {
                                                                               throw new InvalidOperationException("Should not set exception in async void method");
                                                                           }
                                                                           return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "setException"), expr)); },
                                                                 () => { if (methodType != MethodType.AsyncTask)
                                                                         {
                                                                             throw new InvalidOperationException("Should not get task async void method");
                                                                         }
                                                                         return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "getTask"))); },
                                                                 (sm, ctx) => JsExpression.Invocation(JsExpression.Identifier("$Bind"), sm, ctx));
            }
            else
            {
                result = StateMachineRewriter.RewriteNormalMethod(stmt, e => e.NodeType != ExpressionNodeType.Identifier, () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture), () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture), () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)));
            }
            var actual = OutputFormatter.Format(result);

            Assert.That(actual.Replace("\r\n", "\n"), Is.EqualTo(expected.Replace("\r\n", "\n")), "Expected:\n" + expected + "\n\nActual:\n" + actual);
        }
Ejemplo n.º 9
0
 private JsExpression AssignNamedConstructorPrototypes(JsClass c, JsExpression typeRef)
 {
     return(c.NamedConstructors.Reverse().Aggregate((JsExpression)JsExpression.Member(typeRef, Prototype), (right, ctor) => JsExpression.Assign(JsExpression.Member(JsExpression.Member(typeRef, ctor.Name), Prototype), right)));               // This generates a statement like {C}.ctor1.prototype = {C}.ctor2.prototype = {C}.prototoype
 }
Ejemplo n.º 10
0
        private void AddClassMembers(JsClass c, string typevarName, List <JsStatement> stmts)
        {
            if (c.NamedConstructors.Count > 0)
            {
                stmts.AddRange(c.NamedConstructors.Select(m => (JsStatement)JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), m.Name), m.Definition)));
            }

            var  defaultConstructor = Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition).GetConstructors().SingleOrDefault(x => x.Parameters.Count == 0 && x.IsPublic);
            bool hasCreateInstance  = false;

            if (defaultConstructor != null)
            {
                var sem = _metadataImporter.GetConstructorSemantics(defaultConstructor);
                if (sem.Type != ConstructorScriptSemantics.ImplType.UnnamedConstructor && sem.Type != ConstructorScriptSemantics.ImplType.NotUsableFromScript)
                {
                    var createInstance = MetadataUtils.CompileConstructorInvocation(defaultConstructor, null, c.CSharpTypeDefinition, null, EmptyList <ResolveResult> .Instance, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter, null, null);
                    stmts.Add(JsExpression.Assign(
                                  JsExpression.Member(JsExpression.Identifier(typevarName), "createInstance"),
                                  JsExpression.FunctionDefinition(new string[0], JsStatement.Block(createInstance.AdditionalStatements.Concat(new[] { JsStatement.Return(createInstance.Expression) })))));
                    hasCreateInstance = true;
                }
            }

            if (c.CSharpTypeDefinition.Kind == TypeKind.Struct)
            {
                stmts.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), "getDefaultValue"), hasCreateInstance ? JsExpression.Member(JsExpression.Identifier(typevarName), "createInstance") : JsExpression.FunctionDefinition(EmptyList <string> .Instance, JsStatement.Return(JsExpression.New(JsExpression.Identifier(typevarName))))));

                if (_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Type == TypeScriptSemantics.ImplType.MutableValueType)
                {
                    stmts.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), "$clone"), GenerateStructCloneMethod(c.CSharpTypeDefinition, typevarName, hasCreateInstance)));
                }
            }

            stmts.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), m.Name), RewriteMethod(m))));

            if (MetadataUtils.IsSerializable(c.CSharpTypeDefinition, _attributeStore))
            {
                string typeCheckCode = MetadataUtils.GetSerializableTypeCheckCode(c.CSharpTypeDefinition, _attributeStore);
                if (!string.IsNullOrEmpty(typeCheckCode))
                {
                    var oldReg = _errorReporter.Region;
                    _errorReporter.Region = c.CSharpTypeDefinition.Attributes.Single(a => a.AttributeType.FullName == typeof(SerializableAttribute).FullName).Region;
                    var method = MetadataUtils.CreateTypeCheckMethod(Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition), _compilation);

                    var errors = new List <string>();
                    var tokens = InlineCodeMethodCompiler.Tokenize(method, typeCheckCode, errors.Add);
                    if (errors.Count == 0)
                    {
                        var context = new DefaultRuntimeContext(c.CSharpTypeDefinition, _metadataImporter, _errorReporter, _namer);
                        var result  = InlineCodeMethodCompiler.CompileExpressionInlineCodeMethodInvocation(method, tokens, JsExpression.Identifier("obj"), new JsExpression[0],
                                                                                                           n => {
                            var type = ReflectionHelper.ParseReflectionName(n).Resolve(_compilation);
                            if (type.Kind == TypeKind.Unknown)
                            {
                                errors.Add("Unknown type '" + n + "' specified in inline implementation");
                                return(JsExpression.Null);
                            }
                            return(_runtimeLibrary.InstantiateType(type, context));
                        },
                                                                                                           t => _runtimeLibrary.InstantiateTypeForUseAsTypeArgumentInInlineCode(t, context),
                                                                                                           errors.Add);

                        stmts.Add(JsExpression.Assign(
                                      JsExpression.Member(JsExpression.Identifier(typevarName), "isInstanceOfType"),
                                      JsExpression.FunctionDefinition(new[] { "obj" }, JsStatement.Return(result))));

                        foreach (var e in errors)
                        {
                            _errorReporter.Message(Messages._7157, c.CSharpTypeDefinition.FullName, e);
                        }
                    }
                    _errorReporter.Region = oldReg;
                }
                else
                {
                    stmts.Add(JsExpression.Assign(
                                  JsExpression.Member(JsExpression.Identifier(typevarName), "isInstanceOfType"),
                                  JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.True))));
                }
            }

            if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter))
            {
                var args = new List <JsExpression> {
                    JsExpression.Identifier(typevarName),
                    new JsTypeReferenceExpression(c.CSharpTypeDefinition), JsExpression.ArrayLiteral(c.CSharpTypeDefinition.TypeParameters.Select(tp => JsExpression.Identifier(_namer.GetTypeParameterName(tp)))),
                    CreateInstanceMembers(c, typevarName),
                };
                if (c.CSharpTypeDefinition.Kind != TypeKind.Interface)
                {
                    args.Add(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(GetBaseClass(c.CSharpTypeDefinition) ?? JsExpression.Null)));
                }
                args.Add(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.ArrayLiteral(GetImplementedInterfaces(c.CSharpTypeDefinition)))));
                stmts.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? RegisterGenericInterfaceInstance : RegisterGenericClassInstance), args));
                if (c.CSharpTypeDefinition.Kind == TypeKind.Class && c.NamedConstructors.Count > 0)
                {
                    stmts.Add(AssignNamedConstructorPrototypes(c, JsExpression.Identifier(typevarName)));
                }
                if (c.CSharpTypeDefinition.Kind == TypeKind.Struct)
                {
                    stmts.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), "__class"), JsExpression.False));
                }
                var metadata = GetMetadataDescriptor(c.CSharpTypeDefinition, true);
                if (metadata != null)
                {
                    stmts.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, SetMetadata), JsExpression.Identifier(typevarName), metadata));
                }
            }
        }
Ejemplo n.º 11
0
        public void InternalTypesAreNotExported()
        {
            var outerType = CreateMockTypeDefinition("Outer", Accessibility.Internal);
            var innerType = CreateMockTypeDefinition("Inner", Accessibility.Public, outerType);

            AssertCorrect(
                @"////////////////////////////////////////////////////////////////////////////////
// GenericClass
var $GenericClass = function(T1) {
	var $type = function() {
	};
	{Type}.registerGenericClassInstance($type, {GenericClass}, [T1], function() {
		return;
	}, function() {
		return [];
	});
	return $type;
};
{Type}.registerGenericClass(null, 'GenericClass', $GenericClass, 1);
////////////////////////////////////////////////////////////////////////////////
// GenericInterface
var $GenericInterface = function(T1) {
	var $type = function() {
	};
	{Type}.registerGenericInterfaceInstance($type, {GenericInterface}, [T1], function() {
		return [];
	});
	return $type;
};
{Type}.registerGenericInterface(null, 'GenericInterface', $GenericInterface, 1);
////////////////////////////////////////////////////////////////////////////////
// Interface
var $Interface = function() {
};
////////////////////////////////////////////////////////////////////////////////
// Outer
var $Outer = function() {
};
////////////////////////////////////////////////////////////////////////////////
// Inner
var $Outer$Inner = function() {
};
////////////////////////////////////////////////////////////////////////////////
// ResourceClass
var $ResourceClass = { Field1: 'the value', Field2: 123, Field3: null };
{Type}.registerInterface(null, 'Interface', $Interface, []);
{Type}.registerClass(null, 'Outer', $Outer);
{Type}.registerClass(null, 'Outer$Inner', $Outer$Inner);
", new MockScriptSharpMetadataImporter {
                IsResources = t => t.FullName == "ResourceClass"
            },
                new JsClass(outerType, JsClass.ClassTypeEnum.Class, null, null, new JsExpression[0]),
                new JsClass(innerType, JsClass.ClassTypeEnum.Class, null, null, new JsExpression[0]),
                new JsClass(CreateMockTypeDefinition("GenericClass", Accessibility.Internal), JsClass.ClassTypeEnum.Class, new[] { "T1" }, null, new JsExpression[0]),
                new JsClass(CreateMockTypeDefinition("Interface", Accessibility.Internal), JsClass.ClassTypeEnum.Interface, null, null, new JsExpression[0]),
                new JsClass(CreateMockTypeDefinition("GenericInterface", Accessibility.Internal), JsClass.ClassTypeEnum.Interface, new[] { "T1" }, null, new JsExpression[0]),
                new JsClass(CreateMockTypeDefinition("ResourceClass", Accessibility.Internal), JsClass.ClassTypeEnum.Class, null, null, new JsExpression[0])
            {
                StaticInitStatements = { new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(new JsTypeReferenceExpression(Common.CreateMockType("SomeNamespace.InnerNamespace.MyClass")), "Field1"), JsExpression.String("the value"))),
                                         new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(new JsTypeReferenceExpression(Common.CreateMockType("SomeNamespace.InnerNamespace.MyClass")), "Field2"), JsExpression.Number(123))),
                                         new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(new JsTypeReferenceExpression(Common.CreateMockType("SomeNamespace.InnerNamespace.MyClass")), "Field3"), JsExpression.Null)), }
            });
        }
Ejemplo n.º 12
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();
            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);
        }
Ejemplo n.º 13
0
            public override JsNode VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node)
            {
                switch (node.CSharpKind())
                {
                case SyntaxKind.AwaitExpression:
                    var operand = (JsExpression)node.Operand.Accept(this);

/*
 *                      var expressionInfo = stateGenerator.Transformer.model.GetAwaitExpressionInfo(node);
 *                      if (expressionInfo.GetResultMethod == null)
 *                      {
 *                          var classText = node.FirstAncestorOrSelf<ClassDeclarationSyntax>().NormalizeWhitespace().ToString();
 *                          var diagnostics = model.GetDiagnostics().Select(x => x.ToString()).ToArray();
 *                      }
 *
 *                      var returnsVoid = expressionInfo.GetResultMethod.ReturnsVoid;
 */
                    var expressionInfo    = stateGenerator.Transformer.model.GetTypeInfo(node).ConvertedType;
                    var returnsVoid       = expressionInfo.SpecialType == SpecialType.System_Void;
                    var operandType       = model.GetTypeInfo(node.Operand).ConvertedType;
                    var awaiterMethodName = ((INamedTypeSymbol)operandType).GetMethodByName("GetAwaiter").GetMemberName();

                    // Store the awaiter in a field
                    var awaiterIdentifier = stateGenerator.HoistVariable(new LiftedVariableKey("$awaiter"));
                    var awaiter           = awaiterIdentifier.GetReference();
                    stateGenerator.CurrentState.Add(awaiter.Assign(operand.Member(awaiterMethodName).Invoke()).Express());

                    var nextState = stateGenerator.InsertState();

                    JsExpression result = null;
                    if (!returnsVoid)
                    {
                        // If the await returns a value, store it in a field
                        var resultIdentifier = stateGenerator.HoistVariable(new LiftedVariableKey("$result"));
                        result = resultIdentifier.GetReference();

                        // Make sure the field gets set from the awaiter at the beginning of the next state.
                        nextState.Add(result.Assign(awaiter.Member("GetResult").Invoke()).Express());
                    }
                    else
                    {
                        // We still need to call GetResult even if void in order to propagate exceptions
                        nextState.Add(awaiter.Member("GetResult").Invoke().Express());
                    }

                    // Set the state to the next state
                    stateGenerator.CurrentState.Add(stateGenerator.ChangeState(nextState));

                    stateGenerator.CurrentState.Add(Js.If(
                                                        awaiter.Member("get_IsCompleted").Invoke(),

                                                        // If the awaiter is already completed, go to the next state
                                                        stateGenerator.GotoTop(),

                                                        // Otherwise await for completion
                                                        Js.Block(
                                                            // Start the async process
                                                            Js.Reference(builder)
                                                            .Member("TrueAwaitOnCompleted")
                                                            .Invoke(awaiterIdentifier.GetReference(), Js.Reference(stateMachine))
                                                            .Express(),
                                                            Js.Return()
                                                            )
                                                        ));

                    stateGenerator.CurrentState = nextState;

                    return(result ?? Js.Null());
                }

                return(base.VisitPrefixUnaryExpression(node));
            }
        public IList <JsStatement> Process(IEnumerable <JsType> types, ICompilation compilation, 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  = _metadataImporter.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 (_metadataImporter.IsResources(t.CSharpTypeDefinition))
                        {
                            result.Add(GenerateResourcesClass(c));
                        }
                        else
                        {
                            var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement);

                            if (c.TypeArgumentNames.Count == 0)
                            {
                                result.Add(new JsVariableDeclarationStatement(typeRef.Name, unnamedCtor));
                                AddClassMembers(c, typeRef, compilation, result);
                            }
                            else
                            {
                                var stmts = new List <JsStatement> {
                                    new JsVariableDeclarationStatement(InstantiatedGenericTypeVariableName, unnamedCtor)
                                };
                                AddClassMembers(c, JsExpression.Identifier(InstantiatedGenericTypeVariableName), compilation, stmts);
                                stmts.AddRange(c.StaticInitStatements);
                                stmts.Add(new JsReturnStatement(JsExpression.Identifier(InstantiatedGenericTypeVariableName)));
                                result.Add(new JsVariableDeclarationStatement(typeRef.Name, JsExpression.FunctionDefinition(c.TypeArgumentNames, new JsBlockStatement(stmts))));
                                result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(_systemType, c.ClassType == JsClass.ClassTypeEnum.Interface ? RegisterGenericInterface : RegisterGenericClass), GetRoot(t.CSharpTypeDefinition), JsExpression.String(name), typeRef, JsExpression.Number(c.TypeArgumentNames.Count))));
                            }
                        }
                    }
                    else if (t is JsEnum)
                    {
                        var  e     = (JsEnum)t;
                        bool flags = GetAttributePositionalArgs(t.CSharpTypeDefinition, FlagsAttribute, "System") != null;
                        result.Add(new JsVariableDeclarationStatement(typeRef.Name, JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement)));
                        result.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, Prototype), JsExpression.ObjectLiteral(e.Values.Select(v => new JsObjectLiteralProperty(v.Name, (_metadataImporter.IsNamedValues(t.CSharpTypeDefinition) ? JsExpression.String(v.Name) : JsExpression.Number(v.Value))))))));
                        result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(_systemType, RegisterEnum), GetRoot(t.CSharpTypeDefinition), JsExpression.String(name), typeRef, JsExpression.Boolean(flags))));
                    }
                }
                catch (Exception ex) {
                    _errorReporter.Region = t.CSharpTypeDefinition.Region;
                    _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName);
                }
            }

            var typesToRegister = orderedTypes.OfType <JsClass>()
                                  .Where(c => c.TypeArgumentNames.Count == 0 &&
                                         !string.IsNullOrEmpty(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name) &&
                                         (!_metadataImporter.IsResources(c.CSharpTypeDefinition) || Utils.IsPublic(c.CSharpTypeDefinition)) &&                          // Resources classes are only exported if they are public.
                                         !_metadataImporter.IsMixin(c.CSharpTypeDefinition))
                                  .ToList();

            result.AddRange(TopologicalSortTypesByInheritance(typesToRegister)
                            .Select(c => {
                try {
                    string name = _metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name;
                    if (_metadataImporter.IsResources(c.CSharpTypeDefinition))
                    {
                        return(JsExpression.Invocation(JsExpression.Member(_systemType, RegisterType), GetRoot(c.CSharpTypeDefinition), JsExpression.String(name), JsExpression.Identifier(_namer.GetTypeVariableName(name))));
                    }
                    if (c.ClassType == JsClass.ClassTypeEnum.Interface)
                    {
                        return(JsExpression.Invocation(JsExpression.Member(_systemType, RegisterInterface), GetRoot(c.CSharpTypeDefinition), JsExpression.String(name), JsExpression.Identifier(_namer.GetTypeVariableName(name)), JsExpression.ArrayLiteral(c.ImplementedInterfaces)));
                    }
                    else
                    {
                        return(CreateRegisterClassCall(GetRoot(c.CSharpTypeDefinition), name, JsExpression.Identifier(_namer.GetTypeVariableName(name)), c.BaseClass, c.ImplementedInterfaces));
                    }
                }
                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(orderedTypes.OfType <JsClass>().Where(c => c.TypeArgumentNames.Count == 0 && !_metadataImporter.IsResources(c.CSharpTypeDefinition)).SelectMany(t => t.StaticInitStatements));

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

            return(result);
        }
 public void IfStatementIsCorrectlyOutput()
 {
     AssertCorrect(new JsIfStatement(JsExpression.True, new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), null),
                   "if (true) {\n\ti = 0;\n}\n");
     AssertCorrect(new JsIfStatement(JsExpression.True, new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(1)))),
                   "if (true) {\n\ti = 0;\n}\nelse {\n\ti = 1;\n}\n");
 }
Ejemplo n.º 16
0
 private JsStatement MakeSetNextStateStatement(int targetStateValue)
 {
     return(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(_stateVariableName), JsExpression.Number(targetStateValue))));
 }
        public void IfAndElseIfStatementsAreChained()
        {
            AssertCorrect(new JsIfStatement(JsExpression.True, new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), null),
                          "if (true) {\n\ti = 0;\n}\n");
            AssertCorrect(new JsIfStatement(JsExpression.Identifier("a"), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))),
                                            new JsIfStatement(JsExpression.Identifier("b"), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(1))),
                                                              new JsIfStatement(JsExpression.Identifier("c"), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(2))), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(3)))))),
                          @"if (a) {
	i = 0;
}
else if (b) {
	i = 1;
}
else if (c) {
	i = 2;
}
else {
	i = 3;
}
");
        }
Ejemplo n.º 18
0
        public JsExpression GetExpressionForLocal(string name, JsExpression accessor, IType type, IRuntimeContext context)
        {
            var scriptType = TypeOf(type, context);

            JsExpression getterDefinition = JsExpression.FunctionDefinition(new string[0], JsStatement.Return(accessor));
            JsExpression setterDefinition = JsExpression.FunctionDefinition(new[] { "$" }, JsExpression.Assign(accessor, JsExpression.Identifier("$")));

            if (UsesThisVisitor.Analyze(accessor))
            {
                getterDefinition = JsExpression.Invocation(JsExpression.Member(getterDefinition, "bind"), JsExpression.This);
                setterDefinition = JsExpression.Invocation(JsExpression.Member(setterDefinition, "bind"), JsExpression.This);
            }

            return(JsExpression.ObjectLiteral(
                       new JsObjectLiteralProperty("ntype", JsExpression.Number((int)ExpressionType.MemberAccess)),
                       new JsObjectLiteralProperty("type", scriptType),
                       new JsObjectLiteralProperty("expression", JsExpression.ObjectLiteral(
                                                       new JsObjectLiteralProperty("ntype", JsExpression.Number((int)ExpressionType.Constant)),
                                                       new JsObjectLiteralProperty("type", scriptType),
                                                       new JsObjectLiteralProperty("value", JsExpression.ObjectLiteral())
                                                       )),
                       new JsObjectLiteralProperty("member", JsExpression.ObjectLiteral(
                                                       new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())),
                                                       new JsObjectLiteralProperty("name", JsExpression.String(name)),
                                                       new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Property)),
                                                       new JsObjectLiteralProperty("returnType", scriptType),
                                                       new JsObjectLiteralProperty("getter", JsExpression.ObjectLiteral(
                                                                                       new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())),
                                                                                       new JsObjectLiteralProperty("name", JsExpression.String("get_" + name)),
                                                                                       new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)),
                                                                                       new JsObjectLiteralProperty("returnType", scriptType),
                                                                                       new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral()),
                                                                                       new JsObjectLiteralProperty("def", getterDefinition)
                                                                                       )),
                                                       new JsObjectLiteralProperty("setter", JsExpression.ObjectLiteral(
                                                                                       new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())),
                                                                                       new JsObjectLiteralProperty("name", JsExpression.String("set_" + name)),
                                                                                       new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)),
                                                                                       new JsObjectLiteralProperty("returnType", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Void).GetDefinition())),
                                                                                       new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(scriptType)),
                                                                                       new JsObjectLiteralProperty("def", setterDefinition)
                                                                                       ))
                                                       ))
                       ));
        }
Ejemplo n.º 19
0
        public JsFunctionDefinitionExpression CompileAutoEventRemover(IEvent @event, EventScriptSemantics impl, string backingFieldName)
        {
            try {
                string valueName = _namer.GetVariableName(@event.RemoveAccessor.Parameters[0].Name, new HashSet <string>(@event.DeclaringTypeDefinition.TypeParameters.Select(p => _namer.GetTypeParameterName(p))));
                CreateCompilationContext(null, null, @event.DeclaringTypeDefinition, null);

                JsExpression target;
                string[]     args;
                if (@event.IsStatic)
                {
                    target = _runtimeLibrary.InstantiateType(Utils.SelfParameterize(@event.DeclaringTypeDefinition), _statementCompiler);
                    args   = new[] { valueName };
                }
                else if (impl.RemoveMethod.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument)
                {
                    target = JsExpression.Identifier(_namer.ThisAlias);
                    args   = new[] { _namer.ThisAlias, valueName };
                }
                else
                {
                    target = JsExpression.This;
                    args   = new[] { valueName };
                }

                var bfAccessor  = JsExpression.Member(target, backingFieldName);
                var combineCall = _statementCompiler.CompileDelegateRemoveCall(@event.RemoveAccessor.Region, bfAccessor, JsExpression.Identifier(valueName));
                return(JsExpression.FunctionDefinition(args, new JsBlockStatement(new JsExpressionStatement(JsExpression.Assign(bfAccessor, combineCall)))));
            }
            catch (Exception ex) {
                _errorReporter.Region = @event.Region;
                _errorReporter.InternalError(ex);
                return(JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement));
            }
        }
        public IList <JsStatement> Rewrite(IEnumerable <JsType> types, ICompilation compilation)
        {
            var netSystemType = compilation.FindType(KnownTypeCode.Type).GetDefinition();
            var systemType    = new JsTypeReferenceExpression(netSystemType.ParentAssembly, _metadataImporter.GetTypeSemantics(netSystemType).Name);

            var result = new List <JsStatement>();

            var    orderedTypes = OrderByNamespace(types, t => t.Name).ToList();
            string currentNs    = "";

            foreach (var t in orderedTypes)
            {
                try {
                    var globalMethodsPrefix = _metadataImporter.GetGlobalMethodsPrefix(t.CSharpTypeDefinition);

                    string ns = GetNamespace(t.Name);
                    if (ns != currentNs && globalMethodsPrefix == null)
                    {
                        result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(systemType, RegisterNamespace), JsExpression.String(ns))));
                        currentNs = ns;
                    }
                    result.Add(new JsComment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + t.CSharpTypeDefinition.FullName));

                    var typeRef = new JsTypeReferenceExpression(compilation.MainAssembly, t.Name);
                    if (t is JsClass)
                    {
                        var c = (JsClass)t;
                        if (globalMethodsPrefix != null)
                        {
                            if (globalMethodsPrefix == "")
                            {
                                result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.MemberAccess(JsExpression.Identifier("window"), m.Name), m.Definition))));
                            }
                            else
                            {
                                result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(MakeNestedMemberAccess(globalMethodsPrefix + "." + m.Name), m.Definition))));
                            }
                        }
                        else if (_metadataImporter.IsResources(t.CSharpTypeDefinition))
                        {
                            result.Add(GenerateResourcesClass(c));
                        }
                        else
                        {
                            var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement);

                            if (c.TypeArgumentNames.Count == 0)
                            {
                                result.Add(new JsExpressionStatement(JsExpression.Assign(typeRef, unnamedCtor)));
                                AddClassMembers(c, typeRef, compilation, result);
                            }
                            else
                            {
                                var stmts = new List <JsStatement> {
                                    new JsVariableDeclarationStatement(InstantiatedGenericTypeVariableName, unnamedCtor)
                                };
                                AddClassMembers(c, JsExpression.Identifier(InstantiatedGenericTypeVariableName), compilation, stmts);
                                stmts.AddRange(c.StaticInitStatements);
                                stmts.Add(new JsReturnStatement(JsExpression.Identifier(InstantiatedGenericTypeVariableName)));
                                result.Add(new JsExpressionStatement(JsExpression.Assign(typeRef, JsExpression.FunctionDefinition(c.TypeArgumentNames, new JsBlockStatement(stmts)))));
                                result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, c.ClassType == JsClass.ClassTypeEnum.Interface ? RegisterGenericInterface : RegisterGenericClass), JsExpression.String(c.Name), JsExpression.Number(c.TypeArgumentNames.Count))));
                            }
                        }
                    }
                    else if (t is JsEnum)
                    {
                        var  e     = (JsEnum)t;
                        bool flags = GetAttributePositionalArgs(t.CSharpTypeDefinition, FlagsAttribute, "System") != null;
                        result.Add(new JsExpressionStatement(JsExpression.Assign(typeRef, JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement))));
                        result.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, Prototype), JsExpression.ObjectLiteral(e.Values.Select(v => new JsObjectLiteralProperty(v.Name, (_metadataImporter.IsNamedValues(t.CSharpTypeDefinition) ? JsExpression.String(v.Name) : JsExpression.Number(v.Value))))))));
                        result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterEnum), JsExpression.String(t.Name), JsExpression.Boolean(flags))));
                    }
                }
                catch (Exception ex) {
                    _errorReporter.Region = t.CSharpTypeDefinition.Region;
                    _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName);
                }
            }

            var typesToRegister = orderedTypes.OfType <JsClass>()
                                  .Where(c => c.TypeArgumentNames.Count == 0 &&
                                         _metadataImporter.GetGlobalMethodsPrefix(c.CSharpTypeDefinition) == null &&
                                         !_metadataImporter.IsResources(c.CSharpTypeDefinition))
                                  .ToList();

            result.AddRange(TopologicalSortTypesByInheritance(typesToRegister)
                            .Select(c => {
                try {
                    var typeRef = new JsTypeReferenceExpression(compilation.MainAssembly, c.Name);
                    if (c.ClassType == JsClass.ClassTypeEnum.Interface)
                    {
                        return(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterInterface), JsExpression.String(c.Name), JsExpression.ArrayLiteral(c.ImplementedInterfaces)));
                    }
                    else
                    {
                        return(CreateRegisterClassCall(JsExpression.String(c.Name), c.BaseClass, c.ImplementedInterfaces, typeRef));
                    }
                }
                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(orderedTypes.OfType <JsClass>().Where(c => c.TypeArgumentNames.Count == 0 && !_metadataImporter.IsResources(c.CSharpTypeDefinition)).SelectMany(t => t.StaticInitStatements));

            return(result);
        }
Ejemplo n.º 21
0
        public JsFunctionDefinitionExpression CompileAutoPropertySetter(IProperty property, PropertyScriptSemantics impl, string backingFieldName)
        {
            try {
                string valueName = _namer.GetVariableName(property.Setter.Parameters[0].Name, new HashSet <string>(property.DeclaringTypeDefinition.TypeParameters.Select(p => _namer.GetTypeParameterName(p))));
                CreateCompilationContext(null, null, property.DeclaringTypeDefinition, null);

                if (property.IsStatic)
                {
                    var jsType = _runtimeLibrary.InstantiateType(Utils.SelfParameterize(property.DeclaringTypeDefinition), _statementCompiler);
                    return(JsExpression.FunctionDefinition(new[] { valueName }, JsExpression.Assign(JsExpression.Member(jsType, backingFieldName), JsExpression.Identifier(valueName))));
                }
                else if (impl.SetMethod.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument)
                {
                    return(JsExpression.FunctionDefinition(new[] { _namer.ThisAlias, valueName }, JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(_namer.ThisAlias), backingFieldName), JsExpression.Identifier(valueName))));
                }
                else
                {
                    return(JsExpression.FunctionDefinition(new[] { valueName }, JsExpression.Assign(JsExpression.Member(JsExpression.This, backingFieldName), JsExpression.Identifier(valueName))));
                }
            }
            catch (Exception ex) {
                _errorReporter.Region = property.Setter.Region;
                _errorReporter.InternalError(ex);
                return(JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock));
            }
        }
Ejemplo n.º 22
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 void TheOverallStructureIsCorrect()
        {
            AssertCorrect(
                @"{Type}.registerNamespace('OuterNamespace.InnerNamespace');
////////////////////////////////////////////////////////////////////////////////
// OuterNamespace.InnerNamespace.SomeEnum
{SomeEnum} = function() {
};
{SomeEnum}.prototype = { Value1: 1, Value2: 2, Value3: 3 };
{SomeEnum}.registerEnum('OuterNamespace.InnerNamespace.SomeEnum', false);
////////////////////////////////////////////////////////////////////////////////
// OuterNamespace.InnerNamespace.SomeType
{SomeType} = function() {
	this.a = 0;
};
{SomeType}.prototype = {
	method1: function(x) {
		return x;
	},
	method2: function(x, y) {
		return x + y;
	}
};
{SomeType}.staticMethod = function() {
};
////////////////////////////////////////////////////////////////////////////////
// OuterNamespace.InnerNamespace.SomeType2
{SomeType2} = function() {
	this.b = 0;
};
{SomeType2}.prototype = {
	method1: function(x) {
		return x;
	}
};
{SomeType2}.otherStaticMethod = function() {
};
{Type}.registerNamespace('OuterNamespace.InnerNamespace2');
////////////////////////////////////////////////////////////////////////////////
// OuterNamespace.InnerNamespace2.OtherInterface
{OtherInterface} = function() {
};
{OtherInterface}.prototype = { interfaceMethod: null };
////////////////////////////////////////////////////////////////////////////////
// OuterNamespace.InnerNamespace2.OtherType
{OtherType} = function() {
};
{OtherType}.prototype = {
	method1: function(x) {
		return x;
	}
};
{SomeType}.registerClass('OuterNamespace.InnerNamespace.SomeType');
{SomeType2}.registerClass('OuterNamespace.InnerNamespace.SomeType2');
{OtherInterface}.registerInterface('OuterNamespace.InnerNamespace2.OtherInterface', []);
{OtherType}.registerClass('OuterNamespace.InnerNamespace2.OtherType', {SomeType2});
y = 1;
x = 1;
",

                new JsClass(CreateMockType("OuterNamespace.InnerNamespace.SomeType"), "OuterNamespace.InnerNamespace.SomeType", JsClass.ClassTypeEnum.Class, null, null, null)
            {
                UnnamedConstructor = JsExpression.FunctionDefinition(new string[0], new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(JsExpression.This, "a"), JsExpression.Number(0)))),
                InstanceMethods    = { new JsMethod(CreateMockMethod("Method1"), "method1", null, JsExpression.FunctionDefinition(new[] { "x" }, new JsReturnStatement(JsExpression.Identifier("x")))),
                                       new JsMethod(CreateMockMethod("Method2"),    "method2", null, JsExpression.FunctionDefinition(new[] { "x", "y"}, new JsReturnStatement(JsExpression.Binary(ExpressionNodeType.Add, JsExpression.Identifier("x"), JsExpression.Identifier("y"))))) },
                StaticMethods = { new JsMethod(CreateMockMethod("StaticMethod"), "staticMethod", null, JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement)) },
            },
                new JsClass(CreateMockType("OuterNamespace.InnerNamespace.SomeType2"), "OuterNamespace.InnerNamespace.SomeType2", JsClass.ClassTypeEnum.Class, null, null, null)
            {
                UnnamedConstructor   = JsExpression.FunctionDefinition(new string[0], new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(JsExpression.This, "b"), JsExpression.Number(0)))),
                InstanceMethods      = { new JsMethod(CreateMockMethod("Method1"), "method1", null, JsExpression.FunctionDefinition(new[] { "x" }, new JsReturnStatement(JsExpression.Identifier("x")))) },
                StaticMethods        = { new JsMethod(CreateMockMethod("OtherStaticMethod"), "otherStaticMethod", null, JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement)) },
                StaticInitStatements = { new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("y"), JsExpression.Number(1))) }
            },
                new JsEnum(CreateMockType("OuterNamespace.InnerNamespace.SomeEnum"), "OuterNamespace.InnerNamespace.SomeEnum", new[] {
                new JsEnumValue("Value1", 1),
                new JsEnumValue("Value2", 2),
                new JsEnumValue("Value3", 3),
            }),
                new JsClass(CreateMockType("OuterNamespace.InnerNamespace2.OtherType"), "OuterNamespace.InnerNamespace2.OtherType", JsClass.ClassTypeEnum.Class, null, new JsTypeReferenceExpression(null, "OuterNamespace.InnerNamespace.SomeType2"), null)
            {
                UnnamedConstructor   = JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement),
                InstanceMethods      = { new JsMethod(CreateMockMethod("Method1"), "method1", null, JsExpression.FunctionDefinition(new[] { "x" }, new JsReturnStatement(JsExpression.Identifier("x")))), },
                StaticInitStatements = { new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("x"), JsExpression.Number(1))) }
            },
                new JsClass(CreateMockType("OuterNamespace.InnerNamespace2.OtherInterface"), "OuterNamespace.InnerNamespace2.OtherInterface", JsClass.ClassTypeEnum.Interface, null, null, null)
            {
                UnnamedConstructor   = JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement),
                InstanceMethods      = { new JsMethod(CreateMockMethod("InterfaceMethod"), "interfaceMethod", null, null) },
                StaticInitStatements = {}
            });
        }