зеркало из https://github.com/mozilla/pjs.git
173 строки
5.7 KiB
C#
173 строки
5.7 KiB
C#
using System;
|
|
using Mozilla.XPCOM;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Collections;
|
|
|
|
public class Generate
|
|
{
|
|
ModuleBuilder mb;
|
|
Hashtable ifaceTable = new Hashtable();
|
|
bool verbose = false;
|
|
PropertyBuilder lastProperty = null;
|
|
const PropertyAttributes PROPERTY_ATTRS = PropertyAttributes.None;
|
|
const MethodAttributes METHOD_ATTRS = MethodAttributes.Public |
|
|
MethodAttributes.Abstract | MethodAttributes.Virtual |
|
|
MethodAttributes.NewSlot;
|
|
|
|
Type FixupInterfaceType(TypeInfo.ParamDescriptor desc)
|
|
{
|
|
try {
|
|
String ifaceName = desc.GetInterfaceName();
|
|
return EmitOneInterface(ifaceName);
|
|
} catch (Exception e) {
|
|
Console.WriteLine(e);
|
|
return typeof(object);
|
|
}
|
|
}
|
|
|
|
void GenerateInterfaceMethod(TypeBuilder tb,
|
|
TypeInfo.MethodDescriptor desc)
|
|
{
|
|
if (desc == null || !desc.IsVisible())
|
|
return;
|
|
|
|
MethodAttributes methodAttrs = METHOD_ATTRS;
|
|
|
|
String methodName = desc.name;
|
|
if (desc.IsGetter()) {
|
|
methodName = "get_" + desc.name;
|
|
methodAttrs |= MethodAttributes.SpecialName;
|
|
} else if (desc.IsSetter()) {
|
|
methodName = "set_" + desc.name;
|
|
methodAttrs |= MethodAttributes.SpecialName;
|
|
}
|
|
|
|
// Fix up interface types in parameters
|
|
Type ret = desc.resultType;
|
|
if (ret == typeof(object))
|
|
ret = FixupInterfaceType(desc.args[desc.args.Length - 1]);
|
|
Type[] argTypes = (Type[])desc.argTypes.Clone();
|
|
for (int i = 0; i < argTypes.Length; i++) {
|
|
if (argTypes[i] == typeof(object))
|
|
argTypes[i] = FixupInterfaceType(desc.args[i]);
|
|
}
|
|
MethodBuilder meth = tb.DefineMethod(methodName, methodAttrs, ret,
|
|
argTypes);
|
|
|
|
if (desc.IsSetter()) {
|
|
if (lastProperty != null && lastProperty.Name == desc.name) {
|
|
lastProperty.SetSetMethod(meth);
|
|
} else {
|
|
tb.DefineProperty(desc.name, PROPERTY_ATTRS, ret, new Type[0])
|
|
.SetSetMethod(meth);
|
|
}
|
|
lastProperty = null;
|
|
} else if (desc.IsGetter()) {
|
|
lastProperty = tb.DefineProperty(desc.name, PROPERTY_ATTRS, ret,
|
|
new Type[0]);
|
|
lastProperty.SetGetMethod(meth);
|
|
} else {
|
|
lastProperty = null;
|
|
}
|
|
}
|
|
|
|
Type EmitOneInterface(String name)
|
|
{
|
|
if (ifaceTable.ContainsKey(name))
|
|
return (Type)ifaceTable[name];
|
|
Console.WriteLine("Interface: {0}", name);
|
|
|
|
ushort inheritedMethodCount;
|
|
String parentName = TypeInfo.GetParentInfo(name,
|
|
out inheritedMethodCount);
|
|
Type parentType;
|
|
|
|
if (parentName == null)
|
|
parentType = typeof(object);
|
|
else
|
|
parentType = EmitOneInterface(parentName);
|
|
|
|
Console.WriteLine ("Emitting: " + name + " : " + parentType);
|
|
|
|
TypeBuilder ifaceTb = mb.DefineType("Mozilla.XPCOM.Interfaces." + name,
|
|
TypeAttributes.Public |
|
|
TypeAttributes.Interface |
|
|
TypeAttributes.Abstract,
|
|
parentType);
|
|
ifaceTable.Add(name, ifaceTb);
|
|
|
|
TypeInfo.MethodDescriptor[] descs;
|
|
try {
|
|
descs = TypeInfo.GetMethodData(name);
|
|
} catch (Exception ex) {
|
|
Console.WriteLine("skipping interface {0}: {1}", name,
|
|
ex.Message);
|
|
return null;
|
|
}
|
|
|
|
if (descs == null) {
|
|
Console.WriteLine("No descs!");
|
|
return null;
|
|
}
|
|
|
|
if (verbose) {
|
|
Console.WriteLine("{0} has {1} methods ({2} inherited from {3})",
|
|
name, descs.Length, inheritedMethodCount,
|
|
parentName);
|
|
}
|
|
for (int i = inheritedMethodCount; i < descs.Length; i++) {
|
|
GenerateInterfaceMethod(ifaceTb, descs[i]);
|
|
}
|
|
|
|
ifaceTb.CreateType();
|
|
return ifaceTb;
|
|
}
|
|
|
|
void GenerateInterfaceAssembly(string[] args)
|
|
{
|
|
String dllName = args[0];
|
|
String onlyInterface = null;
|
|
if (args.Length > 1)
|
|
onlyInterface = args[1];
|
|
AssemblyName an = new AssemblyName();
|
|
an.Version = new Version(1, 0, 0, 0);
|
|
an.Name = "Mozilla.XPCOM.Interfaces";
|
|
|
|
AssemblyBuilder ab = AppDomain.CurrentDomain.
|
|
DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
|
|
mb = ab.DefineDynamicModule(an.Name, dllName);
|
|
|
|
if (onlyInterface != null) {
|
|
verbose = true;
|
|
EmitOneInterface(onlyInterface);
|
|
} else {
|
|
IntPtr e = TypeInfo.typeinfo_EnumerateInterfacesStart();
|
|
if (e == IntPtr.Zero)
|
|
return;
|
|
|
|
while (true) {
|
|
String name = TypeInfo.typeinfo_EnumerateInterfacesNext(e);
|
|
if (name == null)
|
|
break;
|
|
EmitOneInterface(name);
|
|
}
|
|
|
|
TypeInfo.typeinfo_EnumerateInterfacesStop(e);
|
|
}
|
|
|
|
ab.Save(dllName);
|
|
|
|
Console.WriteLine("Generated metadata for {0} interfaces in {1}",
|
|
ifaceTable.Count, dllName);
|
|
}
|
|
|
|
public static void Main(String[] args)
|
|
{
|
|
Components.Init();
|
|
|
|
Generate gen = new Generate();
|
|
gen.GenerateInterfaceAssembly(args);
|
|
}
|
|
}
|