Browse Source

Bug fixes. Started implementing MSVC ABI. Small refactorings to support this.

git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@71 a470b8cb-0e6f-1642-1b45-71e107334c4b
pull/1/head
alexander.corrado 16 years ago
parent
commit
49769f8f54
  1. 9
      Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 21
      Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  3. 65
      Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  4. 4
      Mono.VisualC.Interop/ABI/VTable.cs
  5. 4
      Mono.VisualC.Interop/ABI/VTableCOM.cs
  6. 8
      Mono.VisualC.Interop/ABI/VTableManaged.cs
  7. 26
      Mono.VisualC.Interop/Attributes.cs
  8. 30
      Mono.VisualC.Interop/CppType.cs
  9. 221
      Mono.VisualC.Interop/IEnumerableTransform.cs
  10. 7
      Mono.VisualC.Interop/Util.cs

9
Mono.VisualC.Interop/ABI/CppAbi.cs

@ -168,7 +168,7 @@ namespace Mono.VisualC.Interop.ABI {
// The members below must be implemented for a given C++ ABI: // The members below must be implemented for a given C++ ABI:
public abstract string GetMangledMethodName (MethodInfo methodInfo); public abstract string GetMangledMethodName (MethodInfo methodInfo);
public abstract CallingConvention DefaultCallingConvention { get; } public abstract CallingConvention GetCallingConvention (MethodInfo methodInfo);
protected virtual void DefineImplType () protected virtual void DefineImplType ()
{ {
@ -238,7 +238,8 @@ namespace Mono.VisualC.Interop.ABI {
MethodInfo nativeMethod; MethodInfo nativeMethod;
if (Modifiers.IsVirtual (interfaceMethod)) if (Modifiers.IsVirtual (interfaceMethod))
nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, il, vtable_field, nativePtr, index); nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, GetCallingConvention (interfaceMethod),
il, nativePtr, vtable_field, index);
else else
nativeMethod = GetPInvokeForMethod (interfaceMethod); nativeMethod = GetPInvokeForMethod (interfaceMethod);
@ -328,7 +329,7 @@ namespace Mono.VisualC.Interop.ABI {
if (targetMethod == null) if (targetMethod == null)
return null; return null;
Type delegateType = Util.GetDelegateTypeForMethodInfo (impl_module, interfaceMethod); Type delegateType = Util.GetDelegateTypeForMethodInfo (impl_module, interfaceMethod, GetCallingConvention (interfaceMethod));
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true); Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true);
// TODO: According to http://msdn.microsoft.com/en-us/library/w16z8yc4.aspx // TODO: According to http://msdn.microsoft.com/en-us/library/w16z8yc4.aspx
@ -405,7 +406,7 @@ namespace Mono.VisualC.Interop.ABI {
MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", library, entryPoint, MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", library, entryPoint,
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Any, signature.ReturnType, parameterTypes, CallingConventions.Any, signature.ReturnType, parameterTypes,
DefaultCallingConvention, CharSet.Ansi); GetCallingConvention (signature), CharSet.Ansi);
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig); builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
Util.ApplyMethodParameterAttributes (signature, builder, true); Util.ApplyMethodParameterAttributes (signature, builder, true);
return builder; return builder;

21
Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs

@ -21,8 +21,9 @@ namespace Mono.VisualC.Interop.ABI {
{ {
} }
public override CallingConvention DefaultCallingConvention { public override CallingConvention GetCallingConvention (MethodInfo methodInfo)
get { return CallingConvention.Cdecl; } {
return CallingConvention.Cdecl;
} }
public override string GetMangledMethodName (MethodInfo methodInfo) public override string GetMangledMethodName (MethodInfo methodInfo)
@ -48,11 +49,11 @@ namespace Mono.VisualC.Interop.ABI {
break; break;
} }
nm.Append ("E"); nm.Append ('E');
int argStart = (Modifiers.IsStatic (methodInfo)? 0 : 1); 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"); nm.Append ('v');
else else
for (int i = argStart; i < parameters.Length; i++) for (int i = argStart; i < parameters.Length; i++)
nm.Append (GetTypeCode (Modifiers.GetMangleType (parameters[i]))); nm.Append (GetTypeCode (Modifiers.GetMangleType (parameters[i])));
@ -67,14 +68,17 @@ namespace Mono.VisualC.Interop.ABI {
StringBuilder code = new StringBuilder (); StringBuilder code = new StringBuilder ();
var ptrOrRef = For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference);
var modifierCode = modifiers.Reverse ().Transform ( var modifierCode = modifiers.Reverse ().Transform (
For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Array).Emit ("P"), For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Array).Emit ("P"),
For.AnyInputIn (CppModifiers.Reference).Emit ("R"), For.AnyInputIn (CppModifiers.Reference).Emit ("R"),
// Itanium mangled names do not include const or volatile unless
// they modify the type pointed to by pointer or reference.
Choose.TopOne ( Choose.TopOne (
For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference).FollowedBy ().AllInputsIn (CppModifiers.Volatile, CppModifiers.Const).InAnyOrder ().Emit ("VK"), For.AllInputsIn (CppModifiers.Volatile, CppModifiers.Const).InAnyOrder ().After (ptrOrRef).Emit ("VK"),
For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference).FollowedBy ().AnyInputIn(CppModifiers.Volatile).Emit ("V"), For.AnyInputIn(CppModifiers.Volatile).After (ptrOrRef).Emit ("V"),
For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference).FollowedBy ().AnyInputIn(CppModifiers.Const).Emit ("K") For.AnyInputIn(CppModifiers.Const).After (ptrOrRef).Emit ("K")
) )
); );
code.Append (string.Join(string.Empty, modifierCode.ToArray ())); code.Append (string.Join(string.Empty, modifierCode.ToArray ()));
@ -89,6 +93,9 @@ namespace Mono.VisualC.Interop.ABI {
code.Append ('c'); code.Append ('c');
break; break;
case CppTypes.Class: case CppTypes.Class:
case CppTypes.Struct:
case CppTypes.Union:
case CppTypes.Enum:
code.Append(mangleType.ElementTypeName.Length); code.Append(mangleType.ElementTypeName.Length);
code.Append(mangleType.ElementTypeName); code.Append(mangleType.ElementTypeName);
break; break;

65
Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs

@ -12,21 +12,76 @@ using System.Text;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Mono.VisualC.Interop;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
public class MsvcAbi : CppAbi { public class MsvcAbi : CppAbi {
public MsvcAbi () public MsvcAbi ()
{ {
} }
public override CallingConvention DefaultCallingConvention { public override CallingConvention GetCallingConvention (MethodInfo methodInfo)
get { {
throw new System.NotImplementedException (); // FIXME: Varargs methods..?
}
if (Modifiers.IsStatic (methodInfo))
return CallingConvention.Cdecl;
else
return CallingConvention.ThisCall;
} }
public override string GetMangledMethodName (MethodInfo methodInfo) public override string GetMangledMethodName (MethodInfo methodInfo)
{ {
throw new System.NotImplementedException (); string methodName = methodInfo.Name;
MethodType methodType = GetMethodType (methodInfo);
ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("?", 30);
// FIXME: This has to include not only the name of the immediate containing class,
// but also all names of containing classes and namespaces up the hierarchy.
nm.Append (methodName).Append ('@').Append (class_name).Append ("@@");
// function modifiers are a matrix of consecutive uppercase letters
// depending on access type and virtual (far)/static (far)/far modifiers
// first, access type
char funcModifier = 'Q'; // (public)
if (Modifiers.IsProtected (methodInfo))
funcModifier = 'I';
else if (Modifiers.IsPrivate (methodInfo))
funcModifier = 'A';
// now, offset based on other modifiers
if (Modifiers.IsStatic (methodInfo))
funcModifier += 2;
else if (Modifiers.IsVirtual (methodInfo)) // (do we need this?)
funcModifier += 4;
nm.Append (funcModifier);
// FIXME: deal with storage classes for "this" i.e. the "const" in -> int foo () const;
if (!Modifiers.IsStatic (methodInfo))
nm.Append ('A');
switch (GetCallingConvention (methodInfo)) {
case CallingConvention.Cdecl:
nm.Append ('A');
break;
case CallingConvention.ThisCall:
nm.Append ('E');
break;
case CallingConvention.StdCall:
nm.Append ('G');
break;
case CallingConvention.FastCall:
nm.Append ('I');
break;
}
// FIXME: handle const, volatile modifiers on return type
nm.Append ("?A");
} }
} }

4
Mono.VisualC.Interop/ABI/VTable.cs

@ -38,8 +38,8 @@ namespace Mono.VisualC.Interop.ABI {
get { return Marshal.SizeOf (typeof (IntPtr)); } get { return Marshal.SizeOf (typeof (IntPtr)); }
} }
public abstract MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField, public abstract MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention callingConvention, ILGenerator callsite,
LocalBuilder native, int vtableIndex); LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex);
// Subclasses must allocate vtPtr! // Subclasses must allocate vtPtr!
public VTable (Delegate[] overrides) public VTable (Delegate[] overrides)

4
Mono.VisualC.Interop/ABI/VTableCOM.cs

@ -29,8 +29,8 @@ namespace Mono.VisualC.Interop.ABI {
WriteOverrides (0); WriteOverrides (0);
} }
public override MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField, public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention callingConvention, ILGenerator callsite,
LocalBuilder native, int vtableIndex) LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex)
{ {
throw new System.NotImplementedException (); throw new System.NotImplementedException ();
} }

8
Mono.VisualC.Interop/ABI/VTableManaged.cs

@ -27,14 +27,14 @@ namespace Mono.VisualC.Interop.ABI {
WriteOverrides (0); WriteOverrides (0);
} }
public override MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField, public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention callingConvention, ILGenerator callsite,
LocalBuilder native, int vtableIndex) LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex)
{ {
Type delegateType; Type delegateType;
if (overrides [vtableIndex] != null) if (overrides [vtableIndex] != null)
delegateType = overrides [vtableIndex].GetType (); delegateType = overrides [vtableIndex].GetType ();
else else
delegateType = Util.GetDelegateTypeForMethodInfo (implModule, target); delegateType = Util.GetDelegateTypeForMethodInfo (implModule, target, callingConvention);
MethodInfo getDelegate = typeof (VTableManaged).GetMethod ("GetDelegateForNative").MakeGenericMethod (delegateType); MethodInfo getDelegate = typeof (VTableManaged).GetMethod ("GetDelegateForNative").MakeGenericMethod (delegateType);
@ -42,7 +42,7 @@ namespace Mono.VisualC.Interop.ABI {
callsite.Emit (OpCodes.Ldarg_0); callsite.Emit (OpCodes.Ldarg_0);
callsite.Emit (OpCodes.Ldfld, vtableField); callsite.Emit (OpCodes.Ldfld, vtableField);
// call this._vtable.GetDelegateForNative(IntPtr native, int vtableIndex) // call this._vtable.GetDelegateForNative(IntPtr native, int vtableIndex)
callsite.Emit (OpCodes.Ldloc_S, native); callsite.Emit (OpCodes.Ldloc_S, nativePtr);
callsite.Emit (OpCodes.Ldc_I4, vtableIndex); callsite.Emit (OpCodes.Ldc_I4, vtableIndex);
callsite.Emit (OpCodes.Callvirt, getDelegate); callsite.Emit (OpCodes.Callvirt, getDelegate);
// check for null // check for null

26
Mono.VisualC.Interop/Attributes.cs

@ -12,14 +12,16 @@ using System.Linq;
using System.Reflection; using System.Reflection;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
#region Interface method attributes
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class VirtualAttribute : Attribute {} public class VirtualAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class StaticAttribute : Attribute {} public class StaticAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class PrivateAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class OverrideNativeAttribute : Attribute {} public class ProtectedAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)] [AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
public class MangleAsAttribute : Attribute { public class MangleAsAttribute : Attribute {
@ -38,6 +40,10 @@ namespace Mono.VisualC.Interop {
this.MangleType = new CppType (cppTypeSpec); this.MangleType = new CppType (cppTypeSpec);
} }
} }
#endregion
[AttributeUsage (AttributeTargets.Method)]
public class OverrideNativeAttribute : Attribute {}
public static class Modifiers { public static class Modifiers {
@ -45,11 +51,18 @@ namespace Mono.VisualC.Interop {
{ {
return method.IsDefined (typeof (VirtualAttribute), false); return method.IsDefined (typeof (VirtualAttribute), false);
} }
public static bool IsStatic (MethodInfo method) public static bool IsStatic (MethodInfo method)
{ {
return method.IsDefined (typeof (StaticAttribute), false); return method.IsDefined (typeof (StaticAttribute), false);
} }
public static bool IsPrivate (MethodInfo method)
{
return method.IsDefined (typeof (PrivateAttribute), false);
}
public static bool IsProtected (MethodInfo method)
{
return method.IsDefined (typeof (ProtectedAttribute), false);
}
public static CppType GetMangleType (ParameterInfo param) public static CppType GetMangleType (ParameterInfo param)
{ {
@ -58,9 +71,10 @@ namespace Mono.VisualC.Interop {
if (maa != null) if (maa != null)
mangleType = maa.MangleType; mangleType = maa.MangleType;
// this means that only CppModifiers were applied .. apply CppType from managed parameter type // this means that either no MangleAsAttribute was defined, or
// only CppModifiers were applied .. apply CppType from managed parameter type
if (mangleType.ElementType == CppTypes.Unknown && mangleType.ElementTypeName == null) if (mangleType.ElementType == CppTypes.Unknown && mangleType.ElementTypeName == null)
mangleType.Apply (CppType.ForManagedType (param.ParameterType)); mangleType.ApplyTo (CppType.ForManagedType (param.ParameterType));
else if (mangleType.ElementType == CppTypes.Unknown) else if (mangleType.ElementType == CppTypes.Unknown)
// FIXME: otherwise, we just assume it's CppTypes.Class for now. // FIXME: otherwise, we just assume it's CppTypes.Class for now.
mangleType.ElementType = CppTypes.Class; mangleType.ElementType = CppTypes.Class;

30
Mono.VisualC.Interop/CppType.cs

@ -90,7 +90,6 @@ namespace Mono.VisualC.Interop {
// pointer types to C++ pointers // pointer types to C++ pointers
// array types to C++ arrays // array types to C++ arrays
(t) => { (t) => {
if (t.GetElementType () == null) return CppTypes.Unknown;
CppType cppType = CppType.ForManagedType (t.GetElementType ()); CppType cppType = CppType.ForManagedType (t.GetElementType ());
if (t.IsByRef) cppType.Modifiers.Add (CppModifiers.Reference); if (t.IsByRef) cppType.Modifiers.Add (CppModifiers.Reference);
if (t.IsPointer) cppType.Modifiers.Add (CppModifiers.Pointer); if (t.IsPointer) cppType.Modifiers.Add (CppModifiers.Pointer);
@ -105,7 +104,15 @@ namespace Mono.VisualC.Interop {
// this will contain the name of said type // this will contain the name of said type
public string ElementTypeName { get; set; } public string ElementTypeName { get; set; }
public List<CppModifiers> Modifiers { get; private set; } private List<CppModifiers> internalModifiers;
public List<CppModifiers> Modifiers {
get {
if (internalModifiers == null)
internalModifiers = new List<CppModifiers> ();
return internalModifiers;
}
}
// here, you can pass in things like "const char*" or "const Foo * const" // 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 // DISCLAIMER: this is really just for convenience for now, and is not meant to be able
@ -119,8 +126,6 @@ namespace Mono.VisualC.Interop {
ElementType = CppTypes.Unknown; ElementType = CppTypes.Unknown;
ElementTypeName = null; ElementTypeName = null;
Modifiers = new List<CppModifiers> ();
Parse (cppTypeSpec); Parse (cppTypeSpec);
} }
@ -180,11 +185,10 @@ namespace Mono.VisualC.Interop {
return; return;
} }
Type managedType = type as Type; Type managedType = type as Type;
if (managedType != null) { if (managedType != null) {
CppType mapped = CppType.ForManagedType (managedType); CppType mapped = CppType.ForManagedType (managedType);
Apply (mapped); ApplyTo (mapped);
return; return;
} }
} }
@ -193,15 +197,16 @@ namespace Mono.VisualC.Interop {
// and combines its modifiers into this instance. // and combines its modifiers into this instance.
// Use when THIS instance may have attributes you want, // Use when THIS instance may have attributes you want,
// but want the element type of the passed instance. // but want the element type of the passed instance.
public void Apply (CppType type) public void ApplyTo (CppType type)
{ {
ElementType = type.ElementType; ElementType = type.ElementType;
ElementTypeName = type.ElementTypeName; ElementTypeName = type.ElementTypeName;
if (Modifiers == null) Modifiers = new List<CppModifiers> ();
List<CppModifiers> oldModifiers = Modifiers; List<CppModifiers> oldModifiers = internalModifiers;
Modifiers = type.Modifiers; internalModifiers = type.Modifiers;
Modifiers.AddRange (oldModifiers);
if (oldModifiers != null)
Modifiers.AddRange (oldModifiers);
} }
/* /*
@ -233,9 +238,6 @@ namespace Mono.VisualC.Interop {
where checkType (type).ElementType != CppTypes.Unknown where checkType (type).ElementType != CppTypes.Unknown
select checkType (type)).FirstOrDefault (); select checkType (type)).FirstOrDefault ();
if (mappedType.Modifiers == null)
mappedType.Modifiers = new List<CppModifiers> ();
return mappedType; return mappedType;
} }

221
Mono.VisualC.Interop/IEnumerableTransform.cs

@ -5,20 +5,34 @@ using System.Collections.Generic;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public enum RuleResult {
NoMatch,
MatchEmit,
MatchNoEmit
}
public delegate bool EmitterFunc<TIn, TOut> (InputData<TIn> input, out TOut output); public delegate RuleResult EmitterFunc<TIn, TOut> (InputData<TIn> input, out TOut output);
public struct InputData<TIn> { public struct InputData<TIn> {
public IEnumerable<TIn> AllValues; public IEnumerable<TIn> AllValues;
public LookaheadEnumerator<TIn> Enumerator; public CloneableEnumerator<TIn> Enumerator;
public List<IRule<TIn>> MatchedRules; public List<IRule<TIn>> MatchedRules;
public InputData (IEnumerable<TIn> input, LookaheadEnumerator<TIn> enumerator) public InputData (IEnumerable<TIn> input, CloneableEnumerator<TIn> enumerator)
{ {
this.AllValues = input; this.AllValues = input;
this.Enumerator = enumerator; this.Enumerator = enumerator;
this.MatchedRules = new List<IRule<TIn>> (); this.MatchedRules = new List<IRule<TIn>> ();
} }
public InputData<TIn> NewContext ()
{
InputData<TIn> nctx = new InputData<TIn> ();
nctx.AllValues = this.AllValues;
nctx.Enumerator = this.Enumerator.Clone ();
nctx.MatchedRules = this.MatchedRules;
return nctx;
}
public TIn Value { public TIn Value {
get { return Enumerator.Current; } get { return Enumerator.Current; }
} }
@ -26,7 +40,7 @@ namespace Mono.VisualC.Interop {
#region Rules #region Rules
public interface IRule<TIn> { public interface IRule<TIn> {
bool SatisfiedBy (InputData<TIn> input); RuleResult SatisfiedBy (InputData<TIn> input);
} }
// yields all inputs indescriminately // yields all inputs indescriminately
@ -34,9 +48,9 @@ namespace Mono.VisualC.Interop {
public AnyRule () public AnyRule ()
{ {
} }
public bool SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
return true; return RuleResult.MatchEmit;
} }
} }
@ -46,9 +60,9 @@ namespace Mono.VisualC.Interop {
public UnmatchedRule () public UnmatchedRule ()
{ {
} }
public bool SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
return !input.MatchedRules.Any (); return !input.MatchedRules.Any ()? RuleResult.MatchEmit : RuleResult.NoMatch;
} }
} }
@ -58,13 +72,13 @@ namespace Mono.VisualC.Interop {
public FirstRule () public FirstRule ()
{ {
} }
public bool SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
if (!triggered) { if (!triggered) {
triggered = true; triggered = true;
return true; return RuleResult.MatchEmit;
} }
return false; return RuleResult.NoMatch;
} }
} }
@ -74,18 +88,27 @@ namespace Mono.VisualC.Interop {
public LastRule () public LastRule ()
{ {
} }
public bool SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
IEnumerator<TIn> item = input.Enumerator; throw new NotImplementedException ();
}
}
while (item.MoveNext ()) { // yields input if the specified previous rule has already been satisfied
foreach (var prevRule in input.MatchedRules) { public class AfterRule<TIn> : IRule<TIn> {
if (prevRule.SatisfiedBy (input)) protected IRule<TIn> previousRule;
return false; protected bool satisfied = false;
} public AfterRule (IRule<TIn> previousRule)
} {
this.previousRule = previousRule;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
if (satisfied)
return RuleResult.MatchEmit;
return true; satisfied = previousRule.SatisfiedBy (input) != RuleResult.NoMatch;
return RuleResult.NoMatch;
} }
} }
@ -101,9 +124,22 @@ namespace Mono.VisualC.Interop {
{ {
this.conditions = conditions; this.conditions = conditions;
} }
public bool SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
return conditions.Contains (input.Value); return conditions.Contains (input.Value)? RuleResult.MatchEmit : RuleResult.NoMatch;
}
}
public class PredicateRule<TIn> : IRule<TIn> {
protected Func<TIn, bool> predicate;
public PredicateRule (Func<TIn, bool> predicate)
{
this.predicate = predicate;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
return predicate (input.Value)? RuleResult.MatchEmit : RuleResult.NoMatch;
} }
} }
@ -124,11 +160,11 @@ namespace Mono.VisualC.Interop {
{ {
this.conditions = conditions; this.conditions = conditions;
} }
public bool SatisfiedBy (InputData<TIn> inputData) public RuleResult SatisfiedBy (InputData<TIn> inputData)
{ {
if (verified && verifiedItems.Count > 0) { if (verified && verifiedItems.Count > 0) {
verifiedItems.Dequeue (); verifiedItems.Dequeue ();
return false; return RuleResult.MatchNoEmit;
} else } else
verified = false; verified = false;
@ -142,51 +178,51 @@ namespace Mono.VisualC.Interop {
if (verifiedItems.Count == conditions.Count ()) { if (verifiedItems.Count == conditions.Count ()) {
verified = true; verified = true;
verifiedItems.Dequeue (); verifiedItems.Dequeue ();
return true; return RuleResult.MatchEmit;
} else } else
verifiedItems.Clear (); verifiedItems.Clear ();
return false; return RuleResult.NoMatch;
} }
} }
public class InOrderRule<TIn> : IRule<TIn> { public class InOrderRule<TIn> : IRule<TIn> {
protected IEnumerable<IRule<TIn>> conditions; protected IEnumerable<TIn> conditions;
protected bool verified = false; protected bool verified = false;
protected int verifiedCount = 0; protected int verifiedCount = 0;
public InOrderRule (params IRule<TIn> [] conditions) public InOrderRule (params TIn [] conditions)
{ {
this.conditions = conditions; this.conditions = conditions;
} }
public InOrderRule (IEnumerable<IRule<TIn>> conditions) public InOrderRule (IEnumerable<TIn> conditions)
{ {
this.conditions = conditions; this.conditions = conditions;
} }
public bool SatisfiedBy (InputData<TIn> inputData) public RuleResult SatisfiedBy (InputData<TIn> inputData)
{ {
if (verified && verifiedCount > 0) { if (verified && verifiedCount > 0) {
verifiedCount--; verifiedCount--;
return false; return RuleResult.MatchNoEmit;
} else } else
verified = false; verified = false;
IEnumerator<IRule<TIn>> condition = conditions.GetEnumerator (); IEnumerator<TIn> condition = conditions.GetEnumerator ();
IEnumerator<TIn> input = inputData.Enumerator; IEnumerator<TIn> input = inputData.Enumerator;
while (condition.MoveNext () && condition.Current.SatisfiedBy (inputData)) { while (condition.MoveNext () && condition.Equals (input.Current)) {
verifiedCount++; verifiedCount++;
if (!input.MoveNext ()) break; if (!input.MoveNext ()) break;
} }
if (verifiedCount == conditions.Count ()) { if (verifiedCount == conditions.Count ()) {
verified = true; verified = true;
verifiedCount--; verifiedCount--;
return true; return RuleResult.MatchEmit;
} else } else
verifiedCount = 0; verifiedCount = 0;
return false; return RuleResult.NoMatch;
} }
} }
@ -202,15 +238,19 @@ namespace Mono.VisualC.Interop {
{ {
this.rules = rules; this.rules = rules;
} }
public bool SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
RuleResult finalResult = RuleResult.NoMatch;
foreach (var rule in rules) { foreach (var rule in rules) {
if (!rule.SatisfiedBy (input)) RuleResult result = rule.SatisfiedBy (input.NewContext ());
return false; if (result == RuleResult.NoMatch)
return RuleResult.NoMatch;
if (finalResult != RuleResult.MatchNoEmit)
finalResult = result;
input.MatchedRules.Add (rule); input.MatchedRules.Add (rule);
} }
return true; return finalResult;
} }
} }
@ -226,18 +266,18 @@ namespace Mono.VisualC.Interop {
{ {
this.rules = rules; this.rules = rules;
} }
public bool SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
bool satisfied = false; bool satisfied = false;
foreach (var rule in rules) { foreach (var rule in rules) {
if (!rule.SatisfiedBy (input)) RuleResult result = rule.SatisfiedBy (input.NewContext ());
continue; if (result != RuleResult.NoMatch) {
input.MatchedRules.Add (rule);
satisfied = true; return result;
input.MatchedRules.Add (rule); }
} }
return satisfied; return RuleResult.NoMatch;
} }
} }
#endregion #endregion
@ -278,6 +318,11 @@ namespace Mono.VisualC.Interop {
}); });
} }
public static IRule<TIn> InputsWhere<TIn> (Func<TIn, bool> predicate)
{
return new PredicateRule<TIn> (predicate);
}
public static IRule<TIn> AnyInput<TIn> () public static IRule<TIn> AnyInput<TIn> ()
{ {
return new AnyRule<TIn> (); return new AnyRule<TIn> ();
@ -307,15 +352,21 @@ namespace Mono.VisualC.Interop {
public IRule<TIn> AnyInputIn (params TIn[] input) public IRule<TIn> AnyInputIn (params TIn[] input)
{ {
return additionalRuleCallback(new InSetRule<TIn> (input)); return additionalRuleCallback (new InSetRule<TIn> (input));
} }
public IRule<TIn> AnyInputIn (IEnumerable<TIn> input) public IRule<TIn> AnyInputIn (IEnumerable<TIn> input)
{ {
return additionalRuleCallback(new InSetRule<TIn> (input)); return additionalRuleCallback (new InSetRule<TIn> (input));
}
public IRule<TIn> InputsWhere (Func<TIn, bool> predicate)
{
return additionalRuleCallback (new PredicateRule<TIn> (predicate));
} }
public IRule<TIn> AnyInput () public IRule<TIn> AnyInput ()
{ {
return additionalRuleCallback(new AnyRule<TIn> ()); return additionalRuleCallback (new AnyRule<TIn> ());
} }
} }
@ -331,7 +382,7 @@ namespace Mono.VisualC.Interop {
public IRule<TIn> InThatOrder () public IRule<TIn> InThatOrder ()
{ {
return additionalRuleCallback (new InOrderRule<TIn> (sequence.Select (tin => (IRule<TIn>)new InSetRule<TIn> (tin)))); return additionalRuleCallback (new InOrderRule<TIn> (sequence));
} }
public IRule<TIn> InAnyOrder () public IRule<TIn> InAnyOrder ()
@ -347,64 +398,46 @@ namespace Mono.VisualC.Interop {
return delegate (InputData<TIn> input, out TOut output) { return delegate (InputData<TIn> input, out TOut output) {
output = default (TOut); output = default (TOut);
foreach (var rule in rules) { foreach (var rule in rules) {
if (rule (input, out output)) RuleResult result = rule (input.NewContext (), out output);
return true; if (result != RuleResult.NoMatch)
return result;
input.Enumerator.Validate ();
} }
return false; return RuleResult.NoMatch;
}; };
} }
} }
public class LookaheadEnumerator<T> : IEnumerator<T> { public class CloneableEnumerator<T> : IEnumerator<T> {
private IEnumerable<T> wrappedEnumerable; private IEnumerable<T> wrappedEnumerable;
private IEnumerator<T> wrappedEnumerator; private IEnumerator<T> wrappedEnumerator;
private int position; private int position;
private bool invalidated;
public LookaheadEnumerator (IEnumerable<T> enumerable, int position) public CloneableEnumerator (IEnumerable<T> enumerable, int position)
{ {
this.wrappedEnumerable = enumerable; this.wrappedEnumerable = enumerable;
this.position = position; this.position = position;
this.invalidated = true;
Validate ();
}
public void Reset () this.wrappedEnumerator = wrappedEnumerable.GetEnumerator ();
{
invalidated = true;
wrappedEnumerator.Reset ();
}
public void Validate ()
{
if (!invalidated) return;
wrappedEnumerator = wrappedEnumerable.GetEnumerator ();
for (int i = 0; i < position; i++) for (int i = 0; i < position; i++)
wrappedEnumerator.MoveNext (); wrappedEnumerator.MoveNext ();
}
invalidated = false; public CloneableEnumerator<T> Clone () {
return new CloneableEnumerator<T> (this.wrappedEnumerable, this.position);
} }
public bool ValidMoveNext () public void Reset ()
{ {
Validate (); wrappedEnumerator.Reset ();
position++;
return wrappedEnumerator.MoveNext ();
} }
public bool MoveNext () public bool MoveNext ()
{ {
invalidated = true; position++;
return wrappedEnumerator.MoveNext (); return wrappedEnumerator.MoveNext ();
} }
public bool Invalidated {
get { return invalidated; }
}
public T Current { public T Current {
get { return wrappedEnumerator.Current; } get { return wrappedEnumerator.Current; }
} }
@ -422,17 +455,16 @@ namespace Mono.VisualC.Interop {
public static IEnumerable<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] rules) public static IEnumerable<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] rules)
{ {
LookaheadEnumerator<TIn> enumerator = new LookaheadEnumerator<TIn> (input, 0); CloneableEnumerator<TIn> enumerator = new CloneableEnumerator<TIn> (input, 0);
while (enumerator.ValidMoveNext ()) {
while (enumerator.MoveNext ()) {
InputData<TIn> inputData = new InputData<TIn> (input, enumerator); InputData<TIn> inputData = new InputData<TIn> (input, enumerator);
foreach (var rule in rules) { foreach (var rule in rules) {
TOut output; TOut output;
if (rule (inputData, out output)) if (rule (inputData.NewContext (), out output) == RuleResult.MatchEmit)
yield return output; yield return output;
enumerator.Validate ();
} }
} }
@ -460,15 +492,14 @@ namespace Mono.VisualC.Interop {
}); });
} }
public static IRule<TIn> After<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
public static IRule<TIn> FollowedBy<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{ {
return new InOrderRule<TIn> (previousRules, parentheticalRules); return new AndRule<TIn> (new AfterRule<TIn> (parentheticalRules), previousRules);
} }
public static RuleCompound<TIn> FollowedBy<TIn> (this IRule<TIn> previousRules) public static RuleCompound<TIn> After<TIn> (this IRule<TIn> previousRules)
{ {
return new RuleCompound<TIn> ((subsequentRules) => { return new RuleCompound<TIn> ((subsequentRules) => {
return FollowedBy<TIn> (previousRules, subsequentRules); return After<TIn> (previousRules, subsequentRules);
}); });
} }
@ -477,12 +508,14 @@ namespace Mono.VisualC.Interop {
return delegate (InputData<TIn> input, out TOut output) { return delegate (InputData<TIn> input, out TOut output) {
output = default (TOut); output = default (TOut);
TIn value = input.Value; TIn value = input.Value;
if (rule.SatisfiedBy (input)) { RuleResult ruleResult = rule.SatisfiedBy (input);
if (ruleResult != RuleResult.NoMatch) {
input.MatchedRules.Add (rule); input.MatchedRules.Add (rule);
output = result (value); output = result (value);
return true; return ruleResult;
} }
return false; return RuleResult.NoMatch;
}; };
} }
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, TOut result) public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, TOut result)

7
Mono.VisualC.Interop/Util.cs

@ -13,7 +13,7 @@ namespace Mono.VisualC.Interop {
return delType.GetMethod ("Invoke"); return delType.GetMethod ("Invoke");
} }
public static Type GetDelegateTypeForMethodInfo (ModuleBuilder mod, MethodInfo targetMethod) public static Type GetDelegateTypeForMethodInfo (ModuleBuilder mod, MethodInfo targetMethod, CallingConvention? callingConvention)
{ {
// TODO: Actually return the same delegate type instead of creating a new one if // TODO: Actually return the same delegate type instead of creating a new one if
// a suitable type already exists?? // a suitable type already exists??
@ -24,6 +24,11 @@ namespace Mono.VisualC.Interop {
TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass; TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass;
TypeBuilder del = mod.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate)); TypeBuilder del = mod.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate));
if (callingConvention.HasValue) {
ConstructorInfo ufpa = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new Type [] { typeof (CallingConvention) });
CustomAttributeBuilder unmanagedPointer = new CustomAttributeBuilder (ufpa, new object [] { callingConvention.Value });
del.SetCustomAttribute (unmanagedPointer);
}
MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) }); ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) });

Loading…
Cancel
Save