diff --git a/Source/Bind/CSharpSpecWriter.cs b/Source/Bind/CSharpSpecWriter.cs index cfb02b86..c9ad9c70 100644 --- a/Source/Bind/CSharpSpecWriter.cs +++ b/Source/Bind/CSharpSpecWriter.cs @@ -328,7 +328,7 @@ namespace Bind sw.WriteLine("}"); sw.WriteLine(); - int current = 0; + int current_wrapper = 0; foreach (string key in wrappers.Keys) { if (((Settings.Compatibility & Settings.Legacy.NoSeparateFunctionNamespaces) == Settings.Legacy.None) && key != "Core") @@ -349,7 +349,8 @@ namespace Bind wrappers[key].Sort(); foreach (Function f in wrappers[key]) { - current = WriteWrapper(sw, current, f, enums); + WriteWrapper(sw, f, enums); + current_wrapper++; } if (((Settings.Compatibility & Settings.Legacy.NoSeparateFunctionNamespaces) == Settings.Legacy.None) && key != "Core") @@ -359,28 +360,35 @@ namespace Bind sw.WriteLine(); } } + + // Emit native signatures. + // These are required by the patcher. + int current_signature = 0; + foreach (var d in wrappers.Values.SelectMany(e => e).Select(w => w.WrappedDelegate).Distinct()) + { + sw.WriteLine("[Slot({0})]", d.Slot); + sw.WriteLine("static extern {0};", GetDeclarationString(d, false)); + current_signature++; + } + sw.Unindent(); sw.WriteLine("}"); + + Console.WriteLine("Wrote {0} wrappers for {1} signatures", current_wrapper, current_signature); } - int WriteWrapper(BindStreamWriter sw, int current, Function f, EnumCollection enums) + void WriteWrapper(BindStreamWriter sw, Function f, EnumCollection enums) { if ((Settings.Compatibility & Settings.Legacy.NoDocumentation) == 0) { - string text = String.Format("Writing function #{0}: {1}", current++, f.ToString()); - ConsoleRewrite(text); - WriteDocumentation(sw, f); } WriteMethod(sw, f, enums); sw.WriteLine(); - return current; } private void WriteMethod(BindStreamWriter sw, Function f, EnumCollection enums) { - CreateBody(f, enums); - if (!String.IsNullOrEmpty(f.Obsolete)) { sw.WriteLine("[Obsolete(\"{0}\")]", f.Obsolete); @@ -397,10 +405,7 @@ namespace Bind sw.WriteLine("[AutoGenerated(Category = \"{0}\", Version = \"{1}\", EntryPoint = \"{2}\")]", f.Category, f.Version, Settings.FunctionPrefix + f.WrappedDelegate.EntryPoint); - sw.WriteLine("[Slot({0})]", f.WrappedDelegate.Slot); - sw.WriteLine("public static extern "); - sw.Write(GetDeclarationString(f)); - sw.WriteLine(); + sw.WriteLine("public static extern {0};", GetDeclarationString(f)); } DocProcessor processor_; @@ -565,9 +570,6 @@ namespace Bind int current = 0; foreach (Enum @enum in enums.Values) { - string text = String.Format("Writing enum #{0}: {1}", current++, @enum.Name); - ConsoleRewrite(text); - if (!Settings.IsEnabled(Settings.Legacy.NoDocumentation)) { // Document which functions use this enum. @@ -650,254 +652,6 @@ namespace Bind return enums.ContainsKey(s); } - void CreateBody(Function func, EnumCollection enums) - { - Function f = new Function(func); - f.Body.Clear(); - - var pin_statements = new List(); - var assign_statements = new List(); - var declaration_statements = new List(); - - // Obtain pointers by pinning the parameters - int index = -1; - foreach (Parameter p in f.Parameters) - { - index++; - if (p.NeedsPin) - { - if (p.WrapperType == WrapperTypes.GenericParameter || - p.WrapperType == WrapperTypes.PointerParameter || - p.WrapperType == WrapperTypes.ArrayParameter || - p.WrapperType == WrapperTypes.ReferenceParameter) - { - // Pin the parameter to obtain a pointer we can safely pass to unmanaged code - if (p.Pointer > 0) - { - declaration_statements.Add(String.Format("IntPtr {0}_ptr = new IntPtr({0});", p.Name)); - } - pin_statements.Add(String.Format( - "{2}{0}_ptr = InteropHelper.Pin({1}{0});", - p.Name, - p.Reference ? "ref " : "", - p.Pointer == 0 ? "IntPtr " : "")); - - // We also need to initialize out parameters, in order to make the compiler happy - if (p.Flow == FlowDirection.Out && p.Reference) - { - declaration_statements.Add(String.Format("{0} = default({1});", p.Name, p.QualifiedType)); - } - } - else if (p.WrapperType == WrapperTypes.None) - { - // do nothing - } - else - { - throw new ApplicationException(String.Format( - "Unknown wrapper type '{0}', code generation failed", - p.WrapperType)); - } - } - else if (p.WrapperType == WrapperTypes.ConvenienceArrayType) - { - var p_array = f.WrappedDelegate.Parameters[f.WrappedDelegate.Parameters.Count - 1]; - var p_size = f.WrappedDelegate.Parameters[f.WrappedDelegate.Parameters.Count - 2]; - declaration_statements.Add(String.Format( - "const {0} = 1;", - GetDeclarationString(p_size, false))); - declaration_statements.Add(String.Format("{0}_ptr = ({1})&{2};", - GetDeclarationString(p_array, false), - GetDeclarationString(p_array as Type), - p.Name)); - } - - p.QualifiedType = f.WrappedDelegate.Parameters[index].QualifiedType; - } - - if (f.ReturnType.WrapperType == WrapperTypes.ConvenienceReturnType || - f.ReturnType.WrapperType == WrapperTypes.ConvenienceArrayReturnType) - { - var r = f.ReturnType; - var p = f.WrappedDelegate.Parameters.Last(); - if (r.WrapperType == WrapperTypes.ConvenienceArrayReturnType) - { - var p_size = f.WrappedDelegate.Parameters[f.WrappedDelegate.Parameters.Count - 2]; - declaration_statements.Add(String.Format( - "const {0} = 1;", - GetDeclarationString(p_size, false))); - } - declaration_statements.Add(String.Format("{0} retval;", GetDeclarationString(r))); - declaration_statements.Add(String.Format("{0}{2} {1}_ptr = &retval;", - GetDeclarationString(r), - p.Name, - pointer_levels[p.IndirectionLevel])); - } - - f.Body.Indent(); - - // Automatic OpenGL error checking. - // See OpenTK.Graphics.ErrorHelper for more information. - // Make sure that no error checking is added to the GetError function, - // as that would cause infinite recursion! - if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0) - { - if (f.TrimmedName != "GetError") - { - f.Body.Add("#if DEBUG"); - f.Body.Add("using (new ErrorHelper(GraphicsContext.CurrentContext))"); - f.Body.Add("{"); - if (f.TrimmedName == "Begin") - f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = false;"); - f.Body.Add("#endif"); - } - } - - // Mark the body as unsafe if necessary - bool add_unsafe = !f.Unsafe && declaration_statements.Count > 0; - if (add_unsafe) - { - f.Body.Add("unsafe"); - f.Body.Add("{"); - f.Body.Indent(); - } - - if (declaration_statements.Count > 0) - { - f.Body.AddRange(declaration_statements); - } - - if (pin_statements.Count > 0) - { - f.Body.AddRange(pin_statements); - } - - // Hack: When creating untyped enum wrappers, it is possible that the wrapper uses an "All" - // enum, while the delegate uses a specific enum (e.g. "TextureUnit"). For this reason, we need - // to modify the parameters before generating the call string. - // Note: We cannot generate a callstring using WrappedDelegate directly, as its parameters will - // typically be different than the parameters of the wrapper. We need to modify the parameters - // of the wrapper directly. - var wrapped = new Delegate(f.WrappedDelegate); - if ((Settings.Compatibility & Settings.Legacy.KeepUntypedEnums) != 0) - { - int parameter_index = -1; // Used for comparing wrapper parameters with delegate parameters - foreach (Parameter p in f.Parameters) - { - parameter_index++; - if (IsEnum(p.Name, enums) && p.QualifiedType != wrapped.Parameters[parameter_index].QualifiedType) - { - p.QualifiedType = wrapped.Parameters[parameter_index].QualifiedType; - } - } - } - - if (assign_statements.Count > 0) - { - // Call function - var callstring = GetInvocationString(f, true); - if (func.Parameters.Any(p => p.WrapperType == WrapperTypes.ConvenienceArrayType)) - { - // foo(int id) { foo(1, ref id) } - callstring = GetInvocationString(wrapped, true); - f.Body.Add(String.Format("{0}{1};", - f.ReturnType.CurrentType.ToLower().Contains("void") ? String.Empty : "return ", - callstring)); - } - else if (f.ReturnType.CurrentType.ToLower().Contains("void")) - { - f.Body.Add(String.Format("{0};", callstring)); - } - else if (func.ReturnType.WrapperType == WrapperTypes.ConvenienceReturnType || - func.ReturnType.WrapperType == WrapperTypes.ConvenienceArrayReturnType) - { - // int foo() { int value; foo(1, &value); retval = value } - callstring = GetInvocationString(wrapped, true); - var p = wrapped.Parameters.Last(); - f.Body.Add(String.Format("{0};", callstring)); - f.Body.Add(String.Format( - "retval = {0}{1};", - pointer_levels[p.IndirectionLevel], - p.Name)); - } - else if (func.ReturnType.CurrentType.ToLower().Contains("string")) - { - f.Body.Add(String.Format("{0} {1} = null; unsafe {{ {1} = new string((sbyte*){2}); }}", - func.ReturnType.QualifiedType, "retval", callstring)); - } - else - { - f.Body.Add(String.Format("{0} {1} = {2};", - GetDeclarationString(f.ReturnType), "retval", callstring)); - } - - // Assign out parameters - f.Body.AddRange(assign_statements); - - // Return - if (!f.ReturnType.CurrentType.ToLower().Contains("void")) - { - f.Body.Add("return retval;"); - } - } - else - { - // Call function and return - var callstring = GetInvocationString(f, true); - if (func.Parameters.Any(p => p.WrapperType == WrapperTypes.ConvenienceArrayType)) - { - // int foo(int id) { return foo(1, ref id) } - callstring = GetInvocationString(wrapped, true); - f.Body.Add(String.Format("{0}{1};", - f.ReturnType.CurrentType.ToLower().Contains("void") ? String.Empty : "return ", - callstring)); - } - else if (f.ReturnType.CurrentType.ToLower().Contains("void")) - { - f.Body.Add(String.Format("{0};", callstring)); - } - else if (func.ReturnType.WrapperType == WrapperTypes.ConvenienceReturnType || - func.ReturnType.WrapperType == WrapperTypes.ConvenienceArrayReturnType) - { - // int foo() { int retval; foo(1, &retval); return retval } - callstring = GetInvocationString(wrapped, true); - f.Body.Add(String.Format("{0};", callstring)); - f.Body.Add(String.Format("return retval;")); - } - else if (func.ReturnType.CurrentType.ToLower().Contains("string")) - { - f.Body.Add(String.Format("unsafe {{ return new string((sbyte*){0}); }}", - callstring)); - } - else - { - f.Body.Add(String.Format("return {0};", callstring)); - } - } - - if (add_unsafe) - { - f.Body.Unindent(); - f.Body.Add("}"); - } - - if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0) - { - if (f.TrimmedName != "GetError") - { - f.Body.Add("#if DEBUG"); - if (f.TrimmedName == "End") - f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = true;"); - f.Body.Add("}"); - f.Body.Add("#endif"); - } - } - - f.Body.Unindent(); - - func.Body = f.Body; - } - string GetDeclarationString(Constant c) { if (String.IsNullOrEmpty(c.Name)) @@ -923,6 +677,7 @@ namespace Bind sb.Append("delegate "); sb.Append(GetDeclarationString(d.ReturnType)); sb.Append(" "); + sb.Append(Settings.FunctionPrefix); sb.Append(d.Name); sb.Append(GetDeclarationString(d.Parameters)); @@ -989,9 +744,12 @@ namespace Bind sb.Remove(sb.Length - 1, 1); sb.Append(">"); } - sb.AppendLine(GetDeclarationString(f.Parameters)); + + sb.Append(GetDeclarationString(f.Parameters)); + if (f.Parameters.HasGenericParameters) { + sb.AppendLine(); foreach (Parameter p in f.Parameters) { if (p.Generic) @@ -999,8 +757,6 @@ namespace Bind } } - sb.AppendLine(";"); - return sb.ToString(); }