private static void DefineMethod(TypeBuilder proxyTB, IPersistentVector sig)
        {
            Symbol mname = (Symbol)sig.nth(0);

            Type[] paramTypes = GenClass.CreateTypeArray((ISeq)sig.nth(1));
            Type   retType    = (Type)sig.nth(2);
            ISeq   pmetas     = (ISeq)(sig.count() >= 4 ? sig.nth(3) : null);

            MethodBuilder mb = proxyTB.DefineMethod(mname.Name, MethodAttributes.Abstract | MethodAttributes.Public | MethodAttributes.Virtual, retType, paramTypes);

            SetCustomAttributes(mb, GenInterface.ExtractAttributes(RT.meta(mname)));
            int i = 1;

            for (ISeq s = pmetas; s != null; s = s.next(), i++)
            {
                IPersistentMap meta = GenInterface.ExtractAttributes((IPersistentMap)s.first());
                if (meta != null && meta.count() > 0)
                {
                    ParameterBuilder pb = mb.DefineParameter(i, ParameterAttributes.None, String.Format("p_{0}", i));
                    GenInterface.SetCustomAttributes(pb, meta);
                }
            }
        }
Example #2
0
        Type Generate(Type superclass, ISeq interfaces, IPersistentMap attributes, string className)
        {
            // define the class
            List <Type> interfaceTypes = new List <Type>
            {
                typeof(IProxy)
            };

            for (ISeq s = interfaces; s != null; s = s.next())
            {
                interfaceTypes.Add((Type)s.first());
            }

            TypeBuilder proxyTB = _context.ModuleBuilder.DefineType(
                className,
                TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed,
                superclass,
                interfaceTypes.ToArray());

            GenInterface.SetCustomAttributes(proxyTB, attributes);

            DefineCtors(proxyTB, superclass);
            MaybeImplementISerializable(proxyTB, interfaceTypes);
            FieldBuilder mapField = AddIProxyMethods(proxyTB);

            HashSet <Type>          allInterfaces  = GetAllInterfaces(interfaces);
            HashSet <MethodBuilder> specialMethods = new HashSet <MethodBuilder>();

            AddInterfaceMethods(proxyTB, mapField, superclass, allInterfaces, specialMethods);
            AddInterfaceProperties(proxyTB, superclass, allInterfaces, specialMethods);  // Must follow AddInterfaceMethods

            Type t = proxyTB.CreateType();

            //if (Compiler.IsCompiling)
            //    SaveProxyContext();
            return(t);
        }
Example #3
0
        public static Type GenerateClass(string className,
                                         Type superclass,
                                         ISeq interfaces, // of Types
                                         ISeq ctors,
                                         ISeq ctorTypes,
                                         ISeq methods,
                                         IPersistentMap exposesFields,
                                         IPersistentMap exposesMethods,
                                         string prefix,
                                         bool hasMain,
                                         string factoryName,
                                         string stateName,
                                         string initName,
                                         string postInitName,
                                         string implCname,
                                         string implNamespace,
                                         bool loadImplNamespace,
                                         IPersistentMap attributes)
        {
            className = className.Replace('-', '_');

            string path = (string)Compiler.CompilePathVar.deref();

            if (path == null)
            {
                throw new InvalidOperationException("*compile-path* not set");
            }

            string extension = hasMain ? ".exe" : ".dll";


            GenContext context = GenContext.CreateWithExternalAssembly(Compiler.munge(className), extension, true);

            // define the class
            List <Type> interfaceTypes = new List <Type>();

            for (ISeq s = interfaces; s != null; s = s.next())
            {
                interfaceTypes.Add((Type)s.first());
            }


            TypeBuilder proxyTB = context.ModuleBuilder.DefineType(
                className,
                TypeAttributes.Class | TypeAttributes.Public,
                superclass,
                interfaceTypes.ToArray());

            GenInterface.SetCustomAttributes(proxyTB, attributes);

            List <MethodSignature> sigs = GetAllSignatures(superclass, interfaceTypes, methods);
            Dictionary <string, List <MethodSignature> > overloads = ComputeOverloads(sigs);

            HashSet <string> varNames = ComputeOverloadNames(overloads);

            foreach (MethodSignature sig in sigs)
            {
                varNames.Add(sig.Name);
            }

            if (!String.IsNullOrEmpty(initName))
            {
                varNames.Add(initName);
            }
            if (!String.IsNullOrEmpty(postInitName))
            {
                varNames.Add(postInitName);
            }
            if (hasMain)
            {
                varNames.Add(_mainName);
            }

            Dictionary <string, FieldBuilder> varMap = DefineStaticFields(proxyTB, varNames);

            FieldBuilder stateFB = String.IsNullOrEmpty(stateName) ? null : DefineStateField(proxyTB, stateName);

            DefineStaticCtor(proxyTB, prefix, varMap, loadImplNamespace, implNamespace, implCname);

            varMap.TryGetValue(initName, out FieldBuilder initFB);
            varMap.TryGetValue(postInitName, out FieldBuilder postInitFB);
            varMap.TryGetValue(_mainName, out FieldBuilder mainFB);

            DefineCtors(proxyTB, superclass,
                        implNamespace + "." + prefix + initName,
                        implNamespace + "." + prefix + postInitName,
                        ctors, ctorTypes, initFB, postInitFB, stateFB, factoryName);

            EmitMethods(proxyTB, sigs, overloads, varMap, exposesMethods);
            EmitExposers(proxyTB, superclass, exposesFields);

            if (hasMain)
            {
                EmitMain(context, proxyTB, implNamespace + "." + prefix + _mainName, mainFB);
            }

            Type t = proxyTB.CreateType();

            context.SaveAssembly();

            return(t);
        }
Example #4
0
        static void DefineCtors(TypeBuilder proxyTB,
                                Type superClass,
                                string initName,
                                string postInitName,
                                ISeq ctors,
                                ISeq ctorTypes,
                                FieldBuilder initFB,
                                FieldBuilder postInitFB,
                                FieldBuilder stateFB,
                                string factoryName)
        {
            ISeq s1 = ctors;

            for (ISeq s = ctorTypes; s != null; s = s.next())
            {
                // TODO: Get rid of this mess by making sure the metadata on the keys of the constructors map gets copied to the constructor-types map.  Sigh.
                IPersistentMap ctorAttributes = GenInterface.ExtractAttributes(RT.meta(((IMapEntry)s1.first()).key()));
                s1 = s1.next();

                IMapEntry me = (IMapEntry)s.first();
                ISeq      thisParamTypesV = (ISeq)me.key();
                ISeq      baseParamTypesV = (ISeq)me.val();

                Type[] thisParamTypes = CreateTypeArray(thisParamTypesV);
                Type[] baseParamTypes = CreateTypeArray(baseParamTypesV);

                BindingFlags    flags     = BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
                ConstructorInfo superCtor = superClass.GetConstructor(flags, null, baseParamTypes, null);

                if (superCtor == null || superCtor.IsPrivate)
                {
                    throw new InvalidOperationException("Base class constructor missing or private");
                }

                ConstructorBuilder cb = proxyTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, thisParamTypes);
                GenInterface.SetCustomAttributes(cb, ctorAttributes);

                CljILGen gen = new CljILGen(cb.GetILGenerator());

                Label noInitLabel      = gen.DefineLabel();
                Label noPostInitLabel  = gen.DefineLabel();
                Label endPostInitLabel = gen.DefineLabel();
                Label endLabel         = gen.DefineLabel();

                LocalBuilder locSuperArgs = gen.DeclareLocal(typeof(object));
                LocalBuilder locInitVal   = gen.DeclareLocal(typeof(object));

                if (initFB != null)
                {
                    // init supplied
                    EmitGetVar(gen, initFB);
                    gen.Emit(OpCodes.Dup);
                    gen.Emit(OpCodes.Brfalse_S, noInitLabel);
                    gen.Emit(OpCodes.Castclass, typeof(IFn));

                    // box init args
                    for (int i = 0; i < thisParamTypes.Length; i++)
                    {
                        gen.EmitLoadArg(i + 1);                     // gen.Emit(OpCodes.Ldarg, i + 1);
                        if (thisParamTypes[i].IsValueType)
                        {
                            gen.Emit(OpCodes.Box, thisParamTypes[i]);
                        }
                    }

                    gen.EmitCall(Compiler.Methods_IFn_invoke[thisParamTypes.Length]);   // gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[thisParamTypes.Length]);

                    // Expecting:  [[super-ctor-args...] state]

                    // store the init return in a local
                    gen.Emit(OpCodes.Dup);
                    gen.Emit(OpCodes.Stloc, locInitVal);

                    // store the first element in a local
                    gen.EmitInt(0);                             // gen.Emit(OpCodes.Ldc_I4_0);
                    gen.EmitCall(Method_RT_nth);                // gen.Emit(OpCodes.Call, Method_RT_nth);
                    gen.Emit(OpCodes.Stloc, locSuperArgs);

                    // Stack this + super-ctor-args + call base-class ctor.
                    gen.EmitLoadArg(0);                         // gen.Emit(OpCodes.Ldarg_0);
                    for (int i = 0; i < baseParamTypes.Length; i++)
                    {
                        gen.Emit(OpCodes.Ldloc, locSuperArgs);
                        gen.EmitInt(i);                         // gen.Emit(OpCodes.Ldc_I4, i);
                        gen.EmitCall(Method_RT_nth);            // gen.Emit(OpCodes.Call, Method_RT_nth);
                        if (baseParamTypes[i].IsValueType)
                        {
                            gen.Emit(OpCodes.Unbox_Any, baseParamTypes[i]);
                        }
                        else
                        {
                            gen.Emit(OpCodes.Castclass, baseParamTypes[i]);
                        }
                    }

                    gen.Emit(OpCodes.Call, superCtor);

                    if (stateFB != null)
                    {
                        gen.EmitLoadArg(0);                     // gen.Emit(OpCodes.Ldarg_0);
                        gen.Emit(OpCodes.Ldloc, locInitVal);
                        gen.EmitInt(1);                         // gen.Emit(OpCodes.Ldc_I4_1);
                        gen.EmitCall(Method_RT_nth);            // gen.Emit(OpCodes.Call, Method_RT_nth);
                        gen.Emit(OpCodes.Castclass, typeof(object));
                        gen.EmitFieldSet(stateFB);              // gen.Emit(OpCodes.Stfld, stateFB);
                    }

                    gen.Emit(OpCodes.Br_S, endLabel);

                    // No init found
                    gen.MarkLabel(noInitLabel);

                    gen.Emit(OpCodes.Pop);
                    EmitUnsupported(gen, initName);

                    gen.MarkLabel(endLabel);
                }
                else  // no InitFB supplied.
                {
                    bool ok = thisParamTypes.Length == baseParamTypes.Length;
                    for (int i = 0; ok && i < thisParamTypes.Length; i++)
                    {
                        ok = baseParamTypes[i].IsAssignableFrom(thisParamTypes[i]);
                    }
                    if (!ok)
                    {
                        throw new InvalidOperationException(":init not specified, but ctor and super ctor args differ");
                    }
                    gen.EmitLoadArg(0);                                 // gen.Emit(OpCodes.Ldarg_0);
                    for (int i = 0; i < thisParamTypes.Length; i++)
                    {
                        gen.EmitLoadArg(i + 1);                         // gen.Emit(OpCodes.Ldarg, i + 1);
                        if (baseParamTypes[i] != thisParamTypes[i])
                        {
                            gen.Emit(OpCodes.Castclass, baseParamTypes[i]);
                        }
                    }
                    gen.Emit(OpCodes.Call, superCtor);
                }

                if (postInitFB != null)
                {
                    // post-init supplied
                    EmitGetVar(gen, postInitFB);
                    gen.Emit(OpCodes.Dup);
                    gen.Emit(OpCodes.Brfalse_S, noPostInitLabel);
                    gen.Emit(OpCodes.Castclass, typeof(IFn));

                    // box init args
                    gen.EmitLoadArg(0);                                 // gen.Emit(OpCodes.Ldarg_0);
                    for (int i = 0; i < thisParamTypes.Length; i++)
                    {
                        gen.EmitLoadArg(i + 1);                         // gen.Emit(OpCodes.Ldarg, i + 1);
                        if (thisParamTypes[i].IsValueType)
                        {
                            gen.Emit(OpCodes.Box, thisParamTypes[i]);
                        }
                        gen.Emit(OpCodes.Castclass, thisParamTypes[i]);
                    }
                    gen.EmitCall(Compiler.Methods_IFn_invoke[thisParamTypes.Length + 1]);   // gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[thisParamTypes.Length + 1]);
                    gen.Emit(OpCodes.Pop);
                    gen.Emit(OpCodes.Br_S, endPostInitLabel);

                    // no post-init found

                    gen.MarkLabel(noPostInitLabel);

                    gen.Emit(OpCodes.Pop);
                    EmitUnsupported(gen, postInitName + " not defined");

                    gen.MarkLabel(endPostInitLabel);
                }

                gen.Emit(OpCodes.Ret);


                if (!String.IsNullOrEmpty(factoryName))
                {
                    MethodBuilder factoryMB = proxyTB.DefineMethod(factoryName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, proxyTB, thisParamTypes);
                    CljILGen      genf      = new CljILGen(factoryMB.GetILGenerator());

                    LocalBuilder[] locals = new LocalBuilder[thisParamTypes.Length];
                    for (int i = 0; i < thisParamTypes.Length; i++)
                    {
                        locals[i] = genf.DeclareLocal(thisParamTypes[i]);
                        genf.EmitLoadArg(i);                    // genf.Emit(OpCodes.Ldarg, i);
                        genf.Emit(OpCodes.Stloc, locals[i]);
                    }


                    for (int i = 0; i < thisParamTypes.Length; i++)
                    {
                        genf.EmitLoadArg(i);                    // genf.Emit(OpCodes.Ldarg, i);
                    }
                    genf.EmitNew(cb);                           // genf.Emit(OpCodes.Newobj, cb);
                    genf.Emit(OpCodes.Ret);
                }
            }
        }