Пример #1
0
 protected Assembly(string fullName, JsArray types, Attribute[] attributes)
 {
     this.fullName = fullName;
     this.attributes = attributes;
     typeFunctions = new JsTypeFunction[types.length];
     for (var i = 0; i < types.length; i++)
     {
         typeFunctions[i] = types[i].As<JsTypeFunction>();
         typesByName[typeFunctions[i].TypeName] = typeFunctions[i];
         typesByNameUpper[typeFunctions[i].TypeName.ToUpper()] = typeFunctions[i];
     }
 }
Пример #2
0
 public static extern JsObject apply <T>(Action <T> method, JsObject thisReference, JsArray arguments);
Пример #3
0
 public static extern JsObject apply(this JsObject target, JsObject thisReference, JsArray arguments);
Пример #4
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>());
        }
Пример #5
0
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        {
            if (IsStatic && obj != null)
                throw new InvalidOperationException("Static methods cannot have a target");
            if (!IsStatic && obj == null)
                throw new InvalidOperationException("Instance methods must have a target");

            var args = new JsArray();
            if (typeArguments != null)
            {
                foreach (var typeArgument in typeArguments)
                    args.push(typeArgument.thisType);
            }
            if (parameters != null)
            {
                var parametersArray = parameters.As<JsArray>();
                for (var i = 0; i < parametersArray.length; i++)
                {
                    var argument = parametersArray[i].As<JsObject>();
                    args.push(argument.As<JsObject>());
                }
            }
            var target = IsStatic ? DeclaringType.thisType : obj;
            return Jsni.apply(jsMethod, target.As<JsObject>(), args);
        }
Пример #6
0
        public static JsTypeFunction Define(JsFunction assembly, JsTypeFunction enclosingType, string name, bool isGenericType, JsArray typeParameters, JsObject prototype, JsFunction typeInitializer)
        {
            JsTypeFunction typeFunction      = null;
            var            isTypeInitialized = false;

            // Create constructor function, which is a superconstructor that takes in the actual
            // constructor as the first argument, and the rest of the arguments are passed directly
            // to that constructor.  These subconstructors are not Javascript constructors -- they
            // are not called via new, they exist for initialization only.
            typeFunction = Jsni.function((constructor, args) =>
            {
                if (constructor != null || !(Jsni.instanceof(Jsni.@this(), typeFunction)))
                {
                    if (!isGenericType || typeFunction.UnconstructedType != null)
                    {
                        typeFunction.member(SpecialNames.StaticInitializer).invoke();
                    }
                }
                if (constructor != null)
                {
                    constructor.apply(Jsni.@this(), args.As <JsArray>());
                }
                if (!Jsni.instanceof(Jsni.@this(), typeFunction))
                {
                    return(typeFunction);
                }
                else
                {
                    return(Jsni.@this());
                }
            }).As <JsTypeFunction>();
            typeFunction.GetAssembly = assembly;
            assembly.member(SpecialNames.AssemblyTypesArray).member("push").invoke(typeFunction);
            typeFunction.memberset("toString", Jsni.function(() => name.As <JsObject>()));
            typeFunction.EnclosingType          = enclosingType;
            typeFunction.TypeName               = name;
            typeFunction.prototype              = Jsni.@new(prototype);
            typeFunction.IsPrototypeInitialized = false;
            typeFunction.TypeInitializer        = Jsni.procedure((_t, p) =>
            {
                var t = _t.As <JsTypeFunction>();
                if (isGenericType)
                {
                    var unconstructedType = t.UnconstructedType ?? t;
                    t.GenericTypeFunction = Jsni.function(() =>
                    {
                        return(Jsni.reference(SpecialNames.MakeGenericTypeConstructor).As <JsFunction>().call(unconstructedType, unconstructedType, Jsni.arguments()).As <JsFunction>().invoke());
                    });
                }
                t.GetTypeFromType = Jsni.function(() =>
                {
                    return(Type._GetTypeFromTypeFunc(Jsni.@this().As <JsTypeFunction>()).As <JsObject>());
                });
                p.memberset(SpecialNames.TypeName, t.member(SpecialNames.TypeName));
                p.___type  = t;
                t.BaseType = prototype.As <JsTypeFunction>();

                typeInitializer.apply(Jsni.@this(), Jsni.arguments().As <JsArray>());
            });
            typeFunction.CallTypeInitializer = Jsni.procedure(() =>
            {
                typeFunction.TypeInitializer.apply(enclosingType, Jsni.array(typeFunction, typeFunction.prototype).concat(typeParameters));
            });
            return(typeFunction);
        }
Пример #7
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>());
        }