Click here to Skip to main content
15,895,829 members
Articles / Programming Languages / MSIL

RunSharp - Reflection.Emit Has Never Been Easier

Rate me:
Please Sign up or sign in to vote.
4.92/5 (48 votes)
10 Aug 2009MIT5 min read 118.4K   509   118  
RunSharp (or Run#) is a high-level wrapper around the Reflection.Emit API, allowing you to generate code at runtime quickly and easily.
/*
 * Copyright (c) 2009, Stefan Simek
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace TriAxis.RunSharp
{
	interface IStandardOperation
	{
		void Emit(CodeGen g, Operator op);
		bool IsUnsigned { get; }
	}

	[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", Justification = "Other name would be unclear")]
	public sealed class Operator
	{
		internal delegate IEnumerable<IMemberInfo> StandardCandidateProvider(Operand[] operands);

		#region Standard operations
		static IMemberInfo[] stdPlusOperators = {
			UnaryOp<int>.Instance, UnaryOp<uint>.Instance, UnaryOp<long>.Instance, UnaryOp<ulong>.Instance, 
			UnaryOp<float>.Instance, UnaryOp<double>.Instance
		};

		static IMemberInfo[] stdMinusOperators = {
			UnaryOp<int>.Instance, UnaryOp<long>.Instance, UnaryOp<float>.Instance, UnaryOp<double>.Instance
		};

		static IMemberInfo[] stdNotOperators = {
			UnaryOp<int>.Instance, UnaryOp<uint>.Instance, UnaryOp<long>.Instance, UnaryOp<ulong>.Instance,
		};

		static SpecificOperatorProvider[] stdNotTemplates = {
			UnaryEnumSpecific
		};

		static IMemberInfo[] stdUnaryBoolOperators = {
			UnaryOp<bool>.Instance
		};

		static IMemberInfo[] stdIncOperators = {
			IncOp<sbyte>.Instance, IncOp<byte>.Instance, IncOp<short>.Instance, IncOp<ushort>.Instance,
			IncOp<int>.Instance, IncOp<uint>.Instance, IncOp<long>.Instance, IncOp<ulong>.Instance,
			IncOp<char>.Instance, IncOp<float>.Instance, IncOp<double>.Instance
		};

		static SpecificOperatorProvider[] stdIncTemplates = {
			IncEnumSpecific
		};

		static IMemberInfo[] stdAddOperators = {
			SameOp<int>.Instance, SameOp<uint>.Instance, SameOp<long>.Instance, SameOp<ulong>.Instance, SameOp<float>.Instance, SameOp<double>.Instance,
			StringConcatOp<string, string>.Instance, StringConcatOp<string, object>.Instance, StringConcatOp<object, string>.Instance
		};

		static SpecificOperatorProvider[] stdAddTemplates = {
			AddEnumSpecific, AddDelegateSpecific
		};

		static IMemberInfo[] stdSubOperators = {
			SameOp<int>.Instance, SameOp<uint>.Instance, SameOp<long>.Instance, SameOp<ulong>.Instance, SameOp<float>.Instance, SameOp<double>.Instance
		};

		static SpecificOperatorProvider[] stdSubTemplates = {
			SubEnumSpecific, SubDelegateSpecific
		};

		static IMemberInfo[] stdArithOperators = {
			SameOp<int>.Instance, SameOp<uint>.Instance, SameOp<long>.Instance, SameOp<ulong>.Instance, SameOp<float>.Instance, SameOp<double>.Instance
		};

		static IMemberInfo[] stdBitOperators = {
			SameOp<bool>.Instance, SameOp<int>.Instance, SameOp<uint>.Instance, SameOp<long>.Instance, SameOp<ulong>.Instance
		};

		static SpecificOperatorProvider[] stdBitTemplates = {
			BitEnumSpecific
		};

		static IMemberInfo[] stdShiftOperators = {
			ShiftOp<int>.Instance, ShiftOp<uint>.Instance, ShiftOp<long>.Instance, ShiftOp<ulong>.Instance
		};

		static IMemberInfo[] stdEqOperators = {
			CmpOp<bool>.Instance, CmpOp<int>.Instance, CmpOp<uint>.Instance, CmpOp<long>.Instance, CmpOp<ulong>.Instance, CmpOp<float>.Instance, CmpOp<double>.Instance,
			CmpOp<object>.Instance
		};

		static SpecificOperatorProvider[] stdEqTemplates = {
			CmpEnumSpecific
		};

		static IMemberInfo[] stdCmpOperators = {
			CmpOp<int>.Instance, CmpOp<uint>.Instance, CmpOp<long>.Instance, CmpOp<ulong>.Instance, CmpOp<float>.Instance, CmpOp<double>.Instance
		};

		static SpecificOperatorProvider[] stdCmpTemplates = {
			CmpEnumSpecific
		};

		static IMemberInfo[] stdNone = { };

		sealed class UnaryOp<T> : StdOp
		{
			public static readonly UnaryOp<T> Instance = new UnaryOp<T>();
			private UnaryOp() : base(typeof(T), typeof(T)) { }
		}

		static IMemberInfo[] UnaryEnumSpecific(Operand[] args)
		{
			Type t = Operand.GetType(args[0]);

			if (t == null || !t.IsEnum)
				return stdNone;

			return new IMemberInfo[] { new StdOp(t, t) };
		}

		sealed class IncOp<T> : IncOp
		{
			public static readonly IncOp<T> Instance = new IncOp<T>();
			private IncOp() : base(typeof(T)) { }
		}

		class IncOp : StdOp
		{
			OpCode convCode;

			public IncOp(Type t) : base(t, t)
			{
				switch (Type.GetTypeCode(t))
				{
					case TypeCode.Single:
						convCode = OpCodes.Conv_R4;
						break;
					case TypeCode.Double:
						convCode = OpCodes.Conv_R8;
						break;
					case TypeCode.Int64:
					case TypeCode.UInt64:
						convCode = OpCodes.Conv_I8;
						break;
					default:
						convCode = OpCodes.Nop;
						break;
				}
			}

			public override void Emit(CodeGen g, Operator op)
			{
				g.IL.Emit(OpCodes.Ldc_I4_1);
				if (convCode != OpCodes.Nop)
					g.IL.Emit(convCode);

				base.Emit(g, op);
			}
		}

		static IMemberInfo[] IncEnumSpecific(Operand[] args)
		{
			Type t = Operand.GetType(args[0]);

			if (t == null || !t.IsEnum)
				return stdNone;

			return new IMemberInfo[] { new IncOp(t) };
		}

		sealed class SameOp<T> : StdOp
		{
			public static readonly SameOp<T> Instance = new SameOp<T>();
			private SameOp() : base(typeof(T), typeof(T), typeof(T)) { }
		}

		static IMemberInfo[] AddEnumSpecific(Operand[] args)
		{
			Type t1 = Operand.GetType(args[0]), t2 = Operand.GetType(args[1]);

			if (t1 == null || t2 == null || t1.IsEnum == t2.IsEnum)	// if none or both types are enum, no operator can be valid
				return stdNone;

			Type e = t1.IsEnum ? t1 : t2;
			Type u = Enum.GetUnderlyingType(e);

			return new IMemberInfo[] { new StdOp(e, e, u), new StdOp(e, u, e) };
		}

		static IMemberInfo[] AddDelegateSpecific(Operand[] args)
		{
			Type t1 = Operand.GetType(args[0]), t2 = Operand.GetType(args[1]);

			if (t1 != t2 || t1 == null || !t1.IsSubclassOf(typeof(Delegate)))	// if the types are not the same, no operator can be valid
				return stdNone;

			return new IMemberInfo[] { new DelegateCombineOp(t1) };
		}

		sealed class DelegateCombineOp : StdOp
		{
			public DelegateCombineOp(Type t) : base(t, t, t) { }
			static MethodInfo miCombine = typeof(Delegate).GetMethod("Combine", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(Delegate), typeof(Delegate) }, null);

			public override void Emit(CodeGen g, Operator op)
			{
				g.IL.Emit(OpCodes.Call, miCombine);
				g.IL.Emit(OpCodes.Castclass, ReturnType);
			}
		}

		static IMemberInfo[] SubEnumSpecific(Operand[] args)
		{
			Type t1 = Operand.GetType(args[0]), t2 = Operand.GetType(args[1]);

			if (t1 == null || t2 == null || !t1.IsEnum || (t2.IsEnum && t2 != t1))	// if the types are not the same, no operator can be valid
				return stdNone;

			Type e = t1;
			Type u = Enum.GetUnderlyingType(e);

			return new IMemberInfo[] { new StdOp(u, e, e), new StdOp(e, e, u) };
		}

		static IMemberInfo[] SubDelegateSpecific(Operand[] args)
		{
			Type t1 = Operand.GetType(args[0]), t2 = Operand.GetType(args[1]);

			if (t1 != t2 || t1 == null || !t1.IsSubclassOf(typeof(Delegate)))	// if the types are not the same, no operator can be valid
				return stdNone;

			return new IMemberInfo[] { new DelegateRemoveOp(t1) };
		}

		sealed class DelegateRemoveOp : StdOp
		{
			public DelegateRemoveOp(Type t) : base(t, t, t) { }
			static MethodInfo miRemove = typeof(Delegate).GetMethod("Remove", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(Delegate), typeof(Delegate) }, null);

			public override void Emit(CodeGen g, Operator op)
			{
				g.IL.Emit(OpCodes.Call, miRemove);
				g.IL.Emit(OpCodes.Castclass, ReturnType);
			}
		}

		sealed class StringConcatOp<T1, T2> : StdOp
		{
			public static readonly StringConcatOp<T1, T2> Instance = new StringConcatOp<T1, T2>();

			MethodInfo method;
			private StringConcatOp() : base(typeof(string), typeof(T1), typeof(T2))
			{
				method = typeof(string).GetMethod("Concat", BindingFlags.Public | BindingFlags.Static, null, ParameterTypes, null);
			}

			public override void Emit(CodeGen g, Operator op)
			{
				g.IL.Emit(OpCodes.Call, method);
			}
		}

		static IMemberInfo[] BitEnumSpecific(Operand[] args)
		{
			Type t1 = Operand.GetType(args[0]), t2 = Operand.GetType(args[1]);

			if (t1 != t2 || t1 == null || !t1.IsEnum)	// if both types are not the same enum, no operator can be valid
				return stdNone;

			return new IMemberInfo[] { new StdOp(t1, t1, t1) };
		}

		sealed class ShiftOp<T> : StdOp
		{
			public static readonly ShiftOp<T> Instance = new ShiftOp<T>();
			private ShiftOp() : base(typeof(T), typeof(T), typeof(int)) { }

			public override void Emit(CodeGen g, Operator op)
			{
				base.Emit(g, op);
			}
		}

		sealed class CmpOp<T> : StdOp
		{
			public static readonly CmpOp<T> Instance = new CmpOp<T>();
			private CmpOp()
				: base(typeof(bool), typeof(T), typeof(T))
			{
				// unsigned is calculated from return type by default
				unsigned = IsUnsigned(typeof(T));
			}
		}

		static IMemberInfo[] CmpEnumSpecific(Operand[] args)
		{
			Type t1 = args[0].Type, t2 = args[1].Type;

			if (t1 != t2 || t1 == null || !t1.IsEnum)	// if both types are not the same enum, no operator can be valid
				return stdNone;

			return new IMemberInfo[] { new StdOp(typeof(bool), t1, t1) };
		}

		class StdOp : IMemberInfo, IStandardOperation
		{
			Type retType;
			Type[] opTypes;
			protected bool unsigned;

			public StdOp(Type returnType, params Type[] opTypes)
			{
				this.retType = returnType; this.opTypes = opTypes;
				unsigned = IsUnsigned(returnType);
			}

			protected static bool IsUnsigned(Type t)
			{
				switch (Type.GetTypeCode(t))
				{
					case TypeCode.Byte:
					case TypeCode.UInt16:
					case TypeCode.UInt32:
					case TypeCode.UInt64:
					case TypeCode.Char:
						return true;

					default:
						return false;
				}
			}

			bool IStandardOperation.IsUnsigned { get { return unsigned; } }

			#region IMemberInfo Members

			public System.Reflection.MemberInfo Member
			{
				get { return null; }
			}

			public string Name
			{
				get { return null; }
			}

			public Type ReturnType
			{
				get { return retType; }
			}

			public Type[] ParameterTypes
			{
				get { return opTypes; }
			}

			public bool IsParameterArray
			{
				get { return false; }
			}

			public bool IsStatic
			{
				get { return true; }
			}

			public bool IsOverride
			{
				get { return false; }
			}

			#endregion

			#region IStandardOperation Members

			public virtual void Emit(CodeGen g, Operator op)
			{
				if (op.opCode != OpCodes.Nop)
					g.IL.Emit(unsigned ? op.opCodeUn : op.opCode);

				if (op.invertOpResult)
				{
					g.IL.Emit(OpCodes.Ldc_I4_0);
					g.IL.Emit(OpCodes.Ceq);
				}
			}

			#endregion
		}

		delegate IMemberInfo[] SpecificOperatorProvider(Operand[] args);
		#endregion

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Plus = new Operator(OpCodes.Nop, false, 0, "UnaryPlus", stdPlusOperators, null);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Minus = new Operator(OpCodes.Neg, false, 0, "UnaryMinus", stdMinusOperators, null);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator LogicalNot = new Operator(OpCodes.Nop, true, BranchInstruction.False, "LogicalNot", stdUnaryBoolOperators, null);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Not = new Operator(OpCodes.Not, false, 0, "OnesComplement", stdNotOperators, stdNotTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Increment = new Operator(OpCodes.Add, OpCodes.Add, OpCodes.Add_Ovf, OpCodes.Add_Ovf_Un, false, 0, "Increment", stdIncOperators, stdIncTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Decrement = new Operator(OpCodes.Sub, OpCodes.Sub, OpCodes.Sub_Ovf, OpCodes.Sub_Ovf_Un, false, 0, "Decrement", stdIncOperators, stdIncTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator True = new Operator(OpCodes.Nop, false, BranchInstruction.True, "True", stdUnaryBoolOperators, null);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator False = new Operator(OpCodes.Nop, true, BranchInstruction.False, "False", stdUnaryBoolOperators, null);

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Add = new Operator(OpCodes.Add, OpCodes.Add, OpCodes.Add_Ovf, OpCodes.Add_Ovf_Un, false, 0, "Addition", stdAddOperators, stdAddTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Subtract = new Operator(OpCodes.Sub, OpCodes.Sub, OpCodes.Sub_Ovf, OpCodes.Sub_Ovf_Un, false, 0, "Subtraction", stdSubOperators, stdSubTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Multiply = new Operator(OpCodes.Mul, OpCodes.Mul, OpCodes.Mul_Ovf, OpCodes.Mul_Ovf_Un, false, 0, "Multiply", stdArithOperators, null);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Divide = new Operator(OpCodes.Div, OpCodes.Div_Un, false, 0, "Division", stdArithOperators, null);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Modulus = new Operator(OpCodes.Rem, OpCodes.Rem_Un, false, 0, "Modulus", stdArithOperators, null);

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator And = new Operator(OpCodes.And, false, 0, "BitwiseAnd", stdBitOperators, stdBitTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Or = new Operator(OpCodes.Or, false, 0, "BitwiseOr", stdBitOperators, stdBitTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Xor = new Operator(OpCodes.Xor, false, 0, "ExclusiveOr", stdBitOperators, stdBitTemplates);

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator LeftShift = new Operator(OpCodes.Shl, false, 0, "LeftShift", stdShiftOperators, null);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator RightShift = new Operator(OpCodes.Shr, OpCodes.Shr_Un, false, 0, "RightShift", stdShiftOperators, null);

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Equality = new Operator(OpCodes.Ceq, false, BranchInstruction.Eq, "Equality", stdEqOperators, stdEqTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator Inequality = new Operator(OpCodes.Ceq, true, BranchInstruction.Ne, "Inequality", stdEqOperators, stdEqTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator LessThan = new Operator(OpCodes.Clt, OpCodes.Clt_Un, false, BranchInstruction.Lt, "LessThan", stdCmpOperators, stdCmpTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator LessThanOrEqual = new Operator(OpCodes.Cgt, OpCodes.Cgt_Un, true, BranchInstruction.Le, "LessThanOrEqual", stdCmpOperators, stdCmpTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator GreaterThan = new Operator(OpCodes.Cgt, OpCodes.Cgt_Un, false, BranchInstruction.Gt, "GreaterThan", stdCmpOperators, stdCmpTemplates);
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "The type is immutable")]
		public static readonly Operator GreaterThanOrEqual = new Operator(OpCodes.Clt, OpCodes.Clt_Un, true, BranchInstruction.Ge, "GreaterThanOrEqual", stdCmpOperators, stdCmpTemplates);

		internal readonly OpCode opCode, opCodeUn;
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Prepared for future use")]
		internal readonly OpCode opCodeChk, opCodeChkUn;
		internal readonly bool invertOpResult;
		internal readonly BranchInstruction branchOp;
		internal readonly string methodName;
		readonly IMemberInfo[] standardCandidates;
		readonly SpecificOperatorProvider[] standardTemplates;

		private Operator(OpCode opCode, bool invertOpResult, BranchInstruction branchOp, string methodName, IMemberInfo[] standardCandidates, SpecificOperatorProvider[] standardTemplates)
		{
			this.opCode = this.opCodeUn = this.opCodeChk = this.opCodeChkUn = opCode;
			this.invertOpResult = invertOpResult;
			this.branchOp = branchOp;
			this.methodName = methodName;
			this.standardCandidates = standardCandidates;
			this.standardTemplates = standardTemplates;
		}

		private Operator(OpCode opCode, OpCode opCodeUn, bool invertOpResult, BranchInstruction branchOp, string methodName, IMemberInfo[] standardCandidates, SpecificOperatorProvider[] standardTemplates)
		{
			this.opCode = this.opCodeChk = opCode;
			this.opCodeUn = this.opCodeChkUn = opCodeUn;
			this.invertOpResult = invertOpResult;
			this.branchOp = branchOp;
			this.methodName = methodName;
			this.standardCandidates = standardCandidates;
			this.standardTemplates = standardTemplates;
		}

		private Operator(OpCode opCode, OpCode opCodeUn, OpCode opCodeChk, OpCode opCodeChkUn, bool invertOpResult, BranchInstruction branchOp, string methodName, IMemberInfo[] standardCandidates, SpecificOperatorProvider[] standardTemplates)
		{
			this.opCode = opCode;
			this.opCodeUn = opCodeUn;
			this.opCodeChk = opCodeChk;
			this.opCodeChkUn = opCodeChkUn;
			this.invertOpResult = invertOpResult;
			this.branchOp = branchOp;
			this.methodName = methodName;
			this.standardCandidates = standardCandidates;
			this.standardTemplates = standardTemplates;
		}

		internal IEnumerable<IMemberInfo> GetStandardCandidates(params Operand[] args)
		{
			if (standardTemplates == null)
				return standardCandidates;
			else
				return GetStandardCandidatesT(args);
		}

		IEnumerable<IMemberInfo> GetStandardCandidatesT(Operand[] args)
		{
			foreach (IMemberInfo op in standardCandidates)
				yield return op;

			foreach (SpecificOperatorProvider tpl in standardTemplates)
			{
				foreach (IMemberInfo inst in tpl(args))
					yield return inst;
			}
		}

		internal List<ApplicableFunction> FindUserCandidates(params Operand[] args)
		{
			List<Type> usedTypes = new List<Type>();
			List<ApplicableFunction> candidates = null;
			string name = "op_" + methodName;
			bool expandedCandidates = false;

			foreach (Operand arg in args)
			{
				for (Type t = Operand.GetType(arg); t != null && t != typeof(object) && (t.IsClass || t.IsValueType) && !usedTypes.Contains(t); t = t.IsValueType ? null : t.BaseType)
				{
					usedTypes.Add(t);

					OverloadResolver.FindApplicable(ref candidates, ref expandedCandidates, TypeInfo.Filter(TypeInfo.GetMethods(t), name, true, true, false), args);
				}
			}

			if (expandedCandidates)
				OverloadResolver.RemoveExpanded(candidates);

			return candidates;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Web Developer
Slovakia Slovakia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions