示例#1
0
        internal static JsTypeFunction MakeGenericTypeFactory(JsTypeFunction unconstructedType, JsArray typeArgs)
        {
            var cache = Jsni.member(unconstructedType, SpecialNames.TypeCache);

            if (cache == null)
            {
                cache = new JsObject();
                unconstructedType.memberset(SpecialNames.TypeCache, cache);
            }
            var keyArray = Jsni.call <JsArray>(x => x.slice(0), typeArgs, 0.As < JsNumber > ()).As <JsArray>();
            var keyParts = new JsArray();

            for (var i = 0; i < keyArray.length; i++)
            {
                keyParts[i] = keyArray[i].member(SpecialNames.TypeName);
            }
            var keyString = keyParts.join(", ");
            var result    = cache[keyString];

            if (result == null)
            {
                var lastIndexOfDollar = unconstructedType.TypeName.LastIndexOf('`');
                var newTypeName       = unconstructedType.TypeName.Substring(0, lastIndexOfDollar) + "<" + keyString + ">";
                var prototype         = unconstructedType.BaseType;
                if (prototype.member("$"))
                {
                    prototype = prototype.member("$").apply(null, typeArgs).As <JsTypeFunction>();
                }
                var generic = Define(newTypeName, prototype);
                generic.memberset(SpecialNames.UnconstructedType, unconstructedType);

                // unconstructedType.$TypeInitializer.apply(this, [generic, generic.prototype].concat(Array.prototype.slice.call(arguments, 0)));
                Jsni.apply(
                    Jsni.member(unconstructedType, SpecialNames.TypeInitializer),
                    unconstructedType,
                    Jsni.invoke(
                        Jsni.member(Jsni.array(generic, generic.prototype), "concat"),
                        keyArray
                        ).As <JsArray>());

                generic.TypeInitializer = Jsni.procedure((t, p) =>
                {
                    p.___type = generic;
                    t.As <JsTypeFunction>().BaseType        = unconstructedType;
                    t.As <JsTypeFunction>().GetTypeFromType = Jsni.function(() => Type._GetTypeFromTypeFunc(Jsni.@this().As <JsTypeFunction>()).As <JsObject>());
                    t.As <JsTypeFunction>().TypeName        = newTypeName;
                    t.As <JsTypeFunction>().CreateTypeField = Jsni.function(() =>
                    {
                        var unconstructedTypeType = Type._GetTypeFromTypeFunc(unconstructedType);
                        var type      = new Type(newTypeName, new Attribute[0]);
                        generic.Type  = type;
                        type.thisType = generic;

                        var typeParameters = unconstructedTypeType.typeArguments;
                        var typeArguments  = InitializeArray(typeArgs, Jsni.type <JsTypeFunction>()).As <JsTypeFunction[]>();

                        Func <Type, JsTypeFunction> reifyGenerics = null;
                        reifyGenerics = theType =>
                        {
                            if (theType == null)
                            {
                                return(null);
                            }
                            if (theType.IsArray)
                            {
                                var elementType = theType.GetElementType();
                                var arrayType   = MakeArrayType(reifyGenerics(elementType));
                                return(arrayType);
                            }
                            if (theType.IsGenericParameter)
                            {
                                for (int i = 0; i < typeArguments.Length; i++)
                                {
                                    var typeParameter = typeParameters[i];
                                    var typeArgument  = typeArguments[i];
                                    if (typeParameter.TypeName == theType.FullName)
                                    {
                                        return(typeArgument);
                                    }
                                }
                            }
                            else if (theType.IsGenericTypeDefinition)
                            {
                                return(MakeGenericTypeFactory(theType.thisType, theType.GenericTypeArguments.Select(x => reifyGenerics(x)).ToArray().As <JsArray>()));
                            }
                            else if (theType.IsGenericType)
                            {
                                JsTypeFunction[] newTypeArguments = null;
                                for (var i = 0; i < theType.typeArguments.Length; i++)
                                {
                                    var theTypeArgument = theType.typeArguments[i];
                                    for (var j = 0; j < typeParameters.Length; j++)
                                    {
                                        var typeParameter = typeParameters[j];
                                        var typeArgument  = typeArguments[j];
                                        if (theTypeArgument == typeParameter)
                                        {
                                            if (newTypeArguments == null)
                                            {
                                                newTypeArguments = new JsTypeFunction[theType.typeArguments.Length];
                                                for (var k = 0; k < theType.typeArguments.Length; k++)
                                                {
                                                    newTypeArguments[k] = theType.typeArguments[k];
                                                }
                                            }
                                            newTypeArguments[i] = typeArgument;
                                        }
                                    }
                                }
                                if (newTypeArguments != null)
                                {
                                    return(MakeGenericTypeFactory(theType.unconstructedType, newTypeArguments.As <JsArray>()));
                                }
                                else
                                {
                                    return(theType.thisType);
                                }
                            }
                            return(theType.thisType);
                        };

                        var newInterfaces = unconstructedTypeType.interfaces.ToArray();
                        for (var i = 0; i < newInterfaces.Length; i++)
                        {
                            var intf         = newInterfaces[i];
                            intf             = reifyGenerics(Type._GetTypeFromTypeFunc(intf));
                            newInterfaces[i] = intf;
                        }

                        var newConstructors = unconstructedTypeType.constructors.ToArray();
                        for (var i = 0; i < newConstructors.Length; i++)
                        {
                            var constructor = newConstructors[i];
                            var parameters  = constructor.GetParameters();
                            for (var j = 0; j < parameters.Length; j++)
                            {
                                var parameter     = parameters[j];
                                var parameterType = reifyGenerics(parameter.ParameterType);
                                parameter         = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes);
                                parameters[j]     = parameter;
                            }
                            newConstructors[i] = new ConstructorInfo(constructor.Name, generic.prototype[constructor.Name].As <JsFunction>(), parameters, constructor.Attributes, constructor.attributes);
                        }

                        var newProperties = unconstructedTypeType.properties.ToArray();
                        for (var i = 0; i < newProperties.Length; i++)
                        {
                            var property         = newProperties[i];
                            var propertyTypeType = property.PropertyType;
                            var propertyType     = reifyGenerics(propertyTypeType);
                            newProperties[i]     = new PropertyInfo(property.Name, propertyType, property.GetGetMethod(), property.GetSetMethod(),
                                                                    property.GetIndexParameters(), property.attributes);
                        }

                        var newMethods = unconstructedTypeType.methods.ToArray();
                        for (var i = 0; i < newMethods.Length; i++)
                        {
                            var method         = newMethods[i];
                            var returnTypeType = method.ReturnType;
                            var returnType     = reifyGenerics(returnTypeType);
                            var parameters     = method.GetParameters();
                            for (var j = 0; j < parameters.Length; j++)
                            {
                                var parameter     = parameters[j];
                                var parameterType = reifyGenerics(parameter.ParameterType);
                                parameter         = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes);
                                parameters[j]     = parameter;
                            }
                            method        = new MethodInfo(method.Name, method.jsMethod, parameters, returnType, method.Attributes, method.attributes);
                            newMethods[i] = method;
                        }

                        type.Init(
                            newTypeName,
                            unconstructedTypeType.typeAttributes,
                            generic,
                            unconstructedType.BaseType,
                            newInterfaces,
                            typeArguments,
                            unconstructedTypeType.fields,
                            newMethods,
                            newConstructors,
                            newProperties,
                            unconstructedTypeType.events,
                            false,
                            unconstructedTypeType.IsAbstract,
                            unconstructedTypeType.IsInterface,
                            false,
                            true,
                            false,
                            unconstructedTypeType.IsEnum,
                            null,
                            unconstructedType);
                        return(type.As <JsObject>());
                    });
                }, SpecialNames.TypeInitializerTypeFunction, SpecialNames.TypeInitializerPrototype);
                Jsni.call(generic.TypeInitializer, Jsni.@this(), generic, generic.prototype);
                result           = generic;
                cache[keyString] = result;
            }

            return(result.As <JsTypeFunction>());
        }
示例#2
0
        internal static JsTypeFunction MakeGenericTypeFactory(JsTypeFunction unconstructedType, JsArray typeArgs)
        {
            var cache = Jsni.member(unconstructedType, SpecialNames.TypeCache);

            if (cache == null)
            {
                cache = new JsObject();
                unconstructedType.memberset(SpecialNames.TypeCache, cache);
            }
            var keyArray = Jsni.call <JsArray>(x => x.slice(0), typeArgs, 0.As < JsNumber > ()).As <JsArray>();
            var keyParts = new JsArray();

            for (var i = 0; i < keyArray.length; i++)
            {
                keyParts[i] = keyArray[i].member(SpecialNames.TypeName);
            }
            var keyString = keyParts.join(", ");
            var result    = cache[keyString];

            if (result == null)
            {
                var lastIndexOfDollar = unconstructedType.TypeName.LastIndexOf('`');
                var newTypeName       = unconstructedType.TypeName.Substring(0, lastIndexOfDollar) + "<" + keyString + ">";
                var prototype         = unconstructedType.BaseType;
                if (prototype.member("$"))
                {
                    prototype = prototype.member("$").apply(null, typeArgs).As <JsTypeFunction>();
                }
                var generic = Define(newTypeName, prototype);
                generic.memberset(SpecialNames.UnconstructedType, unconstructedType);

                // unconstructedType.$TypeInitializer.apply(this, [generic, generic.prototype].concat(Array.prototype.slice.call(arguments, 0)));
                Jsni.apply(
                    Jsni.member(unconstructedType, SpecialNames.TypeInitializer),
                    unconstructedType,
                    Jsni.invoke(
                        Jsni.member(Jsni.array(generic, generic.prototype), "concat"),
                        keyArray
                        ).As <JsArray>());

                generic.TypeInitializer = Jsni.procedure((t, p) =>
                {
                    p.___type = generic;
                    t.As <JsTypeFunction>().BaseType        = unconstructedType;
                    t.As <JsTypeFunction>().GetTypeFromType = Jsni.function(() => Type._GetTypeFromTypeFunc(Jsni.@this().As <JsTypeFunction>()).As <JsObject>());
                    t.As <JsTypeFunction>().CreateTypeField = Jsni.function(() =>
                    {
                        var unconstructedTypeType = Type._GetTypeFromTypeFunc(unconstructedType);
                        var type     = new Type(newTypeName, new Attribute[0]);
                        generic.Type = type;
                        type.Init(
                            newTypeName,
                            unconstructedTypeType.typeAttributes,
                            generic,
                            unconstructedType.BaseType,
                            unconstructedTypeType.interfaces,
                            InitializeArray(typeArgs, Jsni.type <JsTypeFunction>()).As <JsTypeFunction[]>(),
                            unconstructedTypeType.fields,
                            unconstructedTypeType.methods,
                            unconstructedTypeType.constructors,
                            unconstructedTypeType.properties,
                            unconstructedTypeType.events,
                            false,
                            false,
                            true,
                            false,
                            null,
                            unconstructedType);
                        return(type.As <JsObject>());
                    });
                }, SpecialNames.TypeInitializerTypeFunction, SpecialNames.TypeInitializerPrototype);
                Jsni.call(generic.TypeInitializer, Jsni.@this(), generic, generic.prototype);
                result           = generic;
                cache[keyString] = result;
            }

            return(result.As <JsTypeFunction>());
        }
示例#3
0
        internal static JsTypeFunction MakeGenericTypeFactory(JsTypeFunction unconstructedType, JsArray typeArgs)
        {
            var      cache  = Jsni.member(unconstructedType, SpecialNames.TypeCache);
            JsObject result = null;

            if (typeArgs.length > 0)
            {
                if (cache == null)
                {
                    cache = new JsObject();
                    unconstructedType.memberset(SpecialNames.TypeCache, cache);
                }

                JsObject currentCache = cache;
                for (var i = 0; i < typeArgs.length - 1; i++)
                {
                    var nextCache = currentCache[typeArgs[i].member(SpecialNames.TypeName)];
                    if (nextCache == null)
                    {
                        nextCache = new JsObject();
                        currentCache[typeArgs[i].member(SpecialNames.TypeName)] = nextCache;
                    }
                    currentCache = nextCache;
                }
                cache  = currentCache;
                result = cache[typeArgs[typeArgs.length - 1].member(SpecialNames.TypeName)];
            }
            else
            {
                result = cache;
            }

//            JsObject keyString;

            // First two if statements are optimizations for performance reasons to avoid heap allocation when possible.

/*
 *          if (typeArgs.length == 0)
 *              keyString = "";
 *          else if (typeArgs.length == 1)
 *              keyString = typeArgs[0].member(SpecialNames.TypeName);
 *          else
 *          {
 *              var keyArray = Jsni.call<JsArray>(x => x.slice(0), typeArgs, 0.As<JsNumber>()).As<JsArray>();
 *              var keyParts = new JsArray();
 *              for (var i = 0; i < keyArray.length; i++)
 *              {
 *                  keyParts[i] = keyArray[i].member(SpecialNames.TypeName);
 *              }
 *              keyString = keyParts.join(", ");
 *          }
 *
 *          var result = cache[keyString];
 */
            if (result == null)
            {
                var keyArray = Jsni.call <JsArray>(x => x.slice(0), typeArgs, 0.As < JsNumber > ()).As <JsArray>();
                var keyParts = new JsArray();
                for (var i = 0; i < keyArray.length; i++)
                {
                    keyParts[i] = keyArray[i].member(SpecialNames.TypeName);
                }
                var keyString = keyParts.join(", ");

                var lastIndexOfDollar = unconstructedType.TypeName.LastIndexOf('`');
                if (lastIndexOfDollar == -1)
                {
                    lastIndexOfDollar = unconstructedType.TypeName.Length;
                }
                var newTypeName = unconstructedType.TypeName.Substring(0, lastIndexOfDollar) + "<" + keyString + ">";
                var prototype   = unconstructedType.BaseType;
                if (prototype.member("$"))
                {
                    var baseArgs = unconstructedType.BaseTypeArgs.slice(0);
                    for (var i = 0; i < baseArgs.length; i++)
                    {
                        var baseArg = (JsTypeFunction)baseArgs[i];
                        if (baseArg.IsTypeParameter)
                        {
                            for (var j = 0; j < unconstructedType.TypeArgs.length; j++)
                            {
                                var typeArg = unconstructedType.TypeArgs[j];
                                if (typeArg == baseArg)
                                {
                                    baseArgs[i] = typeArgs[j];
                                }
                            }
                        }
                    }
                    prototype = prototype.member("$").apply(null, baseArgs).As <JsTypeFunction>();
                }
                var typeInitializer = Jsni.procedure((_t, p) =>
                {
                    var t     = _t.As <JsTypeFunction>();
                    p.___type = t;
                    t.As <JsTypeFunction>().BaseType        = unconstructedType;
                    t.As <JsTypeFunction>().GetTypeFromType = Jsni.function(() => Type._GetTypeFromTypeFunc(Jsni.@this().As <JsTypeFunction>()).As <JsObject>());
                    t.As <JsTypeFunction>().TypeName        = newTypeName;
                    t.As <JsTypeFunction>().CreateTypeField = Jsni.function(() =>
                    {
                        var unconstructedTypeType = Type._GetTypeFromTypeFunc(unconstructedType);
                        var type      = new Type(newTypeName, new Attribute[0]);
                        t.Type        = type;
                        type.thisType = t;

                        var typeParameters = unconstructedTypeType.typeArguments;
                        var typeArguments  = InitializeArray(typeArgs, Jsni.type <JsTypeFunction>()).As <JsTypeFunction[]>();

                        Func <Type, JsTypeFunction> reifyGenerics = null;
                        reifyGenerics = theType =>
                        {
                            if (theType == null)
                            {
                                return(null);
                            }
                            if (theType.IsArray)
                            {
                                var elementType = theType.GetElementType();
                                var arrayType   = MakeArrayType(reifyGenerics(elementType));
                                return(arrayType);
                            }
                            if (theType.IsGenericParameter)
                            {
                                for (int i = 0; i < typeArguments.Length; i++)
                                {
                                    var typeParameter = typeParameters[i];
                                    var typeArgument  = typeArguments[i];
                                    if (typeParameter.TypeName == theType.FullName)
                                    {
                                        return(typeArgument);
                                    }
                                }
                            }
                            else if (theType.IsGenericTypeDefinition)
                            {
                                return(MakeGenericTypeFactory(theType.thisType, theType.GenericTypeArguments.Select(x => reifyGenerics(x)).ToArray().As <JsArray>()));
                            }
                            else if (theType.IsGenericType)
                            {
                                JsTypeFunction[] newTypeArguments = null;
                                for (var i = 0; i < theType.typeArguments.Length; i++)
                                {
                                    var theTypeArgument = theType.typeArguments[i];
                                    for (var j = 0; j < typeParameters.Length; j++)
                                    {
                                        var typeParameter = typeParameters[j];
                                        var typeArgument  = typeArguments[j];
                                        if (theTypeArgument == typeParameter)
                                        {
                                            if (newTypeArguments == null)
                                            {
                                                newTypeArguments = new JsTypeFunction[theType.typeArguments.Length];
                                                for (var k = 0; k < theType.typeArguments.Length; k++)
                                                {
                                                    newTypeArguments[k] = theType.typeArguments[k];
                                                }
                                            }
                                            newTypeArguments[i] = typeArgument;
                                        }
                                    }
                                }
                                if (newTypeArguments != null)
                                {
                                    return(MakeGenericTypeFactory(theType.unconstructedType, newTypeArguments.As <JsArray>()));
                                }
                                else
                                {
                                    return(theType.thisType);
                                }
                            }
                            return(theType.thisType);
                        };

                        var newInterfaces = unconstructedTypeType.interfaces.ToArray();
                        for (var i = 0; i < newInterfaces.Length; i++)
                        {
                            var intf         = newInterfaces[i];
                            intf             = reifyGenerics(Type._GetTypeFromTypeFunc(intf));
                            newInterfaces[i] = intf;
                        }

                        var newConstructors = unconstructedTypeType.constructors.ToArray();
                        for (var i = 0; i < newConstructors.Length; i++)
                        {
                            var constructor = newConstructors[i];
                            var parameters  = constructor.GetParameters();
                            for (var j = 0; j < parameters.Length; j++)
                            {
                                var parameter     = parameters[j];
                                var parameterType = reifyGenerics(parameter.ParameterType);
                                parameter         = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes);
                                parameters[j]     = parameter;
                            }
                            newConstructors[i] = new ConstructorInfo(constructor.Name, t.prototype[constructor.Name].As <JsFunction>(), parameters, constructor.Attributes, constructor.attributes);
                        }

                        var newProperties = unconstructedTypeType.properties.ToArray();
                        for (var i = 0; i < newProperties.Length; i++)
                        {
                            var property         = newProperties[i];
                            var propertyTypeType = property.PropertyType;
                            var propertyType     = reifyGenerics(propertyTypeType);
                            newProperties[i]     = new PropertyInfo(property.Name, propertyType, property.GetGetMethod(), property.GetSetMethod(),
                                                                    property.GetIndexParameters(), property.attributes);
                        }

                        var newMethods = unconstructedTypeType.methods.ToArray();
                        for (var i = 0; i < newMethods.Length; i++)
                        {
                            var method         = newMethods[i];
                            var returnTypeType = method.ReturnType;
                            var returnType     = reifyGenerics(returnTypeType);
                            var parameters     = method.GetParameters();
                            for (var j = 0; j < parameters.Length; j++)
                            {
                                var parameter     = parameters[j];
                                var parameterType = reifyGenerics(parameter.ParameterType);
                                parameter         = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes);
                                parameters[j]     = parameter;
                            }
                            method        = new MethodInfo(method.Name, method.jsMethod, parameters, returnType, method.Attributes, method.attributes);
                            newMethods[i] = method;
                        }

                        type.Init(
                            newTypeName,
                            (int)((unconstructedTypeType.typeFlags | TypeFlags.GenericType) & ~TypeFlags.GenericTypeDefenition),
                            t,
                            prototype,
                            newInterfaces,
                            typeArguments,
                            unconstructedTypeType.fields,
                            newMethods,
                            newConstructors,
                            newProperties,
                            unconstructedTypeType.events,
                            null,
                            unconstructedType);
                        return(type.As <JsObject>());
                    });
                }, SpecialNames.TypeInitializerTypeFunction, SpecialNames.TypeInitializerPrototype);

                var generic = Define(unconstructedType.GetAssembly, unconstructedType.EnclosingType, newTypeName, true, Jsni.array(), prototype, typeInitializer);
                generic.memberset(SpecialNames.UnconstructedType, unconstructedType);

                // unconstructedType.$TypeInitializer.apply(this, [generic, generic.prototype].concat(Array.prototype.slice.call(arguments, 0)));
                unconstructedType.member(SpecialNames.TypeInitializer).apply(
                    unconstructedType,
                    Jsni.array(generic, generic.prototype).member("concat").invoke(keyArray).As <JsArray>()
                    );

                Jsni.call(generic.TypeInitializer, Jsni.@this(), generic, generic.prototype);
                result = generic;

                if (typeArgs.length == 0)
                {
                    unconstructedType.memberset(SpecialNames.TypeCache, result);
                }
                else
                {
                    cache[typeArgs[typeArgs.length - 1].member(SpecialNames.TypeName)] = result;
                }
            }

            return(result.As <JsTypeFunction>());
        }