Ejemplo n.º 1
0
 public void ArrayLiteralsContainNoSpaces()
 {
     AssertCorrect(JsExpression.ArrayLiteral(), "[]");
     AssertCorrect(JsExpression.ArrayLiteral(JsExpression.Number(1)), "[1]");
     AssertCorrect(JsExpression.ArrayLiteral(JsExpression.Number(1), JsExpression.Number(2)), "[1,2]");
     AssertCorrect(JsExpression.ArrayLiteral(JsExpression.Number(1), null, JsExpression.Number(2), null), "[1,,2,]");
 }
 public void AssignmentIsNotParenthesizedInsideConstructorArgumentList()
 {
     AssertCorrect(JsExpression.ArrayLiteral(
                       JsExpression.Binary(ExpressionNodeType.Assign,
                                           JsExpression.Number(1),
                                           JsExpression.Number(2)
                                           )
                       ),
                   "[1 = 2]");
 }
Ejemplo n.º 3
0
        private JsExpression CreateInitInterfaceCall(JsClass type, string ctorName, IList <JsExpression> interfaces)
        {
            var args = new List <JsExpression> {
                JsExpression.Identifier(ctorName), _linker.CurrentAssemblyExpression, CreateInstanceMembers(type, null)
            };

            if (interfaces.Count > 0)
            {
                args.Add(JsExpression.ArrayLiteral(interfaces));
            }
            return(JsExpression.Invocation(JsExpression.Member(_systemScript, InitInterface), args));
        }
Ejemplo n.º 4
0
        public static JsExpression ConstructFieldPropertyAccessor(IMethod m, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, string fieldName, Func <IType, JsExpression> instantiateType, bool isGetter, bool includeDeclaringType)
        {
            var properties = GetCommonMemberInfoProperties(m, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType);

            properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)));
            properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(m.Parameters.Select(p => instantiateType(p.Type)))));
            properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(m.ReturnType)));
            properties.Add(new JsObjectLiteralProperty(isGetter ? "fget" : "fset", JsExpression.String(fieldName)));
            if (m.IsStatic)
            {
                properties.Add(new JsObjectLiteralProperty("isStatic", JsExpression.True));
            }
            return(JsExpression.ObjectLiteral(properties));
        }
Ejemplo n.º 5
0
            public static IList <JsStatement> Process(IMetadataImporter metadataImporter, INamer namer, ICompilation compilation, IList <JsStatement> statements)
            {
                var usedSymbols        = UsedSymbolsGatherer.Analyze(statements);
                var importer           = new ImportVisitor(metadataImporter, namer, compilation.MainAssembly, usedSymbols);
                var body               = statements.Select(s => importer.VisitStatement(s, null)).ToList();
                var moduleDependencies = importer._moduleAliases.Concat(MetadataUtils.GetAdditionalDependencies(compilation.MainAssembly));

                if (MetadataUtils.IsAsyncModule(compilation.MainAssembly))
                {
                    body.InsertRange(0, new[] { JsStatement.UseStrict, JsStatement.Var("exports", JsExpression.ObjectLiteral()) });
                    body.Add(JsStatement.Return(JsExpression.Identifier("exports")));

                    var pairs = new[] { new KeyValuePair <string, string>("mscorlib", namer.GetVariableName("_", usedSymbols)) }
                    .Concat(moduleDependencies.OrderBy(x => x.Key))
                    .ToList();

                    body = new List <JsStatement> {
                        JsExpression.Invocation(
                            JsExpression.Identifier("define"),
                            JsExpression.ArrayLiteral(pairs.Select(p => JsExpression.String(p.Key))),
                            JsExpression.FunctionDefinition(
                                pairs.Select(p => p.Value),
                                JsStatement.Block(body)
                                )
                            )
                    };
                }
                else if (moduleDependencies.Any())
                {
                    // If we require any module, we require mscorlib. This should work even if we are a leaf module that doesn't include any other module because our parent script will do the mscorlib require for us.
                    body.InsertRange(0, new[] { JsStatement.UseStrict, JsExpression.Invocation(JsExpression.Identifier("require"), JsExpression.String("mscorlib")) }
                                     .Concat(moduleDependencies
                                             .OrderBy(x => x.Key).OrderBy(x => x.Key)
                                             .Select(x => JsStatement.Var(
                                                         x.Value,
                                                         JsExpression.Invocation(
                                                             JsExpression.Identifier("require"),
                                                             JsExpression.String(x.Key))))
                                             .ToList()));
                }
                else
                {
                    body.Insert(0, JsStatement.UseStrict);
                    body = new List <JsStatement> {
                        JsExpression.Invocation(JsExpression.FunctionDefinition(new string[0], JsStatement.Block(body)))
                    };
                }

                return(body);
            }
 public void CommaIsParenthesizedInsideArrayLiteral()
 {
     AssertCorrect(JsExpression.ArrayLiteral(
                       JsExpression.Comma(
                           JsExpression.Number(1),
                           JsExpression.Number(2)
                           ),
                       JsExpression.Number(3),
                       JsExpression.Comma(
                           JsExpression.Number(4),
                           JsExpression.Number(5)
                           )
                       ),
                   "[(1, 2), 3, (4, 5)]");
 }
Ejemplo n.º 7
0
        private JsExpression GetMetadataDescriptor(ITypeDefinition type, bool isGenericSpecialization)
        {
            var properties           = new List <JsObjectLiteralProperty>();
            var scriptableAttributes = MetadataUtils.GetScriptableAttributes(type.Attributes, _metadataImporter).ToList();

            if (scriptableAttributes.Count != 0)
            {
                properties.Add(new JsObjectLiteralProperty("attr", JsExpression.ArrayLiteral(scriptableAttributes.Select(a => MetadataUtils.ConstructAttribute(a, type, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter)))));
            }
            if (type.Kind == TypeKind.Interface && MetadataUtils.IsJsGeneric(type, _metadataImporter) && type.TypeParameters != null && type.TypeParameters.Any(typeParameter => typeParameter.Variance != VarianceModifier.Invariant))
            {
                properties.Add(new JsObjectLiteralProperty("variance", JsExpression.ArrayLiteral(type.TypeParameters.Select(typeParameter => JsExpression.Number(ConvertVarianceToInt(typeParameter.Variance))))));
            }
            if (type.Kind == TypeKind.Class || type.Kind == TypeKind.Struct || type.Kind == TypeKind.Interface)
            {
                var members = type.Members.Where(m => MetadataUtils.IsReflectable(m, _attributeStore))
                              .OrderBy(m => m, MemberOrderer.Instance)
                              .Select(m => {
                    _errorReporter.Region = m.Region;
                    return(MetadataUtils.ConstructMemberInfo(m, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter, t => _runtimeLibrary.InstantiateType(t, isGenericSpecialization ? _genericSpecializationReflectionRuntimeContext : _defaultReflectionRuntimeContext), includeDeclaringType: false));
                })
                              .ToList();
                if (members.Count > 0)
                {
                    properties.Add(new JsObjectLiteralProperty("members", JsExpression.ArrayLiteral(members)));
                }

                var aua = _attributeStore.AttributesFor(type).GetAttribute <AttributeUsageAttribute>();
                if (aua != null)
                {
                    if (!aua.Inherited)
                    {
                        properties.Add(new JsObjectLiteralProperty("attrNoInherit", JsExpression.True));
                    }
                    if (aua.AllowMultiple)
                    {
                        properties.Add(new JsObjectLiteralProperty("attrAllowMultiple", JsExpression.True));
                    }
                }
            }
            if (type.Kind == TypeKind.Enum && _attributeStore.AttributesFor(type).HasAttribute <FlagsAttribute>())
            {
                properties.Add(new JsObjectLiteralProperty("enumFlags", JsExpression.True));
            }

            return(properties.Count > 0 ? JsExpression.ObjectLiteral(properties) : null);
        }
Ejemplo n.º 8
0
        private static List <JsObjectLiteralProperty> GetCommonMemberInfoProperties(IMember m, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, Func <IType, JsExpression> instantiateType, bool includeDeclaringType)
        {
            var result = new List <JsObjectLiteralProperty>();
            var attr   = GetScriptableAttributes(m.Attributes, metadataImporter).ToList();

            if (attr.Count > 0)
            {
                result.Add(new JsObjectLiteralProperty("attr", JsExpression.ArrayLiteral(attr.Select(a => ConstructAttribute(a, m.DeclaringTypeDefinition, compilation, metadataImporter, namer, runtimeLibrary, errorReporter)))));
            }
            if (includeDeclaringType)
            {
                result.Add(new JsObjectLiteralProperty("typeDef", instantiateType(m.DeclaringType)));
            }

            result.Add(new JsObjectLiteralProperty("name", JsExpression.String(m.Name)));
            return(result);
        }
Ejemplo n.º 9
0
        private JsExpression CreateInitClassCall(JsClass type, string ctorName, JsExpression baseClass, IList <JsExpression> interfaces)
        {
            var args = new List <JsExpression> {
                JsExpression.Identifier(ctorName), CreateInstanceMembers(type)
            };

            if (baseClass != null || interfaces.Count > 0)
            {
                args.Add(baseClass ?? JsExpression.Null);
            }
            if (interfaces.Count > 0)
            {
                args.Add(JsExpression.ArrayLiteral(interfaces));
            }

            return(JsExpression.Invocation(JsExpression.Member(_systemScript, InitClass), args));
        }
Ejemplo n.º 10
0
        private JsExpression CreateRegisterInterfaceCall(ITypeDefinition type, string name, JsExpression ctor, IList <JsExpression> interfaces)
        {
            var args = new List <JsExpression> {
                GetRoot(type), JsExpression.String(name), ctor
            };
            var metadata = GetMetadataDescriptor(type, false);

            if (interfaces.Count > 0 || metadata != null)
            {
                args.Add(JsExpression.ArrayLiteral(interfaces));
            }
            if (metadata != null)
            {
                args.Add(metadata);
            }
            return(JsExpression.Invocation(JsExpression.Member(_systemScript, RegisterInterface), args));
        }
Ejemplo n.º 11
0
        private JsExpression GetMetadataDescriptor(ITypeDefinition type, bool isGenericSpecialization)
        {
            var properties           = new List <JsObjectLiteralProperty>();
            var scriptableAttributes = type.Attributes.Where(a => !a.IsConditionallyRemoved && _metadataImporter.GetTypeSemantics(a.AttributeType.GetDefinition()).Type == TypeScriptSemantics.ImplType.NormalType).ToList();

            if (scriptableAttributes.Count != 0)
            {
                properties.Add(new JsObjectLiteralProperty("attr", JsExpression.ArrayLiteral(scriptableAttributes.Select(a => MetadataUtils.ConstructAttribute(a, type, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter)))));
            }
            if (type.Kind == TypeKind.Class)
            {
                var members = type.Members.Where(m => MetadataUtils.IsReflectable(m, _metadataImporter))
                              .OrderBy(m => m, MemberOrderer.Instance)
                              .Select(m => {
                    _errorReporter.Region = m.Region;
                    return(MetadataUtils.ConstructMemberInfo(m, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter, t => _runtimeLibrary.InstantiateType(t, isGenericSpecialization ? _genericSpecializationReflectionRuntimeContext : _defaultReflectionRuntimeContext), includeDeclaringType: false));
                })
                              .ToList();
                if (members.Count > 0)
                {
                    properties.Add(new JsObjectLiteralProperty("members", JsExpression.ArrayLiteral(members)));
                }

                var aua = AttributeReader.ReadAttribute <AttributeUsageAttribute>(type);
                if (aua != null)
                {
                    if (!aua.Inherited)
                    {
                        properties.Add(new JsObjectLiteralProperty("attrNoInherit", JsExpression.True));
                    }
                    if (aua.AllowMultiple)
                    {
                        properties.Add(new JsObjectLiteralProperty("attrAllowMultiple", JsExpression.True));
                    }
                }
            }
            if (type.Kind == TypeKind.Enum && AttributeReader.HasAttribute <FlagsAttribute>(type))
            {
                properties.Add(new JsObjectLiteralProperty("enumFlags", JsExpression.True));
            }

            return(properties.Count > 0 ? JsExpression.ObjectLiteral(properties) : null);
        }
Ejemplo n.º 12
0
            public static IList <JsStatement> Process(IScriptSharpMetadataImporter metadataImporter, INamer namer, IAssembly mainAssembly, IList <JsStatement> statements)
            {
                var usedSymbols = UsedSymbolsGatherer.Analyze(statements);
                var importer    = new ImportVisitor(metadataImporter, namer, mainAssembly, usedSymbols);
                var body        = statements.Select(s => importer.VisitStatement(s, null)).ToList();

                if (metadataImporter.IsAsyncModule)
                {
                    body.Insert(0, new JsVariableDeclarationStatement("exports", JsExpression.ObjectLiteral()));
                    body.Add(new JsReturnStatement(JsExpression.Identifier("exports")));

                    var pairs = new[] { new KeyValuePair <string, string>("mscorlib", namer.GetVariableName("_", usedSymbols)) }.Concat(importer._moduleAliases.OrderBy(x => x.Key)).ToList();

                    body = new List <JsStatement> {
                        new JsExpressionStatement(
                            JsExpression.Invocation(
                                JsExpression.Identifier("define"),
                                JsExpression.ArrayLiteral(pairs.Select(p => JsExpression.String(p.Key))),
                                JsExpression.FunctionDefinition(
                                    pairs.Select(p => p.Value),
                                    new JsBlockStatement(body)
                                    )
                                )
                            )
                    };
                }
                else if (importer._moduleAliases.Count > 0)
                {
                    // If we require any module, we require mscorlib. This should work even if we are a leaf module that doesn't include any other module because our parent script will do the mscorlib require for us.
                    body.InsertRange(0, new[] { (JsStatement) new JsExpressionStatement(JsExpression.Invocation(JsExpression.Identifier("require"), JsExpression.String("mscorlib"))) }
                                     .Concat(importer._moduleAliases.OrderBy(x => x.Key)
                                             .Select(x => new JsVariableDeclarationStatement(
                                                         x.Value,
                                                         JsExpression.Invocation(
                                                             JsExpression.Identifier("require"),
                                                             JsExpression.String(x.Key))))
                                             .ToList()));
                }
                return(body);
            }
        public JsExpression CallBase(IMethod method, IEnumerable <JsExpression> thisAndArguments, IRuntimeContext context)
        {
            var impl = GetMethodSemantics(method);

            JsExpression jsMethod = JsExpression.Member(JsExpression.Member(GetScriptType(method.DeclaringType, TypeContext.GetScriptType, context), "prototype"), impl.Name);

            if (method is SpecializedMethod && !impl.IgnoreGenericArguments)
            {
                jsMethod = InstantiateGenericMethod(jsMethod, ((SpecializedMethod)method).TypeArguments, context);
            }

            if (impl.ExpandParams)
            {
                var args = thisAndArguments.ToList();
                if (args[args.Count - 1] is JsArrayLiteralExpression)
                {
                    return(JsExpression.Invocation(JsExpression.Member(jsMethod, "call"), args.Take(args.Count - 1).Concat(((JsArrayLiteralExpression)args[args.Count - 1]).Elements)));
                }
                else
                {
                    return(JsExpression.Invocation(JsExpression.Member(jsMethod, "apply"), args[0], args.Count == 2 ? args[1] : JsExpression.Invocation(JsExpression.Member(JsExpression.ArrayLiteral(args.Skip(1).Take(args.Count - 2)), "concat"), args[args.Count - 1])));
                }
            }
            else
            {
                return(JsExpression.Invocation(JsExpression.Member(jsMethod, "call"), thisAndArguments));
            }
        }
 private JsExpression GetScriptType(IType type, TypeContext typeContext, IRuntimeContext context)
 {
     if (type.Kind == TypeKind.Delegate)
     {
         return(CreateTypeReferenceExpression(KnownTypeReference.Delegate));
     }
     else if (type is ParameterizedType)
     {
         var pt  = (ParameterizedType)type;
         var def = pt.GetDefinition();
         var sem = _metadataImporter.GetTypeSemantics(def);
         if (sem.Type == TypeScriptSemantics.ImplType.NormalType && !sem.IgnoreGenericArguments)
         {
             return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "makeGenericType"), CreateTypeReferenceExpression(type.GetDefinition()), JsExpression.ArrayLiteral(pt.TypeArguments.Select(a => GetScriptType(a, TypeContext.GenericArgument, context)))));
         }
         else
         {
             return(GetTypeDefinitionScriptType(type.GetDefinition(), typeContext));
         }
     }
     else if (type.TypeParameterCount > 0)
     {
         // This handles open generic types ( typeof(C<,>) )
         return(CreateTypeReferenceExpression(type.GetDefinition()));
     }
     else if (type.Kind == TypeKind.Array)
     {
         return(CreateTypeReferenceExpression(KnownTypeReference.Array));
     }
     else if (type is ITypeParameter)
     {
         return(context.ResolveTypeParameter((ITypeParameter)type));
     }
     else if (type is ITypeDefinition)
     {
         return(GetTypeDefinitionScriptType((ITypeDefinition)type, typeContext));
     }
     else if (type.Kind == TypeKind.Anonymous || type.Kind == TypeKind.Null || type.Kind == TypeKind.Dynamic)
     {
         return(CreateTypeReferenceExpression(KnownTypeReference.Object));
     }
     else
     {
         throw new InvalidOperationException("Could not determine the script type for " + type + ", context " + typeContext);
     }
 }
Ejemplo n.º 15
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)));
            }
        }
        public virtual JsExpression VisitArrayLiteralExpression(JsArrayLiteralExpression expression, TData data)
        {
            var after = VisitExpressions(expression.Elements, data);

            return(ReferenceEquals(after, expression.Elements) ? expression : JsExpression.ArrayLiteral(after));
        }
        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);
        }
        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);
        }
Ejemplo n.º 19
0
        private static JsExpression ConstructConstructorInfo(IMethod constructor, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, Func <IType, JsExpression> instantiateType, bool includeDeclaringType)
        {
            var properties = GetCommonMemberInfoProperties(constructor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType);

            var sem = metadataImporter.GetConstructorSemantics(constructor);

            if (sem.Type == ConstructorScriptSemantics.ImplType.NotUsableFromScript)
            {
                errorReporter.Message(Messages._7200, constructor.FullName);
                return(JsExpression.Null);
            }
            properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Constructor)));
            properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(constructor.Parameters.Select(p => instantiateType(p.Type)))));
            if (sem.Type == ConstructorScriptSemantics.ImplType.NamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod)
            {
                properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name)));
            }
            if (sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod)
            {
                properties.Add(new JsObjectLiteralProperty("sm", JsExpression.True));
            }
            if ((sem.Type == ConstructorScriptSemantics.ImplType.UnnamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.NamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod) && sem.ExpandParams)
            {
                properties.Add(new JsObjectLiteralProperty("exp", JsExpression.True));
            }
            if (sem.Type == ConstructorScriptSemantics.ImplType.Json || sem.Type == ConstructorScriptSemantics.ImplType.InlineCode)
            {
                var usedNames  = new HashSet <string>();
                var parameters = new List <IVariable>();
                var variables  = new Dictionary <IVariable, VariableData>();
                IList <ResolveResult> constructorParameters = null;
                IList <ResolveResult> initializerStatements = null;
                if (sem.Type == ConstructorScriptSemantics.ImplType.Json && constructor.DeclaringType.Kind == TypeKind.Anonymous)
                {
                    initializerStatements = new List <ResolveResult>();
                    foreach (var p in constructor.DeclaringType.GetProperties())
                    {
                        string paramName = MakeCamelCase(p.Name);
                        string name      = namer.GetVariableName(paramName, usedNames);
                        usedNames.Add(name);
                        var variable = new SimpleVariable(p.ReturnType, paramName, DomRegion.Empty);
                        parameters.Add(variable);
                        variables.Add(variable, new VariableData(name, null, false));
                        initializerStatements.Add(new OperatorResolveResult(p.ReturnType, ExpressionType.Assign, new MemberResolveResult(new InitializedObjectResolveResult(constructor.DeclaringType), p), new LocalResolveResult(variable)));
                    }
                }
                else
                {
                    constructorParameters = new List <ResolveResult>();
                    foreach (var p in constructor.Parameters)
                    {
                        string name = namer.GetVariableName(p.Name, usedNames);
                        usedNames.Add(name);
                        var variable = new SimpleVariable(p.Type, p.Name, DomRegion.Empty);
                        parameters.Add(variable);
                        variables.Add(variable, new VariableData(name, null, false));
                        constructorParameters.Add(new LocalResolveResult(variable));
                    }
                }
                var compileResult = CompileConstructorInvocation(constructor, initializerStatements, constructor.DeclaringTypeDefinition, constructor, constructorParameters, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, variables, usedNames);
                var definition    = JsExpression.FunctionDefinition(parameters.Select(p => variables[p].Name), JsStatement.Block(compileResult.AdditionalStatements.Concat(new[] { JsStatement.Return(compileResult.Expression) })));
                properties.Add(new JsObjectLiteralProperty("def", definition));
            }
            return(JsExpression.ObjectLiteral(properties));
        }
        public static IList <string> ValidateLiteralCode(IMethod method, string literalCode, Func <string, JsExpression> resolveType, Func <IType, JsExpression> resolveTypeArgument)
        {
            var errors = new List <string>();

            var tokens = Tokenize(method, literalCode, s => errors.Add("Error in literal code pattern: " + s));

            if (tokens == null)
            {
                return(errors);
            }

            CompileInlineCodeMethodInvocation(method,
                                              tokens,
                                              method.IsStatic || method.IsConstructor ? null : JsExpression.Null,
                                              method.Parameters.Select(p => p.IsParams ? (JsExpression)JsExpression.ArrayLiteral() : JsExpression.String("X")).ToList(),
                                              resolveType,
                                              resolveTypeArgument,
                                              errors.Add);
            return(errors);
        }
            public override JsExpression VisitArrayLiteralExpression(JsArrayLiteralExpression expression, object data)
            {
                var l = VisitWithParamExpansion(expression.Elements);

                return(ReferenceEquals(l, expression.Elements) ? expression : JsExpression.ArrayLiteral(l));
            }
        public static JsExpression CompileInlineCodeMethodInvocation(IMethod method, IList <InlineCodeToken> tokens, JsExpression @this, IList <JsExpression> arguments, Func <string, JsExpression> resolveType, Func <IType, JsExpression> resolveTypeArgument, Action <string> errorReporter)
        {
            var  text          = new StringBuilder();
            var  substitutions = new Dictionary <string, Tuple <JsExpression, bool> >();
            bool hasErrors     = false;

            foreach (var token in tokens)
            {
                switch (token.Type)
                {
                case InlineCodeToken.TokenType.Text:
                    text.Append(token.Text);
                    break;

                case InlineCodeToken.TokenType.This: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);

                    if (@this == null)
                    {
                        hasErrors = true;
                        errorReporter("Cannot use {this} in the literal code for a static method");
                        substitutions[s] = Tuple.Create((JsExpression)JsExpression.Null, false);
                    }
                    else
                    {
                        substitutions[s] = Tuple.Create(@this, false);
                    }
                    break;
                }

                case InlineCodeToken.TokenType.Parameter: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);
                    substitutions[s] = Tuple.Create(arguments[token.Index], token.IsExpandedParamArray);

                    if (token.IsExpandedParamArray)
                    {
                        if (!method.Parameters[token.Index].IsParams)
                        {
                            hasErrors = true;
                            errorReporter("The parameter " + method.Parameters[token.Index].Name + " must be a param array in order to use it with the * modifier.");
                            substitutions[s] = Tuple.Create((JsExpression)JsExpression.ArrayLiteral(), true);
                        }
                        else if (arguments[arguments.Count - 1].NodeType != ExpressionNodeType.ArrayLiteral)
                        {
                            throw new Exception("The last argument must be a literal array if using the {*arg} placeholder");
                        }
                    }
                    break;
                }

                case InlineCodeToken.TokenType.TypeParameter: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);
                    var l = token.OwnerType == EntityType.TypeDefinition ? method.DeclaringType.TypeArguments : method.TypeArguments;
                    substitutions[s] = Tuple.Create(l != null ? resolveTypeArgument(l[token.Index]) : JsExpression.Null, false);
                    break;
                }

                case InlineCodeToken.TokenType.TypeRef: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);

                    substitutions[s] = Tuple.Create(resolveType(token.Text), false);
                    break;
                }

                case InlineCodeToken.TokenType.LiteralStringParameterToUseAsIdentifier: {
                    if (!method.Parameters[token.Index].Type.IsKnownType(KnownTypeCode.String))
                    {
                        text.Append("X");                                       // Just something that should not cause an error.
                        hasErrors = true;
                        errorReporter("The type of the parameter " + method.Parameters[token.Index].Name + " must be string in order to use it with the '@' modifier.");
                    }
                    else
                    {
                        var jce = arguments[token.Index] as JsConstantExpression;
                        if (jce != null && jce.NodeType == ExpressionNodeType.String)
                        {
                            text.Append(jce.StringValue);
                        }
                        else
                        {
                            text.Append("X");                                           // Just something that should not cause an error.
                            hasErrors = true;
                            errorReporter("The argument specified for parameter " + method.Parameters[token.Index].Name + " must be a literal string");
                        }
                    }
                    break;
                }

                default:
                    throw new ArgumentException("Unknown token type " + token.Type);
                }
            }

            if (hasErrors)
            {
                return(JsExpression.Number(0));
            }

            try {
                var expr = JavaScriptParser.Parser.ParseExpression(text.ToString());
                return(new Substituter(substitutions, errorReporter).Process(expr));
            }
            catch (RecognitionException) {
                errorReporter("syntax error in inline code");
                return(JsExpression.Number(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)
                                                                                       ))
                                                       ))
                       ));
        }
        public static IList <string> ValidateLiteralCode(IMethod method, string literalCode, Func <ITypeReference, IType> resolveType)
        {
            var errors = new List <string>();

            CompileInlineCodeMethodInvocation(method,
                                              literalCode,
                                              method.IsStatic ? null : JsExpression.Null,
                                              method.Parameters.Select(p => p.IsParams ? (JsExpression)JsExpression.ArrayLiteral() : JsExpression.String("X")).ToList(),
                                              resolveType,
                                              (t, c) => JsExpression.Null,
                                              true,
                                              errors.Add);
            return(errors);
        }
Ejemplo n.º 25
0
        public IEnumerable <JsStatement> GetCodeAfterLastType(IEnumerable <JsType> types)
        {
            var scriptableAttributes = MetadataUtils.GetScriptableAttributes(_compilation.MainAssembly.AssemblyAttributes, _metadataImporter).ToList();

            if (scriptableAttributes.Count > 0)
            {
                return new[] { (JsStatement)JsExpression.Assign(JsExpression.Member(_linker.CurrentAssemblyExpression, "attr"), JsExpression.ArrayLiteral(scriptableAttributes.Select(a => MetadataUtils.ConstructAttribute(a, null, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter)))) }
            }
            ;
            else
            {
                return(EmptyList <JsStatement> .Instance);
            }
        }
        public static JsExpression CompileInlineCodeMethodInvocation(IMethod method, string literalCode, JsExpression @this, IList <JsExpression> arguments, Func <ITypeReference, IType> resolveType, Func <IType, TypeContext, JsExpression> getJsType, bool isParamArrayExpanded, Action <string> errorReporter)
        {
            List <string> typeParameterNames = new List <string>();
            List <IType>  typeArguments      = new List <IType>();

            if (method.DeclaringTypeDefinition.TypeParameterCount > 0)
            {
                var parameterizedType = method.DeclaringType as ParameterizedType;
                typeParameterNames.AddRange(method.DeclaringTypeDefinition.TypeParameters.Select(p => p.Name));
                if (parameterizedType != null)
                {
                    typeArguments.AddRange(parameterizedType.TypeArguments);
                }
                else
                {
                    typeArguments.AddRange(Enumerable.Repeat(resolveType(ReflectionHelper.ParseReflectionName("System.Object")), method.DeclaringType.TypeParameterCount));
                }
            }

            if (method.TypeParameters.Count > 0)
            {
                typeParameterNames.AddRange(method.TypeParameters.Select(p => p.Name).ToList());
                var specializedMethod = method as SpecializedMethod;
                if (specializedMethod != null)
                {
                    typeArguments.AddRange(specializedMethod.TypeArguments);
                }
                else
                {
                    typeArguments.AddRange(Enumerable.Repeat(resolveType(ReflectionHelper.ParseReflectionName("System.Object")), method.TypeParameters.Count));
                }
            }

            var tokens = Tokenize(literalCode, method.Parameters.Select(p => p.Name).ToList(), typeParameterNames, s => errorReporter("Error in literal code pattern: " + s));

            if (tokens == null)
            {
                return(JsExpression.Number(0));
            }

            var  text          = new StringBuilder();
            var  substitutions = new Dictionary <string, Tuple <JsExpression, bool> >();
            bool hasErrors     = false;

            foreach (var token in tokens)
            {
                switch (token.Type)
                {
                case InlineCodeToken.TokenType.Text:
                    text.Append(token.Text);
                    break;

                case InlineCodeToken.TokenType.This: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);

                    if (@this == null)
                    {
                        hasErrors = true;
                        errorReporter("Cannot use {this} in the literal code for a static method");
                        substitutions[s] = Tuple.Create((JsExpression)JsExpression.Null, false);
                    }
                    else
                    {
                        substitutions[s] = Tuple.Create(@this, false);
                    }
                    break;
                }

                case InlineCodeToken.TokenType.Parameter: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);
                    substitutions[s] = Tuple.Create(arguments[token.Index], false);
                    break;
                }

                case InlineCodeToken.TokenType.TypeParameter: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);
                    substitutions[s] = Tuple.Create(getJsType(typeArguments[token.Index], TypeContext.GenericArgument), false);
                    break;
                }

                case InlineCodeToken.TokenType.TypeRef: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);

                    var type = resolveType(ReflectionHelper.ParseReflectionName(token.Text));
                    if (type.Kind == TypeKind.Unknown)
                    {
                        hasErrors = true;
                        errorReporter("Unknown type '" + token.Text + "' specified in inline implementation");
                        substitutions[s] = Tuple.Create((JsExpression)JsExpression.Null, false);
                    }
                    else
                    {
                        substitutions[s] = Tuple.Create(getJsType(type, TypeContext.GenericArgument), false);
                    }
                    break;
                }

                case InlineCodeToken.TokenType.LiteralStringParameterToUseAsIdentifier: {
                    if (!method.Parameters[token.Index].Type.IsKnownType(KnownTypeCode.String))
                    {
                        text.Append("X");                                       // Just something that should not cause an error.
                        hasErrors = true;
                        errorReporter("The type of the parameter " + method.Parameters[token.Index].Name + " must be string in order to use it with the '@' modifier.");
                    }
                    else
                    {
                        var jce = arguments[token.Index] as JsConstantExpression;
                        if (jce != null && jce.NodeType == ExpressionNodeType.String)
                        {
                            text.Append(jce.StringValue);
                        }
                        else
                        {
                            text.Append("X");                                           // Just something that should not cause an error.
                            hasErrors = true;
                            errorReporter("The argument specified for parameter " + method.Parameters[token.Index].Name + " must be a literal string");
                        }
                    }
                    break;
                }

                case InlineCodeToken.TokenType.ExpandedParamArrayParameter: {
                    string s = string.Format(CultureInfo.InvariantCulture, "$$__{0}__$$", substitutions.Count);
                    text.Append(s);

                    if (!method.Parameters[token.Index].IsParams)
                    {
                        hasErrors = true;
                        errorReporter("The parameter " + method.Parameters[token.Index].Name + " must be a param array in order to use it with the * modifier.");
                        substitutions[s] = Tuple.Create((JsExpression)JsExpression.ArrayLiteral(), true);
                    }
                    else if (!isParamArrayExpanded)
                    {
                        hasErrors = true;
                        errorReporter("The method " + method.DeclaringType.FullName + "." + method.Name + " can only be invoked with its params parameter expanded");
                        substitutions[s] = Tuple.Create((JsExpression)JsExpression.ArrayLiteral(), true);
                    }
                    else
                    {
                        substitutions[s] = Tuple.Create(arguments[token.Index], true);
                    }
                    break;
                }

                default:
                    throw new ArgumentException("Unknown token type " + token.Type);
                }
            }

            if (hasErrors)
            {
                return(JsExpression.Number(0));
            }

            try {
                var expr = JavaScriptParser.Parser.ParseExpression(text.ToString());
                return(new Substituter(substitutions, errorReporter).Process(expr));
            }
            catch (RecognitionException) {
                errorReporter("syntax error in inline code");
                return(JsExpression.Number(0));
            }
        }
Ejemplo n.º 27
0
 public MockRuntimeLibrary()
 {
     GetTypeOf       = (t, c) => GetScriptType(t, TypeContext.TypeOf, c.ResolveTypeParameter);
     InstantiateType = (t, c) => GetScriptType(t, TypeContext.UseStaticMember, c.ResolveTypeParameter);
     InstantiateTypeForUseAsTypeArgumentInInlineCode = (t, c) => GetScriptType(t, TypeContext.GenericArgument, c.ResolveTypeParameter);
     TypeIs                   = (e, s, t, c) => JsExpression.Invocation(JsExpression.Identifier("$TypeIs"), e, GetScriptType(t, TypeContext.CastTarget, c.ResolveTypeParameter));
     TryDowncast              = (e, s, d, c) => JsExpression.Invocation(JsExpression.Identifier("$TryCast"), e, GetScriptType(d, TypeContext.CastTarget, c.ResolveTypeParameter));
     Downcast                 = (e, s, d, c) => JsExpression.Invocation(JsExpression.Identifier("$Cast"), e, GetScriptType(d, TypeContext.CastTarget, c.ResolveTypeParameter));
     Upcast                   = (e, s, d, c) => JsExpression.Invocation(JsExpression.Identifier("$Upcast"), e, GetScriptType(d, TypeContext.CastTarget, c.ResolveTypeParameter));
     ReferenceEquals          = (a, b, c) => JsExpression.Invocation(JsExpression.Identifier("$ReferenceEquals"), a, b);
     ReferenceNotEquals       = (a, b, c) => JsExpression.Invocation(JsExpression.Identifier("$ReferenceNotEquals"), a, b);
     InstantiateGenericMethod = (m, a, c) => JsExpression.Invocation(JsExpression.Identifier("$InstantiateGenericMethod"), new[] { m }.Concat(a.Select(x => GetScriptType(x, TypeContext.GenericArgument, c.ResolveTypeParameter))));
     MakeException            = (e, c) => JsExpression.Invocation(JsExpression.Identifier("$MakeException"), e);
     IntegerDivision          = (n, d, c) => JsExpression.Invocation(JsExpression.Identifier("$IntDiv"), n, d);
     FloatToInt               = (e, c) => JsExpression.Invocation(JsExpression.Identifier("$Truncate"), e);
     Coalesce                 = (a, b, c) => JsExpression.Invocation(JsExpression.Identifier("$Coalesce"), a, b);
     Lift                            = (e, t, c) => JsExpression.Invocation(JsExpression.Identifier("$Lift"), e, JsExpression.Identifier(t.ToString()));
     FromNullable                    = (e, c) => JsExpression.Invocation(JsExpression.Identifier("$FromNullable"), e);
     LiftedBooleanAnd                = (a, b, c) => JsExpression.Invocation(JsExpression.Identifier("$LiftedBooleanAnd"), a, b);
     LiftedBooleanOr                 = (a, b, c) => JsExpression.Invocation(JsExpression.Identifier("$LiftedBooleanOr"), a, b);
     LiftedBooleanXor                = (a, b, c) => JsExpression.Invocation(JsExpression.Identifier("$LiftedBooleanXor"), a, b);
     Bind                            = (f, t, c) => JsExpression.Invocation(JsExpression.Identifier("$Bind"), f, t);
     BindFirstParameterToThis        = (f, c) => JsExpression.Invocation(JsExpression.Identifier("$BindFirstParameterToThis"), f);
     Default                         = (t, c) => t.Kind == TypeKind.Dynamic ? (JsExpression)JsExpression.Identifier("$DefaultDynamic") : JsExpression.Invocation(JsExpression.Identifier("$Default"), GetScriptType(t, TypeContext.GetDefaultValue, c.ResolveTypeParameter));
     CreateArray                     = (t, dim, c) => JsExpression.Invocation(JsExpression.Identifier("$CreateArray"), new[] { GetScriptType(t, TypeContext.GetDefaultValue, c.ResolveTypeParameter) }.Concat(dim));
     CloneDelegate                   = (e, s, t, c) => JsExpression.Invocation(JsExpression.Identifier("$CloneDelegate"), e);
     CallBase                        = (m, a, c) => JsExpression.Invocation(JsExpression.Identifier("$CallBase"), new[] { GetScriptType(m.DeclaringType, TypeContext.BindBaseCall, c.ResolveTypeParameter), JsExpression.String("$" + m.Name), JsExpression.ArrayLiteral(m is SpecializedMethod ? ((SpecializedMethod)m).TypeArguments.Select(x => GetScriptType(x, TypeContext.GenericArgument, c.ResolveTypeParameter)) : new JsExpression[0]), JsExpression.ArrayLiteral(a) });
     BindBaseCall                    = (m, a, c) => JsExpression.Invocation(JsExpression.Identifier("$BindBaseCall"), new[] { GetScriptType(m.DeclaringType, TypeContext.BindBaseCall, c.ResolveTypeParameter), JsExpression.String("$" + m.Name), JsExpression.ArrayLiteral(m is SpecializedMethod ? ((SpecializedMethod)m).TypeArguments.Select(x => GetScriptType(x, TypeContext.GenericArgument, c.ResolveTypeParameter)) : new JsExpression[0]), a });
     MakeEnumerator                  = (yt, mn, gc, d, c) => JsExpression.Invocation(JsExpression.Identifier("$MakeEnumerator"), new[] { GetScriptType(yt, TypeContext.GenericArgument, c.ResolveTypeParameter), mn, gc, d ?? JsExpression.Null });
     MakeEnumerable                  = (yt, ge, c) => JsExpression.Invocation(JsExpression.Identifier("$MakeEnumerable"), new[] { GetScriptType(yt, TypeContext.GenericArgument, c.ResolveTypeParameter), ge });
     GetMultiDimensionalArrayValue   = (a, i, c) => JsExpression.Invocation(JsExpression.Identifier("$MultidimArrayGet"), new[] { a }.Concat(i));
     SetMultiDimensionalArrayValue   = (a, i, v, c) => JsExpression.Invocation(JsExpression.Identifier("$MultidimArraySet"), new[] { a }.Concat(i).Concat(new[] { v }));
     CreateTaskCompletionSource      = (t, c) => JsExpression.Invocation(JsExpression.Identifier("$CreateTaskCompletionSource"), t != null ? GetScriptType(t, TypeContext.GenericArgument, c.ResolveTypeParameter) : JsExpression.String("non-generic"));
     SetAsyncResult                  = (t, v, c) => JsExpression.Invocation(JsExpression.Identifier("$SetAsyncResult"), t, v ?? JsExpression.String("<<null>>"));
     SetAsyncException               = (t, e, c) => JsExpression.Invocation(JsExpression.Identifier("$SetAsyncException"), t, e);
     GetTaskFromTaskCompletionSource = (t, c) => JsExpression.Invocation(JsExpression.Identifier("$GetTask"), t);
     ApplyConstructor                = (c, a, x) => JsExpression.Invocation(JsExpression.Identifier("$ApplyConstructor"), c, a);
     ShallowCopy                     = (s, t, c) => JsExpression.Invocation(JsExpression.Identifier("$ShallowCopy"), s, t);
     GetMember                       = (m, c) => JsExpression.Invocation(JsExpression.Identifier("$GetMember"), GetScriptType(m.DeclaringType, TypeContext.TypeOf, c.ResolveTypeParameter), JsExpression.String(m.Name));
     GetExpressionForLocal           = (n, a, t, c) => JsExpression.Invocation(JsExpression.Identifier("$Local"), JsExpression.String(n), GetScriptType(t, TypeContext.TypeOf, c.ResolveTypeParameter), a);
     CloneValueType                  = (v, t, c) => JsExpression.Invocation(JsExpression.Identifier("$Clone"), v, GetScriptType(t, TypeContext.TypeOf, c.ResolveTypeParameter));
     InitializeField                 = (t, n, m, v, c) => JsExpression.Invocation(JsExpression.Identifier("$Init"), t, JsExpression.String(n), v);
 }
 private JsFunctionDefinitionExpression CreateFunction(params ITypeDefinition[] referencedTypes)
 {
     return(JsExpression.FunctionDefinition(new string[0], JsExpression.ArrayLiteral(referencedTypes.Select(t => new JsTypeReferenceExpression(t)))));
 }
Ejemplo n.º 29
0
        private static JsExpression ConstructMemberInfo(IMember m, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, Func <IType, JsExpression> instantiateType, bool includeDeclaringType, MethodScriptSemantics semanticsIfAccessor)
        {
            if (m is IMethod && ((IMethod)m).IsConstructor)
            {
                return(ConstructConstructorInfo((IMethod)m, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType));
            }

            var properties = GetCommonMemberInfoProperties(m, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType);

            if (m.IsStatic)
            {
                properties.Add(new JsObjectLiteralProperty("isStatic", JsExpression.True));
            }

            if (m is IMethod)
            {
                var method = (IMethod)m;
                var sem    = semanticsIfAccessor ?? metadataImporter.GetMethodSemantics(method);
                if (sem.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.Type != MethodScriptSemantics.ImplType.InlineCode)
                {
                    errorReporter.Message(Messages._7201, m.FullName, "method");
                    return(JsExpression.Null);
                }
                if ((sem.Type == MethodScriptSemantics.ImplType.NormalMethod || sem.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) && sem.ExpandParams)
                {
                    properties.Add(new JsObjectLiteralProperty("exp", JsExpression.True));
                }

                properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)));
                if (sem.Type == MethodScriptSemantics.ImplType.InlineCode)
                {
                    var usedNames  = new HashSet <string>();
                    var parameters = new List <IVariable>();
                    var variables  = new Dictionary <IVariable, VariableData>();
                    var arguments  = new List <ResolveResult>();
                    foreach (var p in method.Parameters)
                    {
                        string name = namer.GetVariableName(p.Name, usedNames);
                        usedNames.Add(name);
                        var variable = new SimpleVariable(p.Type, p.Name, DomRegion.Empty);
                        parameters.Add(variable);
                        variables.Add(variable, new VariableData(name, null, false));
                        arguments.Add(new LocalResolveResult(variable));
                    }
                    var tokens = InlineCodeMethodCompiler.Tokenize(method, sem.LiteralCode, _ => {});

                    var compileResult = Compile(CreateMethodInvocationResolveResult(method, method.IsStatic ? (ResolveResult) new TypeResolveResult(method.DeclaringType) : new ThisResolveResult(method.DeclaringType), arguments), method.DeclaringTypeDefinition, method, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, true, variables, usedNames);
                    var definition    = JsExpression.FunctionDefinition(parameters.Select(p => variables[p].Name), JsStatement.Block(compileResult.AdditionalStatements.Concat(new[] { JsStatement.Return(compileResult.Expression) })));

                    if (tokens.Any(t => t.Type == InlineCodeToken.TokenType.TypeParameter && t.OwnerType == SymbolKind.Method))
                    {
                        definition = JsExpression.FunctionDefinition(method.TypeParameters.Select(namer.GetTypeParameterName), JsStatement.Return(definition));
                        properties.Add(new JsObjectLiteralProperty("tpcount", JsExpression.Number(method.TypeParameters.Count)));
                    }
                    properties.Add(new JsObjectLiteralProperty("def", definition));
                }
                else
                {
                    if (IsJsGeneric(method, metadataImporter))
                    {
                        properties.Add(new JsObjectLiteralProperty("tpcount", JsExpression.Number(method.TypeParameters.Count)));
                    }
                    if (sem.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument)
                    {
                        properties.Add(new JsObjectLiteralProperty("sm", JsExpression.True));
                    }
                    properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name)));
                }
                properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(method.ReturnType)));
                properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(method.Parameters.Select(p => instantiateType(p.Type)))));
            }
            else if (m is IField)
            {
                var field = (IField)m;
                var sem   = metadataImporter.GetFieldSemantics(field);
                if (sem.Type != FieldScriptSemantics.ImplType.Field)
                {
                    errorReporter.Message(Messages._7201, m.FullName, "field");
                    return(JsExpression.Null);
                }
                properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Field)));
                properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(field.ReturnType)));
                properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name)));
            }
            else if (m is IProperty)
            {
                var prop = (IProperty)m;
                var sem  = metadataImporter.GetPropertySemantics(prop);
                properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Property)));
                properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(prop.ReturnType)));
                if (prop.Parameters.Count > 0)
                {
                    properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(prop.Parameters.Select(p => instantiateType(p.Type)))));
                }

                switch (sem.Type)
                {
                case PropertyScriptSemantics.ImplType.GetAndSetMethods:
                    if (sem.GetMethod != null && sem.GetMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.GetMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.GetMethod.Type != MethodScriptSemantics.ImplType.InlineCode)
                    {
                        errorReporter.Message(Messages._7202, m.FullName, "property", "getter");
                        return(JsExpression.Null);
                    }
                    if (sem.SetMethod != null && sem.SetMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.SetMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.SetMethod.Type != MethodScriptSemantics.ImplType.InlineCode)
                    {
                        errorReporter.Message(Messages._7202, m.FullName, "property", "setter");
                        return(JsExpression.Null);
                    }
                    if (sem.GetMethod != null)
                    {
                        properties.Add(new JsObjectLiteralProperty("getter", ConstructMemberInfo(prop.Getter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.GetMethod)));
                    }
                    if (sem.SetMethod != null)
                    {
                        properties.Add(new JsObjectLiteralProperty("setter", ConstructMemberInfo(prop.Setter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.SetMethod)));
                    }
                    break;

                case PropertyScriptSemantics.ImplType.Field:
                    if (prop.CanGet)
                    {
                        properties.Add(new JsObjectLiteralProperty("getter", ConstructFieldPropertyAccessor(prop.Getter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, sem.FieldName, instantiateType, isGetter: true, includeDeclaringType: includeDeclaringType)));
                    }
                    if (prop.CanSet)
                    {
                        properties.Add(new JsObjectLiteralProperty("setter", ConstructFieldPropertyAccessor(prop.Setter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, sem.FieldName, instantiateType, isGetter: false, includeDeclaringType: includeDeclaringType)));
                    }
                    properties.Add(new JsObjectLiteralProperty("fname", JsExpression.String(sem.FieldName)));
                    break;

                default:
                    errorReporter.Message(Messages._7201, m.FullName, "property");
                    return(JsExpression.Null);
                }
            }
            else if (m is IEvent)
            {
                var evt = (IEvent)m;
                var sem = metadataImporter.GetEventSemantics(evt);
                if (sem.Type != EventScriptSemantics.ImplType.AddAndRemoveMethods)
                {
                    errorReporter.Message(Messages._7201, m.FullName, "event");
                    return(JsExpression.Null);
                }
                if (sem.AddMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.AddMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.AddMethod.Type != MethodScriptSemantics.ImplType.InlineCode)
                {
                    errorReporter.Message(Messages._7202, m.FullName, "event", "add accessor");
                    return(JsExpression.Null);
                }
                if (sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.InlineCode)
                {
                    errorReporter.Message(Messages._7202, m.FullName, "event", "remove accessor");
                    return(JsExpression.Null);
                }

                properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Event)));
                properties.Add(new JsObjectLiteralProperty("adder", ConstructMemberInfo(evt.AddAccessor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.AddMethod)));
                properties.Add(new JsObjectLiteralProperty("remover", ConstructMemberInfo(evt.RemoveAccessor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.RemoveMethod)));
            }
            else
            {
                throw new ArgumentException("Invalid member " + m);
            }

            return(JsExpression.ObjectLiteral(properties));
        }
        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))))));
                }
            }
        }