Browse Source

Generator: make interfaces partial, make filter files more expressive. Update qt bindings to build correctly out of the box

pull/1/head
Alexander Corrado 14 years ago
parent
commit
6a2a76216a
  1. 1
      qt/Makefile.am
  2. 5
      qt/demos/hello.cs
  3. 9
      qt/qt-gui-filters.txt
  4. 27
      qt/qt-gui-filters.xml
  5. 7
      qt/src/QApplication.cs
  6. 4
      qt/src/QCoreApplication.cs
  7. 20
      qt/src/QPushButton.cs
  8. 36
      src/generator/Filter.cs
  9. 54
      src/generator/Generator.cs
  10. 1
      src/generator/Makefile.am
  11. 16
      src/generator/Templates/CSharp/CSharpClass.cs
  12. 16
      src/generator/Templates/CSharp/CSharpClass.tt
  13. 5
      src/generator/Templates/CSharp/CSharpLanguage.cs
  14. 1
      src/generator/generator.csproj

1
qt/Makefile.am

@ -29,7 +29,6 @@ generated: qt-gui-filters.xml qt-gui.xml
# $(CXX) -m32 -I. -framework QtGui -framework QtCore -DQ_WS_MAC --shared -fPIC -o $@ -fkeep-inline-functions qt-gui.cpp # $(CXX) -m32 -I. -framework QtGui -framework QtCore -DQ_WS_MAC --shared -fPIC -o $@ -fkeep-inline-functions qt-gui.cpp
Qt.Gui-binding.dll: generated $(addprefix src/,$(HANDWRITTEN)) Qt.Gui-binding.dll: generated $(addprefix src/,$(HANDWRITTEN))
$(RM) -f generated/QString.cs generated/QSize.cs
$(GMCS) -debug -out:$@ -target:library -unsafe -r:$(INTEROP_DLL) generated/*.cs $(addprefix src/,$(HANDWRITTEN)) $(GMCS) -debug -out:$@ -target:library -unsafe -r:$(INTEROP_DLL) generated/*.cs $(addprefix src/,$(HANDWRITTEN))
hello.exe: Qt.Gui-binding.dll demos/hello.cs #libQtGui-inline.so hello.exe: Qt.Gui-binding.dll demos/hello.cs #libQtGui-inline.so

5
qt/demos/hello.cs

@ -9,9 +9,10 @@ namespace QtTest {
public static void Main (string[] args) public static void Main (string[] args)
{ {
using (QApplication app = new QApplication ()) { using (QApplication app = new QApplication ()) {
using (QPushButton hello = new QPushButton ("Hello world!", null)) { using (QPushButton hello = new QPushButton ("Hello world!")) {
hello.Resize (new QSize (100, 30)); var sz = new QSize (100, 30);
hello.Resize (ref sz);
hello.SetVisible (true); hello.SetVisible (true);
QApplication.Exec (); QApplication.Exec ();

9
qt/qt-gui-filters.txt

@ -1,9 +0,0 @@
QObject
QApplication
QCoreApplication
QWidget
QAbstractButton
QPushButton
QPaintDevice
QString
QSize

27
qt/qt-gui-filters.xml

@ -0,0 +1,27 @@
<!--
This XML filter file format.
There are 3 different modes:
Include -> include this type in the generated output
Exclude -> do not include this type in the generated output. methods using this type will be removed (virtual methods will be stubbed with IntPtr)
External -> do not include this type in the generated output, but expect an implementation to be provided
The type of external implementation can be specified:
class (default) -> this type is implemented as a managed reference type
struct -> this type is implemented as a managed value type. when passed as pointer or reference, the managed "ref" prefix will be used
The default behavior is Include. Change the default by specifying the default attribute on the top-level Filter tag.
Specify exceptions to the default behavior with child nodes named after one of the modes above…
-->
<Filter default="Exclude">
<Include>QObject</Include>
<Include>QApplication</Include>
<Include>QCoreApplication</Include>
<Include>QWidget</Include>
<Include>QAbstractButton</Include>
<Include>QPushButton</Include>
<Include>QPaintDevice</Include>
<External implementation="struct">QString</External>
<External implementation="struct">QSize</External>
</Filter>

7
qt/src/QApplication.cs

@ -4,8 +4,11 @@ using Mono.Cxxi;
namespace Qt.Gui { namespace Qt.Gui {
public partial class QApplication { public partial class QApplication {
public partial interface IQApplication {
[Constructor] CppInstancePtr QApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc, [MangleAs ("char**")] IntPtr argv, int version);
}
public QApplication () : base (impl.TypeInfo) public QApplication () : base (impl.TypeInfo)
{ {
InitArgcAndArgv (); InitArgcAndArgv ();

4
qt/src/QCoreApplication.cs

@ -5,6 +5,10 @@ using Mono.Cxxi;
namespace Qt.Gui { namespace Qt.Gui {
public partial class QCoreApplication { public partial class QCoreApplication {
public partial interface IQCoreApplication {
[Constructor] CppInstancePtr QCoreApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc, [MangleAs ("char**")] IntPtr argv);
}
protected IntPtr argc, argv; protected IntPtr argc, argv;
public QCoreApplication () : base (impl.TypeInfo) public QCoreApplication () : base (impl.TypeInfo)

20
qt/src/QPushButton.cs

@ -0,0 +1,20 @@
using System;
using System.Runtime.InteropServices;
using Mono.Cxxi;
namespace Qt.Gui {
public partial class QPushButton {
public QPushButton (QString text, QWidget parent)
: this (ref text, parent)
{
}
public QPushButton (QString text)
: this (ref text, null)
{
}
}
}

36
src/generator/Filter.cs

@ -0,0 +1,36 @@
using System;
using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;
public enum FilterMode {
Include,
Exclude,
External
}
public enum ImplementationType {
@class,
@struct
}
public struct Filter {
public string TypeName { get; set; }
public FilterMode Mode { get; set; }
public ImplementationType ImplType { get; set; }
public static Dictionary<string, Filter> Load (XDocument doc, out FilterMode @default)
{
string value;
@default = (value = (string)doc.Root.Attribute ("default")) != null ? (FilterMode)Enum.Parse (typeof (FilterMode), value) : FilterMode.Include;
var rules = from rule in doc.Root.Elements ()
let mode = (FilterMode)Enum.Parse (typeof (FilterMode), rule.Name.LocalName)
let impl = (value = (string)rule.Attribute ("implementation")) != null ? (ImplementationType)Enum.Parse (typeof (ImplementationType), value) : ImplementationType.@class
select new Filter { TypeName = rule.Value, Mode = mode, ImplType = impl };
return rules.ToDictionary<Filter,string> (r => r.TypeName);
}
}

54
src/generator/Generator.cs

@ -7,6 +7,7 @@ using System;
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml; using System.Xml;
using System.Xml.Linq;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -27,7 +28,10 @@ public class Generator {
// Classes to generate code for // Classes to generate code for
public List<Class> Classes { get; set; } public List<Class> Classes { get; set; }
public Dictionary<Node, Class> NodeToClass { get; set; } public Dictionary<Node, Class> NodeToClass { get; set; }
public Dictionary<string, string> Filters { get; set; }
private FilterMode default_filter_mode;
public FilterMode DefaultFilterMode { get { return default_filter_mode; } set { default_filter_mode = value; } }
public Dictionary<string, Filter> Filters { get; set; }
// Code templates // Code templates
public ITemplate Libs { get; set; } public ITemplate Libs { get; set; }
@ -47,7 +51,7 @@ public class Generator {
Node root = LoadXml (InputFileName); Node root = LoadXml (InputFileName);
if (FilterFile != null) if (FilterFile != null)
LoadFilters (FilterFile); Filters = Filter.Load (XDocument.Load (FilterFile), out default_filter_mode);
CreateClasses (root); CreateClasses (root);
@ -147,29 +151,27 @@ public class Generator {
return root; return root;
} }
void LoadFilters (string file) {
Filters = new Dictionary <string, string> ();
foreach (string s in File.ReadAllLines (file)) {
Filters [s] = s;
}
}
void CreateClasses (Node root) { void CreateClasses (Node root) {
List<Node> classNodes = root.Children.Where (o => o.Type == "Class" || o.Type == "Struct").ToList (); List<Node> classNodes = root.Children.Where (o =>
classNodes.RemoveAll (o => o.IsTrue ("incomplete") || !o.HasValue ("name")); (o.Type == "Class" ||
o.Type == "Struct") &&
if (Filters != null) !(o.IsTrue ("incomplete") ||
classNodes.RemoveAll (o => !Filters.ContainsKey (o.Name)); !o.HasValue ("name")
)).ToList ();
List<Class> classes = new List<Class> (); List<Class> classes = new List<Class> ();
NodeToClass = new Dictionary <Node, Class> (); NodeToClass = new Dictionary <Node, Class> ();
foreach (Node n in classNodes) { foreach (Node n in classNodes) {
Console.WriteLine (n.Name); var filter = GetFilterOrDefault (n.Name);
if (filter.Mode == FilterMode.Exclude)
continue;
Class klass = new Class (n); var klass = new Class (n);
classes.Add (klass);
NodeToClass [n] = klass; NodeToClass [n] = klass;
if (filter.Mode != FilterMode.External)
classes.Add (klass);
} }
// Compute bases // Compute bases
@ -429,7 +431,7 @@ public class Generator {
// Return the System.Type name corresponding to T, or null // Return the System.Type name corresponding to T, or null
// Returned as a string, because other wrappers do not have System.Types yet // Returned as a string, because other wrappers do not have System.Types yet
public static string CppTypeToManaged (CppType t) { public string CppTypeToManaged (CppType t) {
Type mtype = t.ToManagedType (); Type mtype = t.ToManagedType ();
if (mtype != null && mtype != typeof (ICppObject)) { if (mtype != null && mtype != typeof (ICppObject)) {
@ -441,7 +443,12 @@ public class Generator {
case CppTypes.Class: case CppTypes.Class:
case CppTypes.Struct: case CppTypes.Struct:
// FIXME: Full name // FIXME: Full name
return t.ElementTypeName;
var filter = GetFilterOrDefault (t.ElementTypeName);
if (filter.ImplType == ImplementationType.@struct)
return t.ElementTypeName + "&";
else
return t.ElementTypeName;
} }
@ -470,4 +477,13 @@ public class Generator {
} }
} }
} }
Filter GetFilterOrDefault (string typeName)
{
Filter result;
if (Filters != null && Filters.TryGetValue (typeName, out result))
return result;
return new Filter { TypeName = typeName, Mode = default_filter_mode };
}
} }

1
src/generator/Makefile.am

@ -51,6 +51,7 @@ FILES = \
Access.cs \ Access.cs \
Class.cs \ Class.cs \
Field.cs \ Field.cs \
Filter.cs \
Generator.cs \ Generator.cs \
Method.cs \ Method.cs \
Node.cs \ Node.cs \

16
src/generator/Templates/CSharp/CSharpClass.cs

@ -23,7 +23,7 @@ namespace Templates {
private void WriteMethodHeader (Method method, string layoutClass, bool isNonPrimaryOverride, bool @protected) private void WriteMethodHeader (Method method, string layoutClass, bool isNonPrimaryOverride, bool @protected)
{ {
var returnType = CSharpLanguage.TypeName (method.ReturnType, Context.Wrapper | Context.Return); var returnType = CSharpLanguage.TypeName (Generator.CppTypeToManaged (method.ReturnType), Context.Wrapper | Context.Return);
if (!isNonPrimaryOverride && method.IsVirtual) if (!isNonPrimaryOverride && method.IsVirtual)
WriteLine ("[OverrideNative (\"{0}\")]", method.Name); WriteLine ("[OverrideNative (\"{0}\")]", method.Name);
@ -63,7 +63,7 @@ private void WriteParameters (IList<Parameter> parameters, bool writeType, bool
if (i != 0) if (i != 0)
Write (", "); Write (", ");
var type = CSharpLanguage.TypeName (parameters [i].Type, Context.Parameter); var type = CSharpLanguage.TypeName (Generator.CppTypeToManaged (parameters [i].Type), Context.Parameter);
if (writeAttributes) { if (writeAttributes) {
var mangleAs = parameters [i].Type.ToString (); var mangleAs = parameters [i].Type.ToString ();
@ -283,7 +283,7 @@ private bool IsByVal (CppType t)
#line hidden #line hidden
#line 35 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" #line 35 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt"
this.Write("\t\tpublic interface "); this.Write("\t\tpublic partial interface ");
#line default #line default
#line hidden #line hidden
@ -332,7 +332,7 @@ private bool IsByVal (CppType t)
if (method.IsConstructor) if (method.IsConstructor)
Write ("CppInstancePtr"); Write ("CppInstancePtr");
else else
Write (CSharpLanguage.TypeName (method.ReturnType, Context.Interface | Context.Return)); Write (CSharpLanguage.TypeName (Generator.CppTypeToManaged (method.ReturnType), Context.Interface | Context.Return));
Write (" "); Write (" ");
Write (CSharpLanguage.SafeIdentifier (method.Name)); Write (CSharpLanguage.SafeIdentifier (method.Name));
@ -347,7 +347,7 @@ private bool IsByVal (CppType t)
Write (");\n"); Write (");\n");
} }
foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) { foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) {
WriteLine ("CppField<{0}> {1} {{ get; }}", CSharpLanguage.TypeName (field.Type, Context.Generic), CSharpLanguage.SafeIdentifier (field.Name)); WriteLine ("CppField<{0}> {1} {{ get; }}", CSharpLanguage.TypeName (Generator.CppTypeToManaged (field.Type), Context.Generic), CSharpLanguage.SafeIdentifier (field.Name));
} }
ClearIndent (); ClearIndent ();
@ -397,7 +397,7 @@ private bool IsByVal (CppType t)
#line hidden #line hidden
#line 77 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" #line 77 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt"
this.Write(this.ToStringHelper.ToStringWithCulture( CSharpLanguage.TypeName (field.Type, Context.Generic) )); this.Write(this.ToStringHelper.ToStringWithCulture( CSharpLanguage.TypeName (Generator.CppTypeToManaged (field.Type), Context.Generic) ));
#line default #line default
#line hidden #line hidden
@ -442,7 +442,7 @@ private bool IsByVal (CppType t)
PushIndent ("\t\t"); PushIndent ("\t\t");
foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) { foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) {
var fieldName = CSharpLanguage.SafeIdentifier (field.Name); var fieldName = CSharpLanguage.SafeIdentifier (field.Name);
WriteLine ("{0} {1} {2} {{", field.Access, CSharpLanguage.TypeName (field.Type, Context.Wrapper | Context.Return), fieldName); WriteLine ("{0} {1} {2} {{", field.Access, CSharpLanguage.TypeName (Generator.CppTypeToManaged (field.Type), Context.Wrapper | Context.Return), fieldName);
#line default #line default
#line hidden #line hidden
@ -628,7 +628,7 @@ private bool IsByVal (CppType t)
PushIndent ("\t\t"); PushIndent ("\t\t");
foreach (var prop in Class.Properties) { foreach (var prop in Class.Properties) {
var propName = CSharpLanguage.SafeIdentifier (prop.Name); var propName = CSharpLanguage.SafeIdentifier (prop.Name);
var type = CSharpLanguage.TypeName (prop.Type, Context.Wrapper | Context.Return); var type = CSharpLanguage.TypeName (Generator.CppTypeToManaged (prop.Type), Context.Wrapper | Context.Return);
Write (CurrentIndent + "public "); Write (CurrentIndent + "public ");

16
src/generator/Templates/CSharp/CSharpClass.tt

@ -32,7 +32,7 @@ namespace <#= Generator.Namespace #> {
<# } #> <# } #>
<# /* Interface */ #> <# /* Interface */ #>
public interface <#= iface #> : ICppClassOverridable<<#= wrapper #>> { public partial interface <#= iface #> : ICppClassOverridable<<#= wrapper #>> {
<# PushIndent ("\t\t\t"); <# PushIndent ("\t\t\t");
foreach (var method in Class.Methods) { foreach (var method in Class.Methods) {
Write (CurrentIndent); Write (CurrentIndent);
@ -52,7 +52,7 @@ namespace <#= Generator.Namespace #> {
if (method.IsConstructor) if (method.IsConstructor)
Write ("CppInstancePtr"); Write ("CppInstancePtr");
else else
Write (CSharpLanguage.TypeName (method.ReturnType, Context.Interface | Context.Return)); Write (CSharpLanguage.TypeName (Generator.CppTypeToManaged (method.ReturnType), Context.Interface | Context.Return));
Write (" "); Write (" ");
Write (CSharpLanguage.SafeIdentifier (method.Name)); Write (CSharpLanguage.SafeIdentifier (method.Name));
@ -67,14 +67,14 @@ namespace <#= Generator.Namespace #> {
Write (");\n"); Write (");\n");
} }
foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) { foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) {
WriteLine ("CppField<{0}> {1} {{ get; }}", CSharpLanguage.TypeName (field.Type, Context.Generic), CSharpLanguage.SafeIdentifier (field.Name)); WriteLine ("CppField<{0}> {1} {{ get; }}", CSharpLanguage.TypeName (Generator.CppTypeToManaged (field.Type), Context.Generic), CSharpLanguage.SafeIdentifier (field.Name));
} }
ClearIndent (); #> ClearIndent (); #>
} }
<# /* Native layout */ #> <# /* Native layout */ #>
private struct <#= layout #> { private struct <#= layout #> {
<# foreach (var field in Class.Fields) { #> <# foreach (var field in Class.Fields) { #>
public <#= CSharpLanguage.TypeName (field.Type, Context.Generic) #> <#= CSharpLanguage.SafeIdentifier (field.Name) #>; public <#= CSharpLanguage.TypeName (Generator.CppTypeToManaged (field.Type), Context.Generic) #> <#= CSharpLanguage.SafeIdentifier (field.Name) #>;
<# } #> <# } #>
} }
@ -82,7 +82,7 @@ namespace <#= Generator.Namespace #> {
<# PushIndent ("\t\t"); <# PushIndent ("\t\t");
foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) { foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) {
var fieldName = CSharpLanguage.SafeIdentifier (field.Name); var fieldName = CSharpLanguage.SafeIdentifier (field.Name);
WriteLine ("{0} {1} {2} {{", field.Access, CSharpLanguage.TypeName (field.Type, Context.Wrapper | Context.Return), fieldName); #> WriteLine ("{0} {1} {2} {{", field.Access, CSharpLanguage.TypeName (Generator.CppTypeToManaged (field.Type), Context.Wrapper | Context.Return), fieldName); #>
get { get {
return impl.<#= fieldName #> [Native]; return impl.<#= fieldName #> [Native];
} }
@ -138,7 +138,7 @@ namespace <#= Generator.Namespace #> {
<# PushIndent ("\t\t"); <# PushIndent ("\t\t");
foreach (var prop in Class.Properties) { foreach (var prop in Class.Properties) {
var propName = CSharpLanguage.SafeIdentifier (prop.Name); var propName = CSharpLanguage.SafeIdentifier (prop.Name);
var type = CSharpLanguage.TypeName (prop.Type, Context.Wrapper | Context.Return); var type = CSharpLanguage.TypeName (Generator.CppTypeToManaged (prop.Type), Context.Wrapper | Context.Return);
Write (CurrentIndent + "public "); Write (CurrentIndent + "public ");
@ -288,7 +288,7 @@ if (overrideInitBases || Class.BaseClasses.Count > 1) { #>
<#+ <#+
private void WriteMethodHeader (Method method, string layoutClass, bool isNonPrimaryOverride, bool @protected) private void WriteMethodHeader (Method method, string layoutClass, bool isNonPrimaryOverride, bool @protected)
{ {
var returnType = CSharpLanguage.TypeName (method.ReturnType, Context.Wrapper | Context.Return); var returnType = CSharpLanguage.TypeName (Generator.CppTypeToManaged (method.ReturnType), Context.Wrapper | Context.Return);
if (!isNonPrimaryOverride && method.IsVirtual) if (!isNonPrimaryOverride && method.IsVirtual)
WriteLine ("[OverrideNative (\"{0}\")]", method.Name); WriteLine ("[OverrideNative (\"{0}\")]", method.Name);
@ -328,7 +328,7 @@ private void WriteParameters (IList<Parameter> parameters, bool writeType, bool
if (i != 0) if (i != 0)
Write (", "); Write (", ");
var type = CSharpLanguage.TypeName (parameters [i].Type, Context.Parameter); var type = CSharpLanguage.TypeName (Generator.CppTypeToManaged (parameters [i].Type), Context.Parameter);
if (writeAttributes) { if (writeAttributes) {
var mangleAs = parameters [i].Type.ToString (); var mangleAs = parameters [i].Type.ToString ();

5
src/generator/Templates/CSharp/CSharpLanguage.cs

@ -27,11 +27,6 @@ namespace Templates {
return keywords.Contains (proposedName)? "@" + proposedName : proposedName; return keywords.Contains (proposedName)? "@" + proposedName : proposedName;
} }
public static string TypeName (CppType t, Context context)
{
return TypeName (Generator.CppTypeToManaged (t), context);
}
public static string TypeName (string str, Context context) public static string TypeName (string str, Context context)
{ {
switch (str) { switch (str) {

1
src/generator/generator.csproj

@ -71,6 +71,7 @@
<Compile Include="Access.cs" /> <Compile Include="Access.cs" />
<Compile Include="Templates\CSharp\CSharpLanguage.cs" /> <Compile Include="Templates\CSharp\CSharpLanguage.cs" />
<Compile Include="Templates\Context.cs" /> <Compile Include="Templates\Context.cs" />
<Compile Include="Filter.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System"> <Reference Include="System">

Loading…
Cancel
Save