From 42c23d3ebe2b2a03c1bd17ed9c0108945d8db050 Mon Sep 17 00:00:00 2001 From: Antonius Riha Date: Sun, 14 Jun 2015 10:37:20 +0200 Subject: [PATCH 1/2] Introduce accessor concept to InterfaceVMs This fixes inconsistent method generation in GIntrface interfaces, adapters and implementor interfaces. For example, in Atk.IText the method GetRangeExtents existed with two different signatures. In Atk.IText and Atk.TextAdapter we had: (1) Atk.TextRectangle GetRangeExtents(int start_offset, int end_offset, Atk.CoordType coord_type); whereas the signature in Atk.ITextImplementor was: (2) void GetRangeExtents (int start_offset, int end_offset, Atk.CoordType coord_type, out Atk.TextRectangle rect); This fix ensures that all interface methods have the form as shown in (1). This has been implemented by applying the same rules for "Accessor"-methods in InterfaceVM as are already in place in class Method. Essentially these rules state that all methods with one out-parameter are Accessor-methods. --- generator/InterfaceVM.cs | 4 ++- generator/ManagedCallString.cs | 46 +++++++++++++++++++++++------- generator/VMSignature.cs | 51 ++++++++++++++++++++++++++++++++++ generator/VirtualMethod.cs | 24 ++++++++++++++-- 4 files changed, 111 insertions(+), 14 deletions(-) diff --git a/generator/InterfaceVM.cs b/generator/InterfaceVM.cs index 39308c09a..bcc4a84d7 100644 --- a/generator/InterfaceVM.cs +++ b/generator/InterfaceVM.cs @@ -81,7 +81,9 @@ public void GenerateDeclaration (StreamWriter sw, InterfaceVM complement) } } else if (IsSetter) sw.WriteLine ("\t\t" + parms[0].CSType + " " + Name.Substring (3) + " { set; }"); - else + else if (IsAccessor) { + sw.WriteLine ("\t\t" + Signature.AccessorType + " " + Name + " (" + Signature.AsAccessor + ");"); + } else sw.WriteLine ("\t\t" + retval.CSType + " " + Name + " (" + Signature + ");"); } diff --git a/generator/ManagedCallString.cs b/generator/ManagedCallString.cs index 3e54fe349..cd4f01652 100644 --- a/generator/ManagedCallString.cs +++ b/generator/ManagedCallString.cs @@ -24,6 +24,7 @@ namespace GtkSharp.Generation { using System; using System.Collections.Generic; using System.IO; + using System.Linq; public class ManagedCallString { @@ -34,9 +35,18 @@ public class ManagedCallString { string destroy_param = null; public ManagedCallString (Parameters parms) + : this (parms, false) + { + } + + private ManagedCallString (Parameters parms, bool stripAccessorParameter) { for (int i = 0; i < parms.Count; i ++) { Parameter p = parms [i]; + if (stripAccessorParameter && p.PassAs == "out") { + continue; + } + if (p.IsLength && i > 0 && parms [i-1].IsString) continue; else if (p.Scope == "notified") { @@ -90,6 +100,14 @@ public string Unconditional (string indent) { return ret; } + public static ManagedCallString CreateWithoutAccessorParameter (Parameters parms, + out Parameter accessorParam) + { + var call = new ManagedCallString (parms, true); + accessorParam = parms.FirstOrDefault (p => p.PassAs == "out"); + return call; + } + public string Setup (string indent) { string ret = ""; @@ -158,21 +176,29 @@ public string Finish (string indent) continue; } - IGeneratable igen = p.Generatable; - - if (igen is CallbackGen) - continue; - else if (igen is StructBase || igen is ByRefGen) - ret += indent + String.Format ("if ({0} != IntPtr.Zero) System.Runtime.InteropServices.Marshal.StructureToPtr (my{0}, {0}, false);\n", p.Name); - else if (igen is IManualMarshaler) - ret += String.Format ("{0}{1} = {2};", indent, p.Name, (igen as IManualMarshaler).AllocNative ("my" + p.Name)); - else - ret += indent + p.Name + " = " + igen.CallByName ("my" + p.Name) + ";\n"; + ret += GetParamAssignmentStatement ("my" + p.Name, p, indent); } return ret; } + public static string GetParamAssignmentStatement (string srcParameterName, Parameter p, string indent) + { + var ret = string.Empty; + IGeneratable igen = p.Generatable; + + if (igen is CallbackGen) + return string.Empty; + else if (igen is StructBase || igen is ByRefGen) + ret += indent + String.Format ("if ({0} != IntPtr.Zero) System.Runtime.InteropServices.Marshal.StructureToPtr ({1}, {0}, false);\n", p.Name, srcParameterName); + else if (igen is IManualMarshaler) + ret += String.Format ("{0}{1} = {2};", indent, p.Name, (igen as IManualMarshaler).AllocNative (srcParameterName)); + else + ret += indent + p.Name + " = " + igen.CallByName (srcParameterName) + ";\n"; + + return ret; + } + public string DisposeParams (string indent) { string ret = ""; diff --git a/generator/VMSignature.cs b/generator/VMSignature.cs index d2dbc7ce4..0a3b0bdf7 100644 --- a/generator/VMSignature.cs +++ b/generator/VMSignature.cs @@ -55,6 +55,57 @@ public VMSignature (Parameters parms) } } + public bool IsAccessor { + get { + int count = 0; + foreach (Parameter p in parms) { + if (p.PassAs == "out") + count++; + + if (count > 1) + return false; + } + return count == 1; + } + } + + public string AccessorType { + get { + foreach (Parameter p in parms) + if (p.PassAs == "out") + return p.CSType; + + return null; + } + } + + public string AccessorName { + get { + foreach (Parameter p in parms) + if (p.PassAs == "out") + return p.Name; + + return null; + } + } + + public string AsAccessor { + get { + string[] result = new string [parms.Count - 1]; + int i = 0; + + foreach (Parameter p in parms) { + if (p.PassAs == "out") + continue; + + result [i] = p.PassAs != "" ? p.PassAs + " " : ""; + result [i++] += p.CSType + " " + p.Name; + } + + return String.Join (", ", result); + } + } + public string GetCallString (bool use_place_holders) { if (parms.Count == 0) diff --git a/generator/VirtualMethod.cs b/generator/VirtualMethod.cs index 901ad02bd..3175cf3dd 100644 --- a/generator/VirtualMethod.cs +++ b/generator/VirtualMethod.cs @@ -30,6 +30,7 @@ namespace GtkSharp.Generation { public abstract class VirtualMethod : MethodBase { protected ReturnValue retval; protected ManagedCallString call; + private Parameter accessorParam; protected string modifiers = ""; @@ -56,6 +57,12 @@ protected abstract string CallString { } } + protected bool IsAccessor { + get { + return retval.IsVoid && Signature.IsAccessor; + } + } + /* Creates a callback method which invokes the corresponding virtual method * @implementor is the class that implements the virtual method(e.g. the class that derives from an interface) or NULL if containing and declaring type are equal */ @@ -99,16 +106,22 @@ public void GenerateCallback (StreamWriter sw, ClassBase implementor) } string indent = "\t\t\t\t"; - if (!retval.IsVoid) + if (IsAccessor) { + sw.WriteLine (indent + Signature.AccessorType + " __result;"); + } else if (!retval.IsVoid) sw.WriteLine (indent + retval.CSType + " __result;"); sw.Write (call.Setup (indent)); sw.Write (indent); - if (!retval.IsVoid) + if (!retval.IsVoid || IsAccessor) sw.Write ("__result = "); if (!this.IsStatic) sw.Write ("__obj."); sw.WriteLine (this.CallString + ";"); sw.Write (call.Finish (indent)); + if (IsAccessor) { + sw.Write (ManagedCallString.GetParamAssignmentStatement ("__result", accessorParam, indent)); + } + if (!retval.IsVoid) sw.WriteLine ("\t\t\t\treturn " + retval.ToNative ("__result") + ";"); @@ -149,7 +162,12 @@ public override bool Validate (LogWriter log) return false; } - call = new ManagedCallString (parms); + if (IsAccessor) { + call = ManagedCallString.CreateWithoutAccessorParameter (parms, out accessorParam); + } else { + call = new ManagedCallString (parms); + } + return true; } } From 997f8d434af1dd47d43a41414f135e9df33b9dd3 Mon Sep 17 00:00:00 2001 From: Antonius Riha Date: Sun, 14 Jun 2015 10:39:19 +0200 Subject: [PATCH 2/2] Make GObjectVM overrides accessor-aware --- generator/GObjectVM.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/generator/GObjectVM.cs b/generator/GObjectVM.cs index 07dc2f43d..1d62a4ba9 100644 --- a/generator/GObjectVM.cs +++ b/generator/GObjectVM.cs @@ -187,9 +187,26 @@ protected void GenerateMethodBody (StreamWriter sw, ClassBase implementor) sw.Write ("\t\t{0} ", this.Protection); if (this.modifiers != "") sw.Write ("{0} ", this.modifiers); - sw.WriteLine ("virtual {0} On{1} ({2})", retval.CSType, this.Name, Signature.ToString ()); + string ret, signature; + if (IsAccessor) { + ret = Signature.AccessorType; + signature = Signature.AsAccessor; + } else { + ret = retval.CSType; + signature = Signature.ToString (); + } + + sw.WriteLine ("virtual {0} On{1} ({2})", ret, this.Name, signature); sw.WriteLine ("\t\t{"); + var accessorParamName = Signature.AccessorName; + if (IsAccessor) { + sw.WriteLine ("\t\t\t{0} {1};", ret, accessorParamName); + } + sw.WriteLine ("\t\t\t{0}Internal{1} ({2});", retval.IsVoid ? "" : "return ", this.Name, Signature.GetCallString (false)); + if (IsAccessor) { + sw.WriteLine ("\t\t\treturn {0};", accessorParamName); + } sw.WriteLine ("\t\t}"); sw.WriteLine (); // This method is to be invoked from existing VM implementations in the custom code