mirror of https://github.com/mono/CppSharp.git
Browse Source
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-71e107334c4bpull/1/head
15 changed files with 859 additions and 125 deletions
@ -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<string,CppModifiers> Tokenize = new Dictionary<string, CppModifiers> () { |
||||||
|
{ "\\*", CppModifiers.Pointer }, |
||||||
|
{ "\\[\\s*\\]", CppModifiers.Array }, |
||||||
|
{ "\\&", CppModifiers.Reference } |
||||||
|
}; |
||||||
|
|
||||||
|
/* |
||||||
|
public static Dictionary<CppModifiers,string> Stringify = new Dictionary<CppModifiers, string> () { |
||||||
|
{ 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<Func<Type,CppType>> ManagedTypeMap = new List<Func<Type,CppType>> () { |
||||||
|
(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<CppModifiers> 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<CppModifiers> (); |
||||||
|
|
||||||
|
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<CppModifiers> (); |
||||||
|
|
||||||
|
List<CppModifiers> 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<CppModifiers> (); |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,495 @@ |
|||||||
|
using System; |
||||||
|
using System.Linq; |
||||||
|
using System.Collections; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Mono.VisualC.Interop { |
||||||
|
|
||||||
|
|
||||||
|
public delegate bool EmitterFunc<TIn, TOut> (InputData<TIn> input, out TOut output); |
||||||
|
|
||||||
|
public struct InputData<TIn> { |
||||||
|
public IEnumerable<TIn> AllValues; |
||||||
|
public LookaheadEnumerator<TIn> Enumerator; |
||||||
|
public List<IRule<TIn>> MatchedRules; |
||||||
|
public InputData (IEnumerable<TIn> input, LookaheadEnumerator<TIn> enumerator) |
||||||
|
{ |
||||||
|
this.AllValues = input; |
||||||
|
this.Enumerator = enumerator; |
||||||
|
this.MatchedRules = new List<IRule<TIn>> (); |
||||||
|
} |
||||||
|
|
||||||
|
public TIn Value { |
||||||
|
get { return Enumerator.Current; } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#region Rules
|
||||||
|
public interface IRule<TIn> { |
||||||
|
bool SatisfiedBy (InputData<TIn> input); |
||||||
|
} |
||||||
|
|
||||||
|
// yields all inputs indescriminately
|
||||||
|
public class AnyRule<TIn> : IRule<TIn> { |
||||||
|
public AnyRule () |
||||||
|
{ |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> input) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// yields all inputs that haven't satisfied
|
||||||
|
// any other rule
|
||||||
|
public class UnmatchedRule<TIn> : IRule<TIn> { |
||||||
|
public UnmatchedRule () |
||||||
|
{ |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> input) |
||||||
|
{ |
||||||
|
return !input.MatchedRules.Any (); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// yields input if it hasn't been satisfied before
|
||||||
|
public class FirstRule<TIn> : IRule<TIn> { |
||||||
|
protected bool triggered = false; |
||||||
|
public FirstRule () |
||||||
|
{ |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> 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<TIn> : IRule<TIn> { |
||||||
|
public LastRule () |
||||||
|
{ |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> input) |
||||||
|
{ |
||||||
|
IEnumerator<TIn> 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<TIn> : IRule<TIn> { |
||||||
|
protected IEnumerable<TIn> conditions; |
||||||
|
|
||||||
|
public InSetRule (params TIn [] conditions) |
||||||
|
{ |
||||||
|
this.conditions = conditions; |
||||||
|
} |
||||||
|
public InSetRule (IEnumerable<TIn> conditions) |
||||||
|
{ |
||||||
|
this.conditions = conditions; |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> 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<TIn> : IRule<TIn> { |
||||||
|
protected IEnumerable<TIn> conditions; |
||||||
|
|
||||||
|
protected Queue<TIn> verifiedItems = new Queue<TIn> (); |
||||||
|
protected bool verified = false; |
||||||
|
|
||||||
|
|
||||||
|
public AnyOrderRule (params TIn [] conditions) |
||||||
|
{ |
||||||
|
this.conditions = conditions; |
||||||
|
} |
||||||
|
public AnyOrderRule (IEnumerable<TIn> conditions) |
||||||
|
{ |
||||||
|
this.conditions = conditions; |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> inputData) |
||||||
|
{ |
||||||
|
if (verified && verifiedItems.Count > 0) { |
||||||
|
verifiedItems.Dequeue (); |
||||||
|
return false; |
||||||
|
} else |
||||||
|
verified = false; |
||||||
|
|
||||||
|
IEnumerator<TIn> 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<TIn> : IRule<TIn> { |
||||||
|
protected IEnumerable<IRule<TIn>> conditions; |
||||||
|
|
||||||
|
protected bool verified = false; |
||||||
|
protected int verifiedCount = 0; |
||||||
|
|
||||||
|
public InOrderRule (params IRule<TIn> [] conditions) |
||||||
|
{ |
||||||
|
this.conditions = conditions; |
||||||
|
} |
||||||
|
public InOrderRule (IEnumerable<IRule<TIn>> conditions) |
||||||
|
{ |
||||||
|
this.conditions = conditions; |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> inputData) |
||||||
|
{ |
||||||
|
if (verified && verifiedCount > 0) { |
||||||
|
verifiedCount--; |
||||||
|
return false; |
||||||
|
} else |
||||||
|
verified = false; |
||||||
|
|
||||||
|
IEnumerator<IRule<TIn>> condition = conditions.GetEnumerator (); |
||||||
|
IEnumerator<TIn> 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<TIn> : IRule<TIn> { |
||||||
|
protected IEnumerable<IRule<TIn>> rules; |
||||||
|
|
||||||
|
public AndRule (IEnumerable<IRule<TIn>> rules) |
||||||
|
{ |
||||||
|
this.rules = rules; |
||||||
|
} |
||||||
|
public AndRule (params IRule<TIn>[] rules) |
||||||
|
{ |
||||||
|
this.rules = rules; |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> 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<TIn> : IRule<TIn> { |
||||||
|
protected IEnumerable<IRule<TIn>> rules; |
||||||
|
|
||||||
|
public OrRule (IEnumerable<IRule<TIn>> rules) |
||||||
|
{ |
||||||
|
this.rules = rules; |
||||||
|
} |
||||||
|
public OrRule (params IRule<TIn>[] rules) |
||||||
|
{ |
||||||
|
this.rules = rules; |
||||||
|
} |
||||||
|
public bool SatisfiedBy (InputData<TIn> 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<TIn> AnyInputIn<TIn> (params TIn [] input) |
||||||
|
{ |
||||||
|
return new InSetRule<TIn> (input); |
||||||
|
} |
||||||
|
public static IRule<TIn> AnyInputIn<TIn> (IEnumerable<TIn> input) |
||||||
|
{ |
||||||
|
return new InSetRule<TIn> (input); |
||||||
|
} |
||||||
|
|
||||||
|
public static SequenceQualifier<TIn> AllInputsIn<TIn> (params TIn [] input) |
||||||
|
{ |
||||||
|
return new SequenceQualifier<TIn> (input, null); |
||||||
|
} |
||||||
|
public static SequenceQualifier<TIn> AllInputsIn<TIn> (IEnumerable<TIn> input) |
||||||
|
{ |
||||||
|
return new SequenceQualifier<TIn> (input, null); |
||||||
|
} |
||||||
|
|
||||||
|
public static RuleCompound<TIn> First<TIn> () |
||||||
|
{ |
||||||
|
return new RuleCompound<TIn> ((subsequentRules) => { |
||||||
|
return new AndRule<TIn> (subsequentRules, new FirstRule<TIn> ()); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public static RuleCompound<TIn> Last<TIn> () |
||||||
|
{ |
||||||
|
return new RuleCompound<TIn> ((subsequentRules) => { |
||||||
|
return new AndRule<TIn> (subsequentRules, new LastRule<TIn> ()); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public static IRule<TIn> AnyInput<TIn> () |
||||||
|
{ |
||||||
|
return new AnyRule<TIn> (); |
||||||
|
} |
||||||
|
public static IRule<TIn> UnmatchedInput<TIn> () |
||||||
|
{ |
||||||
|
return new UnmatchedRule<TIn> (); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class RuleCompound<TIn> { |
||||||
|
protected Func<IRule<TIn>,IRule<TIn>> additionalRuleCallback; |
||||||
|
|
||||||
|
public RuleCompound (Func<IRule<TIn>,IRule<TIn>> additionalRuleCallback) |
||||||
|
{ |
||||||
|
this.additionalRuleCallback = additionalRuleCallback; |
||||||
|
} |
||||||
|
|
||||||
|
public SequenceQualifier<TIn> AllInputsIn (params TIn [] input) |
||||||
|
{ |
||||||
|
return new SequenceQualifier<TIn> (input, additionalRuleCallback); |
||||||
|
} |
||||||
|
public SequenceQualifier<TIn> AllInputsIn (IEnumerable<TIn> input) |
||||||
|
{ |
||||||
|
return new SequenceQualifier<TIn> (input, additionalRuleCallback); |
||||||
|
} |
||||||
|
|
||||||
|
public IRule<TIn> AnyInputIn (params TIn[] input) |
||||||
|
{ |
||||||
|
return additionalRuleCallback(new InSetRule<TIn> (input)); |
||||||
|
} |
||||||
|
public IRule<TIn> AnyInputIn (IEnumerable<TIn> input) |
||||||
|
{ |
||||||
|
return additionalRuleCallback(new InSetRule<TIn> (input)); |
||||||
|
} |
||||||
|
public IRule<TIn> AnyInput () |
||||||
|
{ |
||||||
|
return additionalRuleCallback(new AnyRule<TIn> ()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class SequenceQualifier<TIn> { |
||||||
|
protected IEnumerable<TIn> sequence; |
||||||
|
protected Func<IRule<TIn>, IRule<TIn>> additionalRuleCallback; |
||||||
|
|
||||||
|
public SequenceQualifier (IEnumerable<TIn> sequence, Func<IRule<TIn>, IRule<TIn>> additionalRuleCallback) |
||||||
|
{ |
||||||
|
this.sequence = sequence; |
||||||
|
this.additionalRuleCallback = additionalRuleCallback ?? (rul => rul); |
||||||
|
} |
||||||
|
|
||||||
|
public IRule<TIn> InThatOrder () |
||||||
|
{ |
||||||
|
return additionalRuleCallback (new InOrderRule<TIn> (sequence.Select (tin => (IRule<TIn>)new InSetRule<TIn> (tin)))); |
||||||
|
} |
||||||
|
|
||||||
|
public IRule<TIn> InAnyOrder () |
||||||
|
{ |
||||||
|
return additionalRuleCallback (new AnyOrderRule<TIn> (sequence)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static class Choose { |
||||||
|
|
||||||
|
public static EmitterFunc<TIn, TOut> TopOne<TIn, TOut> (params EmitterFunc<TIn, TOut> [] rules) |
||||||
|
{ |
||||||
|
return delegate (InputData<TIn> 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<T> : IEnumerator<T> { |
||||||
|
private IEnumerable<T> wrappedEnumerable; |
||||||
|
private IEnumerator<T> wrappedEnumerator; |
||||||
|
|
||||||
|
private int position; |
||||||
|
private bool invalidated; |
||||||
|
|
||||||
|
public LookaheadEnumerator (IEnumerable<T> 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<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] rules) |
||||||
|
{ |
||||||
|
LookaheadEnumerator<TIn> enumerator = new LookaheadEnumerator<TIn> (input, 0); |
||||||
|
|
||||||
|
while (enumerator.ValidMoveNext ()) { |
||||||
|
|
||||||
|
InputData<TIn> inputData = new InputData<TIn> (input, enumerator); |
||||||
|
foreach (var rule in rules) { |
||||||
|
TOut output; |
||||||
|
if (rule (inputData, out output)) |
||||||
|
yield return output; |
||||||
|
|
||||||
|
enumerator.Validate (); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static IRule<TIn> And<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules) |
||||||
|
{ |
||||||
|
return new AndRule<TIn> (previousRules, parentheticalRules); |
||||||
|
} |
||||||
|
public static RuleCompound<TIn> And<TIn> (this IRule<TIn> previousRules) |
||||||
|
{ |
||||||
|
return new RuleCompound<TIn> ((subsequentRules) => { |
||||||
|
return And<TIn> (previousRules, subsequentRules); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public static IRule<TIn> Or<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules) |
||||||
|
{ |
||||||
|
return new OrRule<TIn> (previousRules, parentheticalRules); |
||||||
|
} |
||||||
|
public static RuleCompound<TIn> Or<TIn> (this IRule<TIn> previousRules) |
||||||
|
{ |
||||||
|
return new RuleCompound<TIn> ((subsequentRules) => { |
||||||
|
return Or<TIn> (previousRules, subsequentRules); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static IRule<TIn> FollowedBy<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules) |
||||||
|
{ |
||||||
|
return new InOrderRule<TIn> (previousRules, parentheticalRules); |
||||||
|
} |
||||||
|
public static RuleCompound<TIn> FollowedBy<TIn> (this IRule<TIn> previousRules) |
||||||
|
{ |
||||||
|
return new RuleCompound<TIn> ((subsequentRules) => { |
||||||
|
return FollowedBy<TIn> (previousRules, subsequentRules); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, Func<TIn, TOut> result) |
||||||
|
{ |
||||||
|
return delegate (InputData<TIn> 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<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, TOut result) |
||||||
|
{ |
||||||
|
return Emit (rule, (input) => result); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue