From 5d599a4494f85a7d561b0ff0d0b2d4011dbf7a12 Mon Sep 17 00:00:00 2001 From: "alexander.corrado" Date: Mon, 5 Jul 2010 22:27:56 +0000 Subject: [PATCH] New C++ type abstraction, CppType. Will parse C++ type declaration strings, map managed -> C++ type, and canonicalize different declarations that equate to the same type. Reworked ItaniumAbi to use new CppType for name mangling. git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@68 a470b8cb-0e6f-1642-1b45-71e107334c4b --- CPPInterop.sln | 11 +- Mono.VisualC.Interop/ABI/CppAbi.cs | 4 +- Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs | 113 ++-- Mono.VisualC.Interop/ABI/VTableManaged.cs | 2 +- Mono.VisualC.Interop/Attributes.cs | 57 +- Mono.VisualC.Interop/CppType.cs | 257 +++++++++ Mono.VisualC.Interop/IEnumerableTransform.cs | 495 ++++++++++++++++++ .../Mono.VisualC.Interop.csproj | 2 + Mono.VisualC.Interop/Util.cs | 9 +- QtBindings/Core/QCoreApplication.cs | 6 +- QtBindings/Core/QString.cs | 6 +- QtBindings/Gui/QApplication.cs | 6 +- QtBindings/Gui/QPushButton.cs | 3 +- QtBindings/Gui/QWidget.cs | 2 +- QtBindings/Libs.cs | 11 +- 15 files changed, 859 insertions(+), 125 deletions(-) create mode 100644 Mono.VisualC.Interop/CppType.cs create mode 100644 Mono.VisualC.Interop/IEnumerableTransform.cs diff --git a/CPPInterop.sln b/CPPInterop.sln index 19d36aec..b7502b82 100644 --- a/CPPInterop.sln +++ b/CPPInterop.sln @@ -42,16 +42,23 @@ Global StartupItem = Mono.VisualC.Interop\Mono.VisualC.Interop.csproj Policies = $0 $0.TextStylePolicy = $1 - $1.TabWidth = 8 $1.NoTabsAfterNonTabs = True $1.RemoveTrailingWhitespace = True - $1.inheritsSet = VisualStudio + $1.inheritsSet = Mono $1.inheritsScope = text/plain $1.scope = text/x-csharp $0.CSharpFormattingPolicy = $2 + $2.NamespaceBraceStyle = EndOfLine + $2.ClassBraceStyle = EndOfLine + $2.InterfaceBraceStyle = EndOfLine + $2.StructBraceStyle = EndOfLine + $2.EnumBraceStyle = EndOfLine $2.inheritsSet = Mono $2.inheritsScope = text/x-csharp $2.scope = text/x-csharp + $0.StandardHeader = $3 + $3.Text = + $3.inheritsSet = Apache2License name = CPPInterop EndGlobalSection EndGlobal diff --git a/Mono.VisualC.Interop/ABI/CppAbi.cs b/Mono.VisualC.Interop/ABI/CppAbi.cs index c2dd448d..7fe998fd 100644 --- a/Mono.VisualC.Interop/ABI/CppAbi.cs +++ b/Mono.VisualC.Interop/ABI/CppAbi.cs @@ -454,8 +454,8 @@ namespace Mono.VisualC.Interop.ABI { Label bail = il.DefineLabel (); il.Emit (OpCodes.Ldloca_S, cppInstancePtr); - //il.Emit (OpCodes.Dup); - //il.Emit (OpCodes.Brfalse_S, bail); + il.Emit (OpCodes.Brfalse_S, bail); + il.Emit (OpCodes.Ldloca_S, cppInstancePtr); il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ()); il.Emit (OpCodes.Brfalse_S, bail); diff --git a/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs b/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs index fa3fa91f..d2cda526 100644 --- a/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs +++ b/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs @@ -8,8 +8,10 @@ // using System; +using System.Linq; using System.Text; using System.Reflection; +using System.Collections.Generic; using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { @@ -20,92 +22,83 @@ namespace Mono.VisualC.Interop.ABI { } public override CallingConvention DefaultCallingConvention { - get { - return CallingConvention.Cdecl; - } + get { return CallingConvention.Cdecl; } } public override string GetMangledMethodName (MethodInfo methodInfo) { string methodName = methodInfo.Name; MethodType methodType = GetMethodType (methodInfo); - ParameterInfo[] parameters = methodInfo.GetParameters (); + ParameterInfo [] parameters = methodInfo.GetParameters (); StringBuilder nm = new StringBuilder ("_ZN", 30); nm.Append (class_name.Length).Append (class_name); switch (methodType) { + case MethodType.NativeCtor: + nm.Append ("C1"); + break; - case MethodType.NativeCtor: - nm.Append ("C1"); - break; - - case MethodType.NativeDtor: - nm.Append ("D1"); - break; - - default: - nm.Append (methodName.Length).Append (methodName); - break; + case MethodType.NativeDtor: + nm.Append ("D1"); + break; + default: + nm.Append (methodName.Length).Append (methodName); + break; } nm.Append ("E"); - int argStart = (Modifiers.IsStatic (methodInfo)? 0 : 1); - if (parameters.Length == argStart) { // no args (other than C++ "this" object) + if (parameters.Length == argStart) // no args (other than C++ "this" object) nm.Append ("v"); - } else for (int i = argStart; i < parameters.Length; i++) { - nm.Append (GetTypeCode (Modifiers.GetMangleInfo (parameters[i]))); - } + else + for (int i = argStart; i < parameters.Length; i++) + nm.Append (GetTypeCode (Modifiers.GetMangleType (parameters[i]))); return nm.ToString (); } - protected virtual string GetTypeCode(MangleAsAttribute mangleInfo) { - - Type type = mangleInfo.MangleType; - Type element = type; - bool cppObj = typeof (ICppObject).IsAssignableFrom (element); - - StringBuilder code = new StringBuilder (); - - if (type.IsArray) - { - code.Append ("P"); - element = type.GetElementType (); - } - - if (type.IsByRef) - { - code.Append ("R"); - element = type.GetElementType (); - } - else - if (mangleInfo.Modifiers == CppModifiers.PointerToConst) - code.Append ("PK"); - else - if (cppObj || mangleInfo.Modifiers == CppModifiers.Pointer || mangleInfo.Modifiers == CppModifiers.ConstPointer) - code.Append ("P"); - - if (element.Equals (typeof (string))) - code.Append ("P"); - - if (mangleInfo.Modifiers == CppModifiers.Const) - code.Append ("K"); - - if (element.Equals (typeof (int))) code.Append ("i"); - else if (element.Equals (typeof (ushort))) code.Append ("t"); - else if (element.Equals (typeof (string))) code.Append ("c"); // char - else if (cppObj || element.StructLayoutAttribute.Value != LayoutKind.Auto) { - code.Append(element.Name.Length); - code.Append(element.Name); - } - else throw new NotSupportedException ("Unsupported parameter type: " + type.ToString ()); + public virtual string GetTypeCode (CppType mangleType) + { + CppTypes element = mangleType.ElementType; + IEnumerable modifiers = mangleType.Modifiers; + + StringBuilder code = new StringBuilder (); + + var modifierCode = modifiers.Reverse ().Transform ( + For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Array).Emit ("P"), + For.AnyInputIn (CppModifiers.Reference).Emit ("R"), + + Choose.TopOne ( + For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference).FollowedBy ().AllInputsIn (CppModifiers.Volatile, CppModifiers.Const).InAnyOrder ().Emit ("VK"), + For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference).FollowedBy ().AnyInputIn(CppModifiers.Volatile).Emit ("V"), + For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference).FollowedBy ().AnyInputIn(CppModifiers.Const).Emit ("K") + ) + ); + code.Append (string.Join(string.Empty, modifierCode.ToArray ())); + + switch (element) { + case CppTypes.Int: + code.Append (modifiers.Transform ( + For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder ().Emit ('t') + ).DefaultIfEmpty ('i').ToArray ()); + break; + case CppTypes.Char: + code.Append ('c'); + break; + case CppTypes.Class: + code.Append(mangleType.ElementTypeName.Length); + code.Append(mangleType.ElementTypeName); + break; + + } return code.ToString (); } + + } } \ No newline at end of file diff --git a/Mono.VisualC.Interop/ABI/VTableManaged.cs b/Mono.VisualC.Interop/ABI/VTableManaged.cs index 76f1bd7e..38af94fc 100644 --- a/Mono.VisualC.Interop/ABI/VTableManaged.cs +++ b/Mono.VisualC.Interop/ABI/VTableManaged.cs @@ -56,7 +56,7 @@ namespace Mono.VisualC.Interop.ABI { callsite.Emit (OpCodes.Throw); callsite.MarkLabel (notNull); - return delegateType.GetMethod ("Invoke"); + return Util.GetMethodInfoForDelegate (delegateType); } diff --git a/Mono.VisualC.Interop/Attributes.cs b/Mono.VisualC.Interop/Attributes.cs index ef39eac2..ece85bbc 100644 --- a/Mono.VisualC.Interop/Attributes.cs +++ b/Mono.VisualC.Interop/Attributes.cs @@ -18,48 +18,28 @@ namespace Mono.VisualC.Interop { [AttributeUsage (AttributeTargets.Method)] public class StaticAttribute : Attribute {} - [AttributeUsage (AttributeTargets.Parameter)] - public class ConstAttribute : Attribute {} - [AttributeUsage (AttributeTargets.Method)] public class OverrideNativeAttribute : Attribute {} - [AttributeUsage (AttributeTargets.Parameter)] + [AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)] public class MangleAsAttribute : Attribute { - public CppModifiers Modifiers { get; set; } - public Type MangleType { get; private set; } + public CppType MangleType { get; private set; } - public bool ByRef { - get { return MangleType.IsByRef; } - set { - if (!MangleType.IsByRef && value) - MangleType = MangleType.MakeByRefType (); - else if (MangleType.IsByRef && !value) - MangleType = MangleType.GetElementType (); - } - } - public MangleAsAttribute (Type mangleType) + public MangleAsAttribute (CppType mangleType) { - this.Modifiers = CppModifiers.None; this.MangleType = mangleType; } public MangleAsAttribute (string mangleTypeStr) { - this.Modifiers = CppModifiers.None; - this.MangleType = Type.GetType (mangleTypeStr); + this.MangleType = new CppType (mangleTypeStr); } + public MangleAsAttribute (params object[] cppTypeSpec) + { + this.MangleType = new CppType (cppTypeSpec); + } } - public enum CppModifiers { - None, - Const, - Pointer, - PointerToConst, - ConstPointer, - ConstPointerToConst - } - - public static class Modifiers { + public static class Modifiers { public static bool IsVirtual (MethodInfo method) { @@ -71,17 +51,22 @@ namespace Mono.VisualC.Interop { return method.IsDefined (typeof (StaticAttribute), false); } - public static MangleAsAttribute GetMangleInfo (ParameterInfo param) + public static CppType GetMangleType (ParameterInfo param) { + CppType mangleType = new CppType (); MangleAsAttribute maa = (MangleAsAttribute)param.GetCustomAttributes (typeof (MangleAsAttribute), false).FirstOrDefault (); - bool isConst = param.IsDefined (typeof (ConstAttribute), false); - if (maa == null) - maa = new MangleAsAttribute (param.ParameterType); + if (maa != null) + mangleType = maa.MangleType; - if (isConst) - maa.Modifiers = CppModifiers.Const; + // this means that only CppModifiers were applied .. apply CppType from managed parameter type + if (mangleType.ElementType == CppTypes.Unknown && mangleType.ElementTypeName == null) + mangleType.Apply (CppType.ForManagedType (param.ParameterType)); + else if (mangleType.ElementType == CppTypes.Unknown) + // FIXME: otherwise, we just assume it's CppTypes.Class for now. + mangleType.ElementType = CppTypes.Class; - return maa; + return mangleType; } } + } diff --git a/Mono.VisualC.Interop/CppType.cs b/Mono.VisualC.Interop/CppType.cs new file mode 100644 index 00000000..9da1475f --- /dev/null +++ b/Mono.VisualC.Interop/CppType.cs @@ -0,0 +1,257 @@ +// +// Mono.VisualC.Interop.CppType.cs: Abstracts a C++ type declaration +// +// Author: +// Alexander Corrado (alexander.corrado@gmail.com) +// +// Copyright (C) 2010 Alexander Corrado +// + +using System; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Reflection; +using System.Collections.Generic; + +namespace Mono.VisualC.Interop { + + public enum CppModifiers { + Const, + Pointer, + Array, + Reference, + Volatile, + // --- + Signed, + Unsigned, + Short, + Long + } + public enum CppTypes { + Unknown, + Class, + Struct, + Enum, + Union, + Void, + Bool, + Char, + Int, + Float, + Double + } + + public struct CppType { + + public static Dictionary Tokenize = new Dictionary () { + { "\\*", CppModifiers.Pointer }, + { "\\[\\s*\\]", CppModifiers.Array }, + { "\\&", CppModifiers.Reference } + }; + + /* + public static Dictionary Stringify = new Dictionary () { + { CppModifiers.Pointer, "*" }, + { CppModifiers.Array, "[]" }, + { CppModifiers.Reference, "&" } + }; + */ + + // FIXME: Passing these as delegates allows for the flexibility of doing processing on the + // type (i.e. to correctly mangle the function pointer arguments if the managed type is a delegate), + // however this does not make it very easy to override the default mappings at runtime. + public static List> ManagedTypeMap = new List> () { + (t) => { return typeof (void).Equals (t) ? CppTypes.Void : CppTypes.Unknown; }, + (t) => { return typeof (bool).Equals (t) ? CppTypes.Bool : CppTypes.Unknown; }, + (t) => { return typeof (char).Equals (t) ? CppTypes.Char : CppTypes.Unknown; }, + (t) => { return typeof (int).Equals (t) ? CppTypes.Int : CppTypes.Unknown; }, + (t) => { return typeof (float).Equals (t) ? CppTypes.Float : CppTypes.Unknown; }, + (t) => { return typeof (double).Equals (t)? CppTypes.Double : CppTypes.Unknown; }, + + (t) => { return typeof (short).Equals (t) ? new CppType (CppModifiers.Short, CppTypes.Int) : CppTypes.Unknown; }, + (t) => { return typeof (long).Equals (t) ? new CppType (CppModifiers.Long, CppTypes.Int) : CppTypes.Unknown; }, + + // strings mangle as "const char*" by default + (t) => { return typeof (string).Equals (t)? new CppType (CppModifiers.Const, CppTypes.Char, CppModifiers.Pointer) : CppTypes.Unknown; }, + // StringBuilder gets "char*" + (t) => { return typeof (StringBuilder).Equals (t)? new CppType (CppTypes.Char, CppModifiers.Pointer) : CppTypes.Unknown; }, + + // delegate types get special treatment + (t) => { return typeof (Delegate).IsAssignableFrom (t)? CppType.ForDelegate (t) : CppTypes.Unknown; }, + + // ... and of course ICppObjects do too! + // FIXME: We assume c++ class not struct. There should probably be an attribute + // we can apply to managed wrappers to indicate if the underlying C++ type is actually declared struct + (t) => { return typeof (ICppObject).IsAssignableFrom (t)? new CppType (CppTypes.Class, t.Name, CppModifiers.Pointer) : CppTypes.Unknown; }, + + // convert managed type modifiers to C++ type modifiers like so: + // ref types to C++ references + // pointer types to C++ pointers + // array types to C++ arrays + (t) => { + if (t.GetElementType () == null) return CppTypes.Unknown; + CppType cppType = CppType.ForManagedType (t.GetElementType ()); + if (t.IsByRef) cppType.Modifiers.Add (CppModifiers.Reference); + if (t.IsPointer) cppType.Modifiers.Add (CppModifiers.Pointer); + if (t.IsArray) cppType.Modifiers.Add (CppModifiers.Array); + return cppType; + } + }; + + public CppTypes ElementType { get; set; } + + // if the ElementType is Union, Struct, Class, or Enum + // this will contain the name of said type + public string ElementTypeName { get; set; } + + public List Modifiers { get; private set; } + + // here, you can pass in things like "const char*" or "const Foo * const" + // DISCLAIMER: this is really just for convenience for now, and is not meant to be able + // to parse even moderately complex C++ type declarations. + public CppType (string type) : this (Regex.Split (type, "\\s+(?!\\])")) + { + } + + public CppType (params object[] cppTypeSpec) + { + ElementType = CppTypes.Unknown; + ElementTypeName = null; + + Modifiers = new List (); + + Parse (cppTypeSpec); + } + + private void Parse (object [] modifiers) + { + for (int i = 0; i < modifiers.Length; i++) { + + if (modifiers [i] is CppModifiers) { + Modifiers.Add ((CppModifiers)modifiers [i]); + continue; + } + + string strModifier = modifiers [i] as string; + if (strModifier != null) { + // FIXME: Use Enum.TryParse here if we decide to make this NET_4_0 only + try { + Modifiers.Add ((CppModifiers)Enum.Parse (typeof (CppModifiers), strModifier, true)); + continue; + } catch { } + } + + // must be a type name + ParseType (modifiers [i]); + } + } + + private void ParseType (object type) + { + if (type is CppTypes) { + ElementType = (CppTypes)type; + ElementTypeName = null; + return; + } + + string strType = type as string; + if (strType != null) { + // strip tokens off type name + foreach (var token in Tokenize) { + foreach (var match in Regex.Matches (strType, token.Key)) + Modifiers.Add (token.Value); + + strType = Regex.Replace (strType, token.Key, string.Empty); + } + + // FIXME: Use Enum.TryParse here if we decide to make this NET_4_0 only + try { + CppTypes parsed = (CppTypes)Enum.Parse (typeof (CppTypes), strType, true); + ElementType = parsed; + ElementTypeName = null; + return; + } catch { } + + // it's the element type name + strType = strType.Trim (); + if (!strType.Equals (string.Empty)) + ElementTypeName = strType; + return; + } + + + Type managedType = type as Type; + if (managedType != null) { + CppType mapped = CppType.ForManagedType (managedType); + Apply (mapped); + return; + } + } + + // Applies the element type of the passed instance + // and combines its modifiers into this instance. + // Use when THIS instance may have attributes you want, + // but want the element type of the passed instance. + public void Apply (CppType type) + { + ElementType = type.ElementType; + ElementTypeName = type.ElementTypeName; + if (Modifiers == null) Modifiers = new List (); + + List oldModifiers = Modifiers; + Modifiers = type.Modifiers; + Modifiers.AddRange (oldModifiers); + } + + /* + public override string ToString () + { + StringBuilder cppTypeString = new StringBuilder (); + + cppTypeString.Append (Enum.GetName (typeof (CppTypes), ElementType).ToLower ()); + + if (ElementTypeName != null) + cppTypeString.Append (" ").Append (ElementTypeName); + + foreach (var modifier in Modifiers) { + string stringified; + if (!Stringify.TryGetValue (modifier, out stringified)) + stringified = Enum.GetName (typeof (CppModifiers), modifier).ToLower (); + + cppTypeString.Append (" ").Append (stringified); + } + + return cppTypeString.ToString (); + } + */ + + public static CppType ForManagedType (Type type) + { + + var mappedType = (from checkType in ManagedTypeMap + where checkType (type).ElementType != CppTypes.Unknown + select checkType (type)).FirstOrDefault (); + + if (mappedType.Modifiers == null) + mappedType.Modifiers = new List (); + + return mappedType; + } + + public static CppType ForDelegate (Type delType) + { + if (!typeof (Delegate).IsAssignableFrom (delType)) + throw new ArgumentException ("Argument must be a delegate type"); + + throw new NotImplementedException (); + } + + + + public static implicit operator CppType (CppTypes type) { + return new CppType (type); + } + } +} + diff --git a/Mono.VisualC.Interop/IEnumerableTransform.cs b/Mono.VisualC.Interop/IEnumerableTransform.cs new file mode 100644 index 00000000..07273943 --- /dev/null +++ b/Mono.VisualC.Interop/IEnumerableTransform.cs @@ -0,0 +1,495 @@ +using System; +using System.Linq; +using System.Collections; +using System.Collections.Generic; + +namespace Mono.VisualC.Interop { + + + public delegate bool EmitterFunc (InputData input, out TOut output); + + public struct InputData { + public IEnumerable AllValues; + public LookaheadEnumerator Enumerator; + public List> MatchedRules; + public InputData (IEnumerable input, LookaheadEnumerator enumerator) + { + this.AllValues = input; + this.Enumerator = enumerator; + this.MatchedRules = new List> (); + } + + public TIn Value { + get { return Enumerator.Current; } + } + } + + #region Rules + public interface IRule { + bool SatisfiedBy (InputData input); + } + + // yields all inputs indescriminately + public class AnyRule : IRule { + public AnyRule () + { + } + public bool SatisfiedBy (InputData input) + { + return true; + } + } + + // yields all inputs that haven't satisfied + // any other rule + public class UnmatchedRule : IRule { + public UnmatchedRule () + { + } + public bool SatisfiedBy (InputData input) + { + return !input.MatchedRules.Any (); + } + } + + // yields input if it hasn't been satisfied before + public class FirstRule : IRule { + protected bool triggered = false; + public FirstRule () + { + } + public bool SatisfiedBy (InputData input) + { + if (!triggered) { + triggered = true; + return true; + } + return false; + } + } + + // yields input if it is the last that would satisfy + // all its matched rules + public class LastRule : IRule { + public LastRule () + { + } + public bool SatisfiedBy (InputData input) + { + IEnumerator item = input.Enumerator; + + while (item.MoveNext ()) { + foreach (var prevRule in input.MatchedRules) { + if (prevRule.SatisfiedBy (input)) + return false; + } + } + + return true; + } + } + + // yields all inputs found in the specified set + public class InSetRule : IRule { + protected IEnumerable conditions; + + public InSetRule (params TIn [] conditions) + { + this.conditions = conditions; + } + public InSetRule (IEnumerable conditions) + { + this.conditions = conditions; + } + public bool SatisfiedBy (InputData input) + { + return conditions.Contains (input.Value); + } + } + + // is satisfied by any of the specified items as long the + // item appears adjacent with all the other items + public class AnyOrderRule : IRule { + protected IEnumerable conditions; + + protected Queue verifiedItems = new Queue (); + protected bool verified = false; + + + public AnyOrderRule (params TIn [] conditions) + { + this.conditions = conditions; + } + public AnyOrderRule (IEnumerable conditions) + { + this.conditions = conditions; + } + public bool SatisfiedBy (InputData inputData) + { + if (verified && verifiedItems.Count > 0) { + verifiedItems.Dequeue (); + return false; + } else + verified = false; + + IEnumerator input = inputData.Enumerator; + + while (conditions.Contains (input.Current) && !verifiedItems.Contains (input.Current)) { + verifiedItems.Enqueue (input.Current); + if (!input.MoveNext ()) break; + } + + if (verifiedItems.Count == conditions.Count ()) { + verified = true; + verifiedItems.Dequeue (); + return true; + } else + verifiedItems.Clear (); + + return false; + } + } + + public class InOrderRule : IRule { + protected IEnumerable> conditions; + + protected bool verified = false; + protected int verifiedCount = 0; + + public InOrderRule (params IRule [] conditions) + { + this.conditions = conditions; + } + public InOrderRule (IEnumerable> conditions) + { + this.conditions = conditions; + } + public bool SatisfiedBy (InputData inputData) + { + if (verified && verifiedCount > 0) { + verifiedCount--; + return false; + } else + verified = false; + + IEnumerator> condition = conditions.GetEnumerator (); + IEnumerator input = inputData.Enumerator; + + while (condition.MoveNext () && condition.Current.SatisfiedBy (inputData)) { + verifiedCount++; + if (!input.MoveNext ()) break; + } + if (verifiedCount == conditions.Count ()) { + verified = true; + verifiedCount--; + return true; + } else + verifiedCount = 0; + + return false; + } + } + + // yields all inputs that match all specified rules + public class AndRule : IRule { + protected IEnumerable> rules; + + public AndRule (IEnumerable> rules) + { + this.rules = rules; + } + public AndRule (params IRule[] rules) + { + this.rules = rules; + } + public bool SatisfiedBy (InputData input) + { + foreach (var rule in rules) { + if (!rule.SatisfiedBy (input)) + return false; + + input.MatchedRules.Add (rule); + } + return true; + } + } + + // yields all inputs that match any specified rules + public class OrRule : IRule { + protected IEnumerable> rules; + + public OrRule (IEnumerable> rules) + { + this.rules = rules; + } + public OrRule (params IRule[] rules) + { + this.rules = rules; + } + public bool SatisfiedBy (InputData input) + { + bool satisfied = false; + foreach (var rule in rules) { + if (!rule.SatisfiedBy (input)) + continue; + + satisfied = true; + input.MatchedRules.Add (rule); + } + + return satisfied; + } + } + #endregion + + // the base point for building up rules + // All rules start For... + public static class For { + + public static IRule AnyInputIn (params TIn [] input) + { + return new InSetRule (input); + } + public static IRule AnyInputIn (IEnumerable input) + { + return new InSetRule (input); + } + + public static SequenceQualifier AllInputsIn (params TIn [] input) + { + return new SequenceQualifier (input, null); + } + public static SequenceQualifier AllInputsIn (IEnumerable input) + { + return new SequenceQualifier (input, null); + } + + public static RuleCompound First () + { + return new RuleCompound ((subsequentRules) => { + return new AndRule (subsequentRules, new FirstRule ()); + }); + } + + public static RuleCompound Last () + { + return new RuleCompound ((subsequentRules) => { + return new AndRule (subsequentRules, new LastRule ()); + }); + } + + public static IRule AnyInput () + { + return new AnyRule (); + } + public static IRule UnmatchedInput () + { + return new UnmatchedRule (); + } + } + + public class RuleCompound { + protected Func,IRule> additionalRuleCallback; + + public RuleCompound (Func,IRule> additionalRuleCallback) + { + this.additionalRuleCallback = additionalRuleCallback; + } + + public SequenceQualifier AllInputsIn (params TIn [] input) + { + return new SequenceQualifier (input, additionalRuleCallback); + } + public SequenceQualifier AllInputsIn (IEnumerable input) + { + return new SequenceQualifier (input, additionalRuleCallback); + } + + public IRule AnyInputIn (params TIn[] input) + { + return additionalRuleCallback(new InSetRule (input)); + } + public IRule AnyInputIn (IEnumerable input) + { + return additionalRuleCallback(new InSetRule (input)); + } + public IRule AnyInput () + { + return additionalRuleCallback(new AnyRule ()); + } + } + + public class SequenceQualifier { + protected IEnumerable sequence; + protected Func, IRule> additionalRuleCallback; + + public SequenceQualifier (IEnumerable sequence, Func, IRule> additionalRuleCallback) + { + this.sequence = sequence; + this.additionalRuleCallback = additionalRuleCallback ?? (rul => rul); + } + + public IRule InThatOrder () + { + return additionalRuleCallback (new InOrderRule (sequence.Select (tin => (IRule)new InSetRule (tin)))); + } + + public IRule InAnyOrder () + { + return additionalRuleCallback (new AnyOrderRule (sequence)); + } + } + + public static class Choose { + + public static EmitterFunc TopOne (params EmitterFunc [] rules) + { + return delegate (InputData input, out TOut output) { + output = default (TOut); + foreach (var rule in rules) { + if (rule (input, out output)) + return true; + + input.Enumerator.Validate (); + } + return false; + }; + } + } + + public class LookaheadEnumerator : IEnumerator { + private IEnumerable wrappedEnumerable; + private IEnumerator wrappedEnumerator; + + private int position; + private bool invalidated; + + public LookaheadEnumerator (IEnumerable enumerable, int position) + { + this.wrappedEnumerable = enumerable; + this.position = position; + this.invalidated = true; + Validate (); + } + + public void Reset () + { + invalidated = true; + wrappedEnumerator.Reset (); + } + + public void Validate () + { + if (!invalidated) return; + wrappedEnumerator = wrappedEnumerable.GetEnumerator (); + for (int i = 0; i < position; i++) + wrappedEnumerator.MoveNext (); + + invalidated = false; + } + + public bool ValidMoveNext () + { + Validate (); + position++; + return wrappedEnumerator.MoveNext (); + } + + public bool MoveNext () + { + invalidated = true; + return wrappedEnumerator.MoveNext (); + } + + public bool Invalidated { + get { return invalidated; } + } + + public T Current { + get { return wrappedEnumerator.Current; } + } + object IEnumerator.Current { + get { return this.Current; } + } + public void Dispose () + { + } + } + + public static class EnumerableSequenceExtensions { + + // Transforms an IEnumerable into another by specific rules. + + public static IEnumerable Transform (this IEnumerable input, params EmitterFunc [] rules) + { + LookaheadEnumerator enumerator = new LookaheadEnumerator (input, 0); + + while (enumerator.ValidMoveNext ()) { + + InputData inputData = new InputData (input, enumerator); + foreach (var rule in rules) { + TOut output; + if (rule (inputData, out output)) + yield return output; + + enumerator.Validate (); + } + } + + } + + public static IRule And (this IRule previousRules, IRule parentheticalRules) + { + return new AndRule (previousRules, parentheticalRules); + } + public static RuleCompound And (this IRule previousRules) + { + return new RuleCompound ((subsequentRules) => { + return And (previousRules, subsequentRules); + }); + } + + public static IRule Or (this IRule previousRules, IRule parentheticalRules) + { + return new OrRule (previousRules, parentheticalRules); + } + public static RuleCompound Or (this IRule previousRules) + { + return new RuleCompound ((subsequentRules) => { + return Or (previousRules, subsequentRules); + }); + } + + + public static IRule FollowedBy (this IRule previousRules, IRule parentheticalRules) + { + return new InOrderRule (previousRules, parentheticalRules); + } + public static RuleCompound FollowedBy (this IRule previousRules) + { + return new RuleCompound ((subsequentRules) => { + return FollowedBy (previousRules, subsequentRules); + }); + } + + public static EmitterFunc Emit (this IRule rule, Func result) + { + return delegate (InputData input, out TOut output) { + output = default (TOut); + TIn value = input.Value; + if (rule.SatisfiedBy (input)) { + input.MatchedRules.Add (rule); + output = result (value); + return true; + } + return false; + }; + } + public static EmitterFunc Emit (this IRule rule, TOut result) + { + return Emit (rule, (input) => result); + } + + } +} + diff --git a/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj b/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj index db94bd93..4dbdf0a2 100644 --- a/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj +++ b/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj @@ -50,6 +50,8 @@ + + diff --git a/Mono.VisualC.Interop/Util.cs b/Mono.VisualC.Interop/Util.cs index 303c0ccb..e6986d21 100644 --- a/Mono.VisualC.Interop/Util.cs +++ b/Mono.VisualC.Interop/Util.cs @@ -1,11 +1,12 @@ using System; using System.Linq; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Reflection; using System.Reflection.Emit; namespace Mono.VisualC.Interop { - public static class Util { + internal static class Util { public static MethodInfo GetMethodInfoForDelegate (Type delType) { @@ -37,12 +38,6 @@ namespace Mono.VisualC.Interop { return del.CreateType (); } - public static Delegate GetDelegateForMethodInfo (ModuleBuilder mod, MethodInfo targetMethod) - { - Type delType = GetDelegateTypeForMethodInfo (mod, targetMethod); - return Delegate.CreateDelegate (delType, targetMethod); - } - public static Type[] GetDelegateParameterTypes (Type delType) { MethodInfo invoke = GetMethodInfoForDelegate (delType); diff --git a/QtBindings/Core/QCoreApplication.cs b/QtBindings/Core/QCoreApplication.cs index 9ccc5973..d64880c5 100644 --- a/QtBindings/Core/QCoreApplication.cs +++ b/QtBindings/Core/QCoreApplication.cs @@ -6,10 +6,10 @@ namespace Qt.Core { public class QCoreApplication : QObject { #region Sync with qcoreapplication.h // C++ interface - protected interface IQCoreApplication : ICppClassOverridable, Base { + public interface IQCoreApplication : ICppClassOverridable, Base { // ... - void QCoreApplication (CppInstancePtr @this, [MangleAs ("System.Int32&")] IntPtr argc, - [MangleAs (typeof (string[]))] IntPtr argv); + void QCoreApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc, + [MangleAs ("char**")] IntPtr argv); // ... [Static] int exec (); // ... diff --git a/QtBindings/Core/QString.cs b/QtBindings/Core/QString.cs index b13d22b6..5a945dcd 100644 --- a/QtBindings/Core/QString.cs +++ b/QtBindings/Core/QString.cs @@ -9,12 +9,8 @@ namespace Qt.Core { public unsafe struct QString { #region Sync with qstring.h public interface IQString : ICppClass { - void QString(ref QString @this, - [MangleAs (typeof (QChar), Modifiers=CppModifiers.PointerToConst)] - IntPtr unicode, int size); + void QString(ref QString @this, [MangleAs ("const QChar*")] IntPtr unicode, int size); } - [StructLayout (LayoutKind.Sequential)] - private struct QChar {} [StructLayout (LayoutKind.Sequential)] public struct Data { diff --git a/QtBindings/Gui/QApplication.cs b/QtBindings/Gui/QApplication.cs index c78104d7..d4df5418 100644 --- a/QtBindings/Gui/QApplication.cs +++ b/QtBindings/Gui/QApplication.cs @@ -8,10 +8,10 @@ namespace Qt.Gui { public class QApplication : QCoreApplication { #region Sync with qapplication.h // C++ interface - protected interface IQApplication : ICppClassOverridable, Base { + public interface IQApplication : ICppClassOverridable, Base { // ... - void QApplication (CppInstancePtr @this, [MangleAs ("System.Int32&")] IntPtr argc, - [MangleAs (typeof (string[]))] IntPtr argv, int version); + void QApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc, + [MangleAs ("char**")] IntPtr argv, int version); // ... [Virtual] bool macEventFilter(CppInstancePtr @this, IntPtr eventHandlerCallRef, IntPtr eventRef); // ... diff --git a/QtBindings/Gui/QPushButton.cs b/QtBindings/Gui/QPushButton.cs index 3c812381..d9b84f54 100644 --- a/QtBindings/Gui/QPushButton.cs +++ b/QtBindings/Gui/QPushButton.cs @@ -8,8 +8,7 @@ namespace Qt.Gui { // C++ interface public interface IQPushButton : ICppClassOverridable, Base { // ... - void QPushButton (CppInstancePtr @this, [Const] ref QString text, - QWidget parent); + void QPushButton (CppInstancePtr @this, [MangleAs ("const QString &")] ref QString text, QWidget parent); // ... } // C++ fields diff --git a/QtBindings/Gui/QWidget.cs b/QtBindings/Gui/QWidget.cs index 84613e6a..5ea3b37e 100644 --- a/QtBindings/Gui/QWidget.cs +++ b/QtBindings/Gui/QWidget.cs @@ -14,7 +14,7 @@ namespace Qt.Gui { // ... [Virtual] void setVisible (CppInstancePtr @this, bool visible); // ... - void resize (CppInstancePtr @this, [MangleAs (typeof (QSize), ByRef=true, Modifiers=CppModifiers.Const)] ref QSize size); + void resize (CppInstancePtr @this, [MangleAs ("const QSize &")] ref QSize size); // ... [Virtual] /*QSize*/ int sizeHint (CppInstancePtr @this); [Virtual] /*QSize*/ int minimumSizeHint (CppInstancePtr @this); diff --git a/QtBindings/Libs.cs b/QtBindings/Libs.cs index c16eb338..a2eaec92 100644 --- a/QtBindings/Libs.cs +++ b/QtBindings/Libs.cs @@ -10,15 +10,20 @@ namespace Qt { static Libs () { + string lib; CppAbi abi; if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { // for Windows... + lib = "{0}4.dll"; abi = new MsvcAbi (); - else + } else { // for Mac... + lib = "/Library/Frameworks/{0}.framework/Versions/Current/{0}"; abi = new ItaniumAbi (); + } - QtCore = new CppLibrary ("/Library/Frameworks/QtCore.framework/Versions/Current/QtCore", abi); - QtGui = new CppLibrary ("/Library/Frameworks/QtGui.framework/Versions/Current/QtGui", abi); + QtCore = new CppLibrary (string.Format(lib, "QtCore"), abi); + QtGui = new CppLibrary (string.Format(lib, "QtGui"), abi); } } }