void GenerateMetadata(DModule module, Type type, Type[] genericArgs)
 {
     module.WriteLine("    static struct __clrmetadata");
     module.WriteLine("    {");
     module.Write("        enum typeSpec = ");
     GenerateTypeSpecExpression(module, "            ", type, genericArgs);
     module.WriteLine(";");
     module.WriteLine("    }");
 }
 void GenerateDelegate(DModule module, Type type)
 {
     module.Write("/* .NET Delegate */ static struct {0}", Util.GetUnqualifiedTypeName(type));
     Type[] genericArgs = type.GetGenericArguments();
     GenerateGenericParameters(module, genericArgs, type.DeclaringType.GetGenericArgCount());
     module.WriteLine();
     module.WriteLine("{");
     module.WriteLine("    // TODO: generate delegate members");
     module.WriteLine("}");
 }
 void GenerateInterface(DModule module, Type type)
 {
     module.WriteLine("interface {0}", Util.GetUnqualifiedTypeName(type));
     module.WriteLine("{");
     Debug.Assert(type.GetFields().Length == 0);
     //??? GenerateMetadata(module, type);
     GenerateMethods(module, type);
     GenerateSubTypes(module, type);
     module.WriteLine("}");
 }
 void GenerateStruct(DModule module, Type type)
 {
     module.WriteLine("static struct {0}", Util.GetUnqualifiedTypeName(type));
     module.WriteLine("{");
     Type[] genericArgs = type.GetGenericArguments();
     GenerateMetadata(module, type, genericArgs);
     GenerateFields(module, type);
     GenerateMethods(module, type);
     GenerateSubTypes(module, type);
     module.WriteLine("}");
 }
    void GenerateEnum(DModule module, Type type)
    {
        const String EnumValueFieldName = "value__";

        module.WriteLine("/* .NET Enum */ static struct {0}", Util.GetUnqualifiedTypeName(type));
        module.WriteLine("{");
        Type[] genericArgs = type.GetGenericArguments();
        Debug.Assert(genericArgs.IsEmpty(), "enums can have generic arguments???");
        GenerateMetadata(module, type, genericArgs);
        String baseTypeDName = ToDEquivalentType(type.BaseType); // TODO: Marshal Type instead???

        module.WriteLine("    private {0} {1}; // .NET BasteType is actually {2}", baseTypeDName, EnumValueFieldName, type.BaseType);
        module.WriteLine("    enum : typeof(this)");
        module.WriteLine("    {");
        UInt32 nonStaticFieldCount = 0;

        foreach (FieldInfo field in type.GetFields())
        {
            Debug.Assert(field.DeclaringType == type);
            Debug.Assert(field.FieldType == type);
            if (!field.IsStatic)
            {
                Debug.Assert(field.Name == EnumValueFieldName);
                nonStaticFieldCount++;
                continue;
            }
            module.WriteLine("        {0} = typeof(this)({1}({2})),", Util.ToDIdentifier(field.Name), baseTypeDName, field.GetRawConstantValue());
        }
        module.WriteLine("    }");
        Debug.Assert(nonStaticFieldCount == 1);

        // Commenting out for now because of a conflict with TypeNameKind ToString
        // It looks like C# might allow field names and method names to have the same symbol?
        // I'll need to see in which cases C# allows this, maybe only with static fields?
        // If so, the right solution would probably be to modify the field name that conflicts.
        //GenerateMethods(module, type);

        /*
         * foreach (var method in type.GetMethods())
         * {
         *  module.WriteLine("    // TODO: generate something for enum method {0}", method);
         * }
         */

        // Generate opMethods so this behaves like an enum
        module.WriteLine("    typeof(this) opBinary(string op)(const typeof(this) right) const");
        module.WriteLine("    { return typeof(this)(mixin(\"this.value__ \" ~ op ~ \" right.value__\")); }");
        // TODO: there's probably more (or less) to generate to get the behavior right
        module.WriteLine("}");
    }
 // TODO: remove this?
 void GenerateGenericTypeSpecsExpression(DModule module, String linePrefix, Type[] genericArgs)
 {
     if (genericArgs.IsEmpty())
     {
         module.Write("null");
     }
     else
     {
         module.WriteLine("[");
         foreach (Type genericArg in genericArgs)
         {
             module.WriteLine("{0}    __d.clrbridge.GetTypeSpec!({1}),", linePrefix, ToDEquivalentType(genericArg));
         }
         module.Write("{0}]", linePrefix);
     }
 }
    void Message(DModule module, String fmt, params Object[] args)
    {
        String message = String.Format(fmt, args);

        Console.WriteLine(message);
        module.WriteLine("/* {0} */", message);
    }
 void GenerateClass(DModule module, Type type)
 {
     module.Write("/* .NET class */ static struct {0}", Util.GetUnqualifiedTypeName(type));
     Type[] genericArgs = type.GetGenericArguments();
     GenerateGenericParameters(module, genericArgs, type.DeclaringType.GetGenericArgCount());
     module.WriteLine();
     module.WriteLine("{");
     module.WriteLine("    // TODO: mixin the base class rather than DotNetObject");
     module.WriteLine("    mixin __d.clrbridge.DotNetObjectMixin!\"__d.clr.DotNetObject\";");
     // generate metadata, one reason for this is so that when this type is used as a template parameter, we can
     // get the .NET name for this type
     GenerateMetadata(module, type, genericArgs);
     GenerateFields(module, type);
     GenerateMethods(module, type);
     GenerateSubTypes(module, type);
     module.WriteLine("}");
 }
 void GenerateParameterTypeSpecExpression(DModule module, String linePrefix, ParameterInfo[] paramInfos)
 {
     if (paramInfos.IsEmpty())
     {
         module.Write("null");
     }
     else
     {
         module.WriteLine("[");
         String subTypePrefix = linePrefix + "        ";
         foreach (ParameterInfo paramInfo in paramInfos)
         {
             //module.WriteLine("{0}   {1},", linePrefix, TypeSpecReference(paramInfo.ParameterType));
             module.Write("{0}    /* param '{1}' */", linePrefix, paramInfo.Name);
             GenerateTypeSpecExpression(module, subTypePrefix, paramInfo.ParameterType);
             module.WriteLine(",");
         }
         module.Write("{0}]", linePrefix);
     }
 }
    void GenerateTypeSpecExpression(DModule module, String linePrefix, Type type, Type[] genericArgs)
    {
        if (type.IsGenericParameter)
        {
            Debug.Assert(genericArgs.IsEmpty(), "you can have a generic parameter type with generic args??");
            module.Write("__d.clrbridge.GetTypeSpec!({0})", ToDEquivalentType(type));
            return;
        }
        module.WriteLine("__d.clr.TypeSpec(");
        module.WriteLine("{0}\"{1}\",", linePrefix, type.Assembly.FullName);
        bool hasGenerics = !genericArgs.IsEmpty();

        module.Write("{0}\"{1}\"{2}", linePrefix, type.FullName, hasGenerics ? ", [" : ")", type.Name);
        if (hasGenerics)
        {
            module.WriteLine();
            foreach (Type genericArg in genericArgs)
            {
                module.WriteLine("{0}    __d.clrbridge.GetTypeSpec!({1}),", linePrefix, ToDEquivalentType(genericArg));
            }
            module.Write("{0}])", linePrefix);
        }
    }
 void GenerateFields(DModule module, Type type)
 {
     foreach (FieldInfo field in type.GetFields())
     {
         Type   fieldType = field.FieldType;
         String fromDll   = (fieldType.Assembly == thisAssembly) ? "" :
                            GetExtraAssemblyInfo(fieldType.Assembly).fromDllPrefix;
         // fields are represented as D @property functions
         module.WriteLine("    @property {0} {1}() {{ return typeof(return).init; }}; // fromPrefix '{2}' {3} {4}",
                          ToDEquivalentType(fieldType),
                          field.Name.ToDIdentifier(),
                          fromDll,
                          field.FieldType, field.FieldType.AssemblyQualifiedName);
     }
 }
    void GenerateMethodBody(DModule module, Type type,
                            MethodBase method, Type returnType, ParameterInfo[] parameters)
    {
        // skip non-static methods for now, they just take too long right now
        if (!method.IsStatic && !method.IsConstructor)
        {
            if (returnType != typeof(void))
            {
                module.WriteLine("        return typeof(return).init;");
            }
            return;
        }
        // TODO: we may want to cache some of this stuff, but for now we'll just get it every time
        Type[] genericArgs = method.IsGenericMethod ? method.GetGenericArguments() : null;
        module.WriteLine("        enum __method_spec__ = __d.clrbridge.MethodSpec(__clrmetadata.typeSpec, \"{0}\",", method.Name);
        module.Write("            /* generic args */ ");
        GenerateGenericTypeSpecsExpression(module, "            ", genericArgs);
        module.Write(", /* parameter types */ ");
        GenerateParameterTypeSpecExpression(module, "            ", parameters);
        module.WriteLine(");");

        String methodTypeString = method.IsConstructor ? "Constructor" : "Method";

        // Get Assembly so we can get Type then Method (TODO: cache this somehow?)
        module.WriteLine("        const  __this_type__ = __d.globalClrBridge.getClosedType!(__clrmetadata.typeSpec);");
        module.WriteLine("        scope (exit) __this_type__.finalRelease(__d.globalClrBridge);");
        module.WriteLine("        assert(__method_spec__.genericTypes.length == 0, \"methods with generic args not implemented\");");
        // TODO: use getClosedMethod and getClosedConstructor
        module.WriteLine("        const __method__ = __d.globalClrBridge.get{0}(__this_type__.type,", methodTypeString);
        if (!method.IsConstructor)
        {
            module.WriteLine("            __d.CStringLiteral!\"{0}\",", method.Name);
        }
        module.WriteLine("            __d.globalClrBridge.getTypesArray!(__method_spec__.paramTypes)());");
        module.WriteLine("        scope (exit) { __d.globalClrBridge.release(__method__); }");

        //
        // Create parameters ObjectArray
        //
        {
            uint paramIndex = 0;
            foreach (ParameterInfo parameter in parameters)
            {
                if (parameter.ParameterType.IsArray ||
                    parameter.ParameterType.IsByRef ||
                    parameter.ParameterType.IsPointer)
                {
                    // skip complicated types for now
                }
                else
                {
                    String boxType = TryGetBoxType(parameter.ParameterType);
                    if (boxType != null)
                    {
                        module.WriteLine("        auto  __param{0}__ = __d.globalClrBridge.box!(__d.clr.PrimitiveType.{1})({2}); // actual type is {3}",
                                         paramIndex, boxType, Util.ToDIdentifier(parameter.Name), Util.GetQualifiedTypeName(parameter.ParameterType));
                        module.WriteLine("        scope (exit) __d.globalClrBridge.release(__param{0}__);", paramIndex);
                    }
                }
                paramIndex++;
            }
        }
        if (parameters.Length == 0)
        {
            module.WriteLine("        __d.ObjectArray __param_values__ = __d.ObjectArray.nullObject;");
        }
        else
        {
            module.WriteLine("        __d.ObjectArray __param_values__ = __d.globalClrBridge.makeObjectArray(");
            {
                uint   paramIndex = 0;
                string prefix     = " ";
                foreach (ParameterInfo parameter in parameters)
                {
                    if (TryGetBoxType(parameter.ParameterType) != null)
                    {
                        module.WriteLine("            {0}__param{1}__", prefix, paramIndex);
                    }
                    else
                    {
                        module.WriteLine("            {0}{1}", prefix, Util.ToDIdentifier(parameter.Name));
                    }
                    prefix = ",";
                    paramIndex++;
                }
            }
            module.WriteLine("        );");
            module.WriteLine("        scope (exit) { __d.globalClrBridge.release(__param_values__); }");
        }
        String returnValueAddrString;

        if (returnType == typeof(void))
        {
            returnValueAddrString = "null";
        }
        else
        {
            returnValueAddrString = "cast(void**)&__return_value__";
            if (returnType == typeof(Boolean))
            {
                module.WriteLine("        ushort __return_value__;");
            }
            else
            {
                module.WriteLine("        typeof(return) __return_value__;");
            }
        }

        if (method.IsConstructor)
        {
            module.WriteLine("        __return_value__ = cast(typeof(return))__d.globalClrBridge.callConstructor(__method__, __param_values__);");
        }
        else
        {
            module.WriteLine("        __d.globalClrBridge.funcs.CallGeneric(__method__, __d.clr.DotNetObject.nullObject, __param_values__, {0});", returnValueAddrString);
        }

        if (returnType == typeof(Boolean))
        {
            module.WriteLine("        return (__return_value__ == 0) ? false : true;");
        }
        else if (returnType != typeof(void))
        {
            module.WriteLine("        return __return_value__;");
        }
    }
    void GenerateMethods(DModule module, Type type)
    {
        foreach (ConstructorInfo constructor in type.GetConstructors())
        {
            if (type.IsValueType)
            {
                continue; // script structs for now
            }
            Debug.Assert(constructor.GetGenericArguments().IsEmpty(), "constructors can have generic arguments?");
            module.Write("    {0} static typeof(this) New", constructor.IsPrivate ? "private" : "public");
            ParameterInfo[] parameters = constructor.GetParameters();
            GenerateParameterList(module, parameters);
            module.WriteLine();
            module.WriteLine("    {");
            GenerateMethodBody(module, type, constructor, type, parameters);
            module.WriteLine("    }");
        }
        foreach (MethodInfo method in type.GetMethods())
        {
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // skip virtual methods for now so we don't get linker errors
            if (method.IsVirtual)
            {
                continue;
            }

            module.Write("    {0}", method.IsPrivate ? "private" : "public");
            if (method.IsStatic)
            {
                module.Write(" static");
            }
            else if (method.IsFinal)
            {
                module.Write(" final");
            }

            Type[] genericArguments = method.GetGenericArguments();
            Debug.Assert(method.ReturnType != null);
            if (method.ReturnType == typeof(void))
            {
                module.Write(" void");
            }
            else
            {
                module.Write(" {0}", ToDEquivalentType(method.ReturnType));
            }
            module.Write(" {0}", Util.ToDIdentifier(method.Name));
            ParameterInfo[] parameters = method.GetParameters();
            GenerateGenericParameters(module, genericArguments, type.GetGenericArgCount());
            GenerateParameterList(module, parameters);
            if (method.IsVirtual)
            {
                module.WriteLine(";");
                continue;
            }
            module.WriteLine();
            module.WriteLine("    {");
            GenerateMethodBody(module, type, method, method.ReturnType, parameters);
            module.WriteLine("    }");
        }
    }