RetroZilla/extensions/mono/tools/generate-interfaces.cs
2015-10-20 23:03:22 -04:00

173 lines
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);
}
}